"disallowQuotedKeysInObjects": "allButReserved",
"requireDotNotation": { "allExcept": [ "keywords" ] },
"jsDoc": {
+ "checkAnnotations": {
+ "preset": "jsduck5",
+ "extra": {
+ "context": true,
+ "source": true,
+ "see": true,
+ "private": true
+ }
+ },
"checkParamNames": true,
+ "checkRedundantAccess": true,
"checkRedundantReturns": true,
"checkTypes": "strictNativeCase",
"requireNewlineAfterDescription": true,
'MWExceptionHandler' => __DIR__ . '/includes/exception/MWExceptionHandler.php',
'MWHookException' => __DIR__ . '/includes/Hooks.php',
'MWHttpRequest' => __DIR__ . '/includes/HttpFunctions.php',
- 'MWMemcached' => __DIR__ . '/includes/libs/objectcache/MemcachedClient.php',
+ 'MWMemcached' => __DIR__ . '/includes/compat/MemcachedClientCompat.php',
'MWMessagePack' => __DIR__ . '/includes/libs/MWMessagePack.php',
'MWNamespace' => __DIR__ . '/includes/MWNamespace.php',
'MWOldPassword' => __DIR__ . '/includes/password/MWOldPassword.php',
'MediaWiki\\Widget\\NamespaceInputWidget' => __DIR__ . '/includes/widget/NamespaceInputWidget.php',
'MediaWiki\\Widget\\TitleInputWidget' => __DIR__ . '/includes/widget/TitleInputWidget.php',
'MediaWiki\\Widget\\UserInputWidget' => __DIR__ . '/includes/widget/UserInputWidget.php',
- 'MemCachedClientforWiki' => __DIR__ . '/includes/libs/objectcache/MemcachedClient.php',
+ 'MemCachedClientforWiki' => __DIR__ . '/includes/compat/MemcachedClientCompat.php',
'MemcLockManager' => __DIR__ . '/includes/filebackend/lockmanager/MemcLockManager.php',
'MemcachedBagOStuff' => __DIR__ . '/includes/libs/objectcache/MemcachedBagOStuff.php',
+ 'MemcachedClient' => __DIR__ . '/includes/libs/objectcache/MemcachedClient.php',
'MemcachedPeclBagOStuff' => __DIR__ . '/includes/objectcache/MemcachedPeclBagOStuff.php',
'MemcachedPhpBagOStuff' => __DIR__ . '/includes/libs/objectcache/MemcachedPhpBagOStuff.php',
'MemoizedCallable' => __DIR__ . '/includes/libs/MemoizedCallable.php',
"ext-iconv": "*",
"liuggio/statsd-php-client": "1.0.16",
"mediawiki/at-ease": "1.1.0",
- "oojs/oojs-ui": "0.13.1",
+ "oojs/oojs-ui": "0.13.2",
"oyejorge/less.php": "1.7.0.9",
"php": ">=5.3.3",
"psr/log": "1.0.0",
/**
* Check whether feed's cache should be cleared; for changes feeds
- * If the feed should be purged; $timekey and $key will be removed from
- * $messageMemc
+ * If the feed should be purged; $timekey and $key will be removed from cache
*
* @param string $timekey Cache key of the timestamp of the last item
* @param string $key Cache key of feed's content
*/
public static function checkPurge( $timekey, $key ) {
- global $wgRequest, $wgUser, $messageMemc;
+ global $wgRequest, $wgUser;
+
$purge = $wgRequest->getVal( 'action' ) === 'purge';
if ( $purge && $wgUser->isAllowed( 'purge' ) ) {
- $messageMemc->delete( $timekey );
- $messageMemc->delete( $key );
+ $cache = ObjectCache::getMainWANInstance();
+ $cache->delete( $timekey, 1 );
+ $cache->delete( $key, 1 );
}
}
require_once "$IP/includes/compat/normal/UtfNormalUtil.php";
+
+$ps_validation = Profiler::instance()->scopedProfileIn( $fname . '-validation' );
+
+// T48998: Bail out early if $wgArticlePath is non-absolute
+if ( !preg_match( '/^https?:\/\/|\//', $wgArticlePath ) ) {
+ throw new FatalError(
+ 'If you use a relative URL on $wgArticlePath, it must start ' .
+ 'with a slash (/).<br><br>See ' .
+ '<a href="https://www.mediawiki.org/wiki/Manual:$wgArticlePath">' .
+ 'https://www.mediawiki.org/wiki/Manual:$wgArticlePath</a>'
+ );
+}
+
+Profiler::instance()->scopedProfileOut( $ps_validation );
+
$ps_default2 = Profiler::instance()->scopedProfileIn( $fname . '-defaults2' );
if ( $wgCanonicalServer === false ) {
$messageMemc = wfGetMessageCacheStorage();
$parserMemc = wfGetParserCacheStorage();
-wfDebugLog( 'caches', 'main: ' . get_class( $wgMemc ) .
+wfDebugLog( 'caches',
+ 'cluster: ' . get_class( $wgMemc ) .
+ ', WAN: ' . $wgMainWANCache .
+ ', stash: ' . $wgMainStash .
', message: ' . get_class( $messageMemc ) .
', parser: ' . get_class( $parserMemc ) );
"apihelp-block-example-user-complex": "Trvale zablokovat uživatele <kbd>Vandal</kbd> s odůvodněním <kbd>Vandalism</kbd> a zabránit vytváření nových účtů a odesílání e-mailů.",
"apihelp-checktoken-param-type": "Typ testovaného tokenu.",
"apihelp-checktoken-param-token": "Token, který se má otestovat.",
+ "apihelp-checktoken-param-maxtokenage": "Nejvyšší povolené stáří tokenu v sekundách.",
+ "apihelp-checktoken-example-simple": "Testuje správnost tokenu <kbd>csrf</kbd>.",
"apihelp-compare-description": "Vrátí rozdíl dvou stránek.\n\nVe „from“ i „to“ musíte zadat číslo revize, název stránky nebo ID stránky.",
"apihelp-compare-param-fromtitle": "Název první stránky k porovnání.",
"apihelp-compare-param-fromid": "ID první stránky k porovnání.",
* Introduced by r47317
*/
class BacklinkCache {
- /** @var ProcessCacheLRU */
- protected static $cache;
+ /** @var BacklinkCache */
+ protected static $instance;
/**
* Multi dimensions array representing batches. Keys are:
* @return BacklinkCache
*/
public static function get( Title $title ) {
- if ( !self::$cache ) { // init cache
- self::$cache = new ProcessCacheLRU( 1 );
+ if ( !self::$instance || !self::$instance->title->equals( $title ) ) {
+ self::$instance = new self( $title );
}
- $dbKey = $title->getPrefixedDBkey();
- if ( !self::$cache->has( $dbKey, 'obj', 3600 ) ) {
- self::$cache->set( $dbKey, 'obj', new self( $title ) );
- }
-
- return self::$cache->get( $dbKey, 'obj' );
+ return self::$instance;
}
/**
return $updates;
}
+ /**
+ * @param string $key Message key
+ * @param string $lang Language code
+ * @return string
+ */
+ private function fetchMessage( $key, $lang ) {
+ $message = wfMessage( $key )->inLanguage( $lang );
+ if ( !$message->exists() ) {
+ wfDebugLog( 'resourceloader', __METHOD__ . " failed to find: '$key' ($lang)" );
+ }
+ return $message->plain();
+ }
+
/**
* Reencode a message blob with the updated value for a message
*
*/
private function reencodeBlob( $blob, $key, $lang ) {
$decoded = FormatJson::decode( $blob, true );
- $decoded[$key] = wfMessage( $key )->inLanguage( $lang )->plain();
-
+ $decoded[$key] = $this->fetchMessage( $key, $lang );
return FormatJson::encode( (object)$decoded );
}
$messages = array();
foreach ( $module->getMessages() as $key ) {
- $messages[$key] = wfMessage( $key )->inLanguage( $lang )->plain();
+ $messages[$key] = $this->fetchMessage( $key, $lang );
}
return FormatJson::encode( (object)$messages );
Hooks::run( 'MessageCache::get', array( &$lckey ) );
- if ( ord( $lckey ) < 128 ) {
- $uckey = ucfirst( $lckey );
- } else {
- $uckey = $wgContLang->ucfirst( $lckey );
- }
+ $uckey = $wgContLang->ucfirst( $lckey );
// Loop through each language in the fallback list until we find something useful
$lang = wfGetLangObj( $langcode );
}
$optionsHash = md5( serialize( $opts->getAllValues() ) ) . $wgRenderHashAppend;
- $timekey = wfMemcKey( $this->type, $this->format, $wgLang->getCode(), $optionsHash, 'timestamp' );
+ $timekey = wfMemcKey(
+ $this->type, $this->format, $wgLang->getCode(), $optionsHash, 'timestamp' );
$key = wfMemcKey( $this->type, $this->format, $wgLang->getCode(), $optionsHash );
FeedUtils::checkPurge( $timekey, $key );
}
/**
- * Save to feed result to $messageMemc
+ * Save to feed result to cache
*
* @param string $feed Feed's content
* @param string $timekey Memcached key of the last modification
* @param string $key Memcached key of the content
*/
public function saveToCache( $feed, $timekey, $key ) {
- global $messageMemc;
- $expire = 3600 * 24; # One day
- $messageMemc->set( $key, $feed, $expire );
- $messageMemc->set( $timekey, wfTimestamp( TS_MW ), $expire );
+ $cache = ObjectCache::getMainWANInstance();
+ $cache->set( $key, $feed, $cache::TTL_DAY );
+ $cache->set( $timekey, wfTimestamp( TS_MW ), $cache::TTL_DAY );
}
/**
- * Try to load the feed result from $messageMemc
+ * Try to load the feed result from cache
*
* @param int $lastmod Timestamp of the last item in the recentchanges table
* @param string $timekey Memcached key of the last modification
* @return string|bool Feed's content on cache hit or false on cache miss
*/
public function loadFromCache( $lastmod, $timekey, $key ) {
- global $wgFeedCacheTimeout, $wgOut, $messageMemc;
+ global $wgFeedCacheTimeout, $wgOut;
- $feedLastmod = $messageMemc->get( $timekey );
+ $cache = ObjectCache::getMainWANInstance();
+ $feedLastmod = $cache->get( $timekey );
if ( ( $wgFeedCacheTimeout > 0 ) && $feedLastmod ) {
/**
if ( $feedLastmodUnix < $lastmodUnix ) {
$wgOut->setLastModified( $feedLastmod ); // bug 21916
}
- return $messageMemc->get( $key );
+ return $cache->get( $key );
} else {
wfDebug( "RC: cached feed timestamp check failed ($feedLastmod; $lastmod)\n" );
}
/**
* Generate the feed items given a row from the database, printing the feed.
* @param object $rows DatabaseBase resource with recentchanges rows
- * @param Feed $feed
+ * @param ChannelFeed $feed
*/
public static function generateFeed( $rows, &$feed ) {
$items = self::buildItems( $rows );
--- /dev/null
+<?php
+/**
+ * Backward-compatibility alias for MemcachedClient
+ *
+ * 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
+ *
+ * @since 1.27
+ * @file
+ */
+
+/**
+ * @deprecated since 1.27
+ */
+class MWMemcached extends MemcachedClient {
+}
+
+/**
+ * @deprecated since 1.27
+ */
+class MemCachedClientforWiki extends MWMemcached {
+}
if ( !empty( $this->startupPositions[$masterName] ) ) {
$info = $lb->parentInfo();
$pos = $this->startupPositions[$masterName];
- wfDebug( __METHOD__ . ": LB " . $info['id'] . " waiting for master pos $pos\n" );
+ wfDebug( __METHOD__ . ": LB '" . $info['id'] . "' waiting for master pos $pos\n" );
$lb->waitFor( $pos );
}
}
MWExceptionHandler::logException( $ePrior );
}
$ePrior = $e;
+ // Some callbacks may use startAtomic/endAtomic, so make sure
+ // their transactions are ended so other callbacks don't fail
+ if ( $this->trxLevel() ) {
+ $this->rollback( __METHOD__ );
+ }
}
}
} while ( count( $this->mTrxIdleCallbacks ) );
$this->asOfTime = microtime( true );
}
+ function asOfTime() {
+ return $this->asOfTime;
+ }
+
+ function hasReached( DBMasterPos $pos ) {
+ if ( !( $pos instanceof self ) ) {
+ throw new InvalidArgumentException( "Position not an instance of " . __CLASS__ );
+ }
+
+ $thisPos = $this->getCoordinates();
+ $thatPos = $pos->getCoordinates();
+
+ return ( $thisPos && $thatPos && $thisPos >= $thatPos );
+ }
+
function __toString() {
// e.g db1034-bin.000976/843431247
return "{$this->file}/{$this->pos}";
return false;
}
-
- function hasReached( MySQLMasterPos $pos ) {
- $thisPos = $this->getCoordinates();
- $thatPos = $pos->getCoordinates();
-
- return ( $thisPos && $thatPos && $thisPos >= $thatPos );
- }
-
- function asOfTime() {
- return $this->asOfTime;
- }
}
interface DBMasterPos {
/**
* @return float UNIX timestamp
+ * @since 1.25
*/
public function asOfTime();
+
+ /**
+ * @param DBMasterPos $pos
+ * @return bool Whether this position is at or higher than $pos
+ * @since 1.27
+ */
+ public function hasReached( DBMasterPos $pos );
+
+ /**
+ * @return string
+ * @since 1.27
+ */
+ public function __toString();
}
private $mLoadMonitorClass;
/** @var LoadMonitor */
private $mLoadMonitor;
+ /** @var BagOStuff */
+ private $srvCache;
/** @var bool|DatabaseBase Database connection that caused a problem */
private $mErrorConnection;
}
}
}
+
+ $this->srvCache = ObjectCache::getLocalServerInstance();
}
/**
protected function doWait( $index, $open = false, $timeout = null ) {
$close = false; // close the connection afterwards
- # Find a connection to wait on, creating one if needed and allowed
+ // Check if we already know that the DB has reached this point
+ $server = $this->getServerName( $index );
+ $key = $this->srvCache->makeGlobalKey( __CLASS__, 'last-known-pos', $server );
+ /** @var DBMasterPos $knownReachedPos */
+ $knownReachedPos = $this->srvCache->get( $key );
+ if ( $knownReachedPos && $knownReachedPos->hasReached( $this->mWaitForPos ) ) {
+ wfDebugLog( 'replication', __METHOD__ . ": Slave $server known to be caught up.\n" );
+ return true;
+ }
+
+ // Find a connection to wait on, creating one if needed and allowed
$conn = $this->getAnyOpenConnection( $index );
if ( !$conn ) {
if ( !$open ) {
- wfDebug( __METHOD__ . ": no connection open\n" );
+ wfDebugLog( 'replication', __METHOD__ . ": no connection open for $server\n" );
return false;
} else {
$conn = $this->openConnection( $index, '' );
if ( !$conn ) {
- wfDebug( __METHOD__ . ": failed to open connection\n" );
+ wfDebugLog( 'replication', __METHOD__ . ": failed to open connection to $server\n" );
return false;
}
}
}
- wfDebug( __METHOD__ . ": Waiting for slave #$index to catch up...\n" );
+ wfDebugLog( 'replication', __METHOD__ . ": Waiting for slave $server to catch up...\n" );
$timeout = $timeout ?: $this->mWaitTimeout;
$result = $conn->masterPosWait( $this->mWaitForPos, $timeout );
if ( $result == -1 || is_null( $result ) ) {
- # Timed out waiting for slave, use master instead
- $server = $server = $this->getServerName( $index );
+ // Timed out waiting for slave, use master instead
$msg = __METHOD__ . ": Timed out waiting on $server pos {$this->mWaitForPos}";
- wfDebug( "$msg\n" );
+ wfDebugLog( 'replication', "$msg\n" );
wfDebugLog( 'DBPerformance', "$msg:\n" . wfBacktrace( true ) );
$ok = false;
} else {
- wfDebug( __METHOD__ . ": Done\n" );
+ wfDebugLog( 'replication', __METHOD__ . ": Done\n" );
$ok = true;
+ // Remember that the DB reached this point
+ $this->srvCache->set( $key, $this->mWaitForPos, BagOStuff::TTL_DAY );
}
if ( $close ) {
$refCount = $conn->getLBInfo( 'foreignPoolRefCount' );
if ( $serverIndex === null || $refCount === null ) {
wfDebug( __METHOD__ . ": this connection was not opened as a foreign connection\n" );
-
/**
* This can happen in code like:
* foreach ( $dbs as $db ) {
* When a connection to the local DB is opened in this way, reuseConnection()
* should be ignored
*/
-
return;
}
if ( !$this->laggedSlaveMode && $this->getServerCount() > 1 ) {
try {
// See if laggedSlaveMode gets set
- $this->getConnection( DB_SLAVE, false, $wiki );
+ $conn = $this->getConnection( DB_SLAVE, false, $wiki );
+ $this->reuseConnection( $conn );
} catch ( DBConnectionError $e ) {
// Avoid expensive re-connect attempts and failures
$this->slavesDownMode = true;
{
- "@metadata": [],
+ "@metadata": {
+ "authors": [
+ "Anggoro"
+ ]
+ },
"mainpagetext": "'''Prangkat empuk wiki wis suksès dipasang.'''",
- "mainpagedocfooter": "Mangga maca [//meta.wikimedia.org/wiki/Help:Contents User's Guide] kanggo katrangan luwih langkung prakara panggunan prangkat empuk wiki\n== Miwiti panggunan ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Daftar pangaturan préférènsi]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Milis rilis MediaWiki]"
+ "mainpagedocfooter": "Mangga maca [//meta.wikimedia.org/wiki/Help:Contents User's Guide] kanggo katrangan luwih langkung prakara panggunan prangkat empuk wiki\n== Miwiti panggunan ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Daftar pangaturan préférènsi]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Milis rilis MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]"
}
$ms = intval( 1000 * $dbwSerial->pendingWriteQueryDuration() );
$msg = $job->toString() . " COMMIT ENQUEUED [{$ms}ms of writes]";
- $this->logger->info( $msg );
+ $this->logger->warning( $msg );
$this->debugCallback( $msg );
// Wait for an exclusive lock to commit
return false;
}
try {
- $conn->hDel( $this->getReadyQueueKey(), $this->encQueueName( $type, $wiki ) );
+ // Make sure doNotifyQueueNonEmpty() takes precedence to avoid races
+ $conn->watch( $this->getReadyQueueKey() );
+ $conn->multi()
+ ->hDel( $this->getReadyQueueKey(), $this->encQueueName( $type, $wiki ) )
+ ->exec();
return true;
} catch ( RedisException $e ) {
$title, null, !empty( $this->params['useRecursiveLinksUpdate'] ), $parserOutput );
foreach ( $updates as $key => $update ) {
if ( $update instanceof LinksUpdate ) {
- if ( isset( $this->params['triggeredRecursive'] ) ) {
+ if ( !empty( $this->params['triggeredRecursive'] ) ) {
$update->setTriggeredRecursive();
}
- if ( isset( $this->params['triggeringUser'] ) && $this->params['triggeringUser'] ) {
+ if ( !empty( $this->params['triggeringUser'] ) ) {
$userInfo = $this->params['triggeringUser'];
if ( $userInfo['userId'] ) {
$user = User::newFromId( $userInfo['userId'] );
}
$update->setTriggeringUser( $user );
}
- if ( isset( $this->params['triggeringRevisionId'] ) && $this->params['triggeringRevisionId'] ) {
+ if ( !empty( $this->params['triggeringRevisionId'] ) ) {
$revision = Revision::newFromId( $this->params['triggeringRevisionId'] );
if ( $revision === null ) {
$revision = Revision::newFromId(
* @ingroup Cache
*/
class MemcachedBagOStuff extends BagOStuff {
- /** @var MWMemcached|Memcached */
+ /** @var MemcachedClient|Memcached */
protected $client;
/**
/**
* Get the underlying client object. This is provided for debugging
* purposes.
- * @return BagOStuff
+ * @return MemcachedClient|Memcached
*/
public function getClient() {
return $this->client;
*/
/**
- * This is the PHP client for memcached - a distributed memory cache daemon.
+ * This is a PHP client for memcached - a distributed memory cache daemon.
+ *
* More information is available at http://www.danga.com/memcached/
*
* Usage example:
*
- * require_once 'memcached.php';
- *
- * $mc = new MWMemcached(array(
- * 'servers' => array('127.0.0.1:10000',
- * array('192.0.0.1:10010', 2),
- * '127.0.0.1:10020'),
- * 'debug' => false,
- * 'compress_threshold' => 10240,
- * 'persistent' => true));
+ * $mc = new MemcachedClient(array(
+ * 'servers' => array(
+ * '127.0.0.1:10000',
+ * array( '192.0.0.1:10010', 2 ),
+ * '127.0.0.1:10020'
+ * ),
+ * 'debug' => false,
+ * 'compress_threshold' => 10240,
+ * 'persistent' => true
+ * ));
*
- * $mc->add( 'key', array( 'some', 'array' ) );
- * $mc->replace( 'key', 'some random string' );
- * $val = $mc->get( 'key' );
+ * $mc->add( 'key', array( 'some', 'array' ) );
+ * $mc->replace( 'key', 'some random string' );
+ * $val = $mc->get( 'key' );
*
- * @author Ryan T. Dean <rtdean@cytherianage.net>
+ * @author Ryan T. Dean <rtdean@cytherianage.net>
* @version 0.1.2
*/
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
-// {{{ requirements
-// }}}
-
-// {{{ class MWMemcached
+// {{{ class MemcachedClient
/**
* memcached client class implemented using (p)fsockopen()
*
* @author Ryan T. Dean <rtdean@cytherianage.net>
* @ingroup Cache
*/
-class MWMemcached {
+class MemcachedClient {
// {{{ properties
// {{{ public
// {{{ set_compress_threshold()
/**
- * Sets the compression threshold
+ * Set the compression threshold
*
* @param int $thresh Threshold to compress if larger than
*/
// {{{ set_debug()
/**
- * Sets the debug flag
+ * Set the debug flag
*
+ * @see __construct()
* @param bool $dbg True for debugging, false otherwise
- *
- * @see MWMemcached::__construct
*/
public function set_debug( $dbg ) {
$this->_debug = $dbg;
// {{{ set_servers()
/**
- * Sets the server list to distribute key gets and puts between
+ * Set the server list to distribute key gets and puts between
*
+ * @see __construct()
* @param array $list Array of servers to connect to
- *
- * @see MWMemcached::__construct()
*/
public function set_servers( $list ) {
$this->_servers = $list;
}
// }}}
-
-class MemCachedClientforWiki extends MWMemcached {
-}
parent::__construct( $params );
$params = $this->applyDefaultParams( $params );
- $this->client = new MWMemcached( $params );
+ $this->client = new MemcachedClient( $params );
$this->client->set_servers( $params['servers'] );
$this->client->set_debug( $params['debug'] );
}
*
* @return string
*/
- static function arrayToHeaderString( $headers, $endl = "\n" ) {
+ static function arrayToHeaderString( $headers, $endl = PHP_EOL ) {
$strings = array();
foreach ( $headers as $name => $value ) {
// Prevent header injection by stripping newlines from value
// Line endings need to be different on Unix and Windows due to
// the bug described at http://trac.wordpress.org/ticket/2603
- if ( wfIsWindows() ) {
- $endl = "\r\n";
- } else {
- $endl = "\n";
- }
+ $endl = PHP_EOL;
if ( is_array( $body ) ) {
// we are sending a multipart message
* values, but serialization is much slower unless the php.ini option
* igbinary.compact_strings is off.
* @param array $params
- * @throws MWException
+ * @throws InvalidArgumentException
*/
function __construct( $params ) {
parent::__construct( $params );
// is as good as any. There's no way to configure libmemcached to use
// hashes identical to the ones currently in use by the PHP client, and
// even implementing one of the libmemcached hashes in pure PHP for
- // forwards compatibility would require MWMemcached::get_sock() to be
+ // forwards compatibility would require MemcachedClient::get_sock() to be
// rewritten.
$this->client->setOption( Memcached::OPT_LIBKETAMA_COMPATIBLE, true );
* @ingroup Cache
*/
class SqlBagOStuff extends BagOStuff {
- /** @var LoadBalancer */
- protected $lb;
/** @var array */
protected $serverInfos;
/** @var array */
$db = DatabaseBase::factory( $type, $info );
$db->clearFlag( DBO_TRX );
} else {
- /*
- * We must keep a separate connection to MySQL in order to avoid deadlocks
- * However, SQLite has an opposite behavior. And PostgreSQL needs to know
- * if we are in transaction or no
- */
+ // We must keep a separate connection to MySQL in order to avoid deadlocks
+ // However, SQLite has an opposite behavior. And PostgreSQL needs to know
+ // if we are in transaction or not (@TODO: find some work-around).
$index = $this->slaveOnly ? DB_SLAVE : DB_MASTER;
if ( wfGetDB( $index )->getType() == 'mysql' ) {
- $this->lb = wfGetLBFactory()->newMainLB();
- $db = $this->lb->getConnection( $index );
+ $lb = wfGetLBFactory()->newMainLB();
+ $db = $lb->getConnection( $index );
$db->clearFlag( DBO_TRX ); // auto-commit mode
} else {
$db = wfGetDB( $index );
return array( 'class' => $field );
} else {
return array(
- 'lang' => wfBCP47( $this->langcode ),
+ 'lang' => $this->lang->getHtmlCode(),
'dir' => $this->lang->getDir(),
'class' => $field
);
);
if ( $res->numRows() > 0 ) {
- $out = Html::openElement( 'div', array( 'class' => 'mw-allpages-body' ) );
- $out .= Html::openElement( 'ul', array( 'class' => 'mw-allpages-chunk' ) );
+ $out = Html::openElement( 'ul', array( 'class' => 'mw-allpages-chunk' ) );
while ( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
$t = Title::newFromRow( $s );
$n++;
}
$out .= Html::closeElement( 'ul' );
- $out .= Html::closeElement( 'div' );
+
+ if ( $res->numRows() > 2 ) {
+ // Only apply CSS column styles if there's more than 2 entries.
+ // Otherwise, rendering is broken as "mw-allpages-body"'s CSS column count is 3.
+ $out = Html::rawElement( 'div', array( 'class' => 'mw-allpages-body' ), $out );
+ }
} else {
$out = '';
}
$n = 0;
if ( $res->numRows() > 0 ) {
- $out = Html::openElement( 'div', array( 'class' => 'mw-prefixindex-body' ) );
- $out .= Html::openElement( 'ul', array( 'class' => 'mw-prefixindex-list' ) );
+ $out = Html::openElement( 'ul', array( 'class' => 'mw-prefixindex-list' ) );
$prefixLength = strlen( $prefix );
while ( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
$link = '[[' . htmlspecialchars( $s->page_title ) . ']]';
}
- $out .= "<li> $link </li>\n";
+ $out .= "<li>$link</li>\n";
$n++;
}
$out .= Html::closeElement( 'ul' );
- $out .= Html::closeElement( 'div' );
+
+ if ( $res->numRows() > 2 ) {
+ // Only apply CSS column styles if there's more than 2 entries.
+ // Otherwise rendering is broken as "mw-prefixindex-body"'s CSS column count is 3.
+ $out = Html::rawElement( 'div', array( 'class' => 'mw-prefixindex-body' ), $out );
+ }
} else {
$out = '';
}
function ucfirst( $string ) {
if ( $string[0] == 'i' ) {
return 'İ' . substr( $string, 1 );
- } else {
- return parent::ucfirst( $string );
}
+ return parent::ucfirst( $string );
}
}
function ucfirst( $string ) {
if ( substr( $string, 0, 1 ) === 'i' ) {
return 'İ' . substr( $string, 1 );
- } else {
- return parent::ucfirst( $string );
}
+ return parent::ucfirst( $string );
}
/**
function lcfirst( $string ) {
if ( substr( $string, 0, 1 ) === 'I' ) {
return 'ı' . substr( $string, 1 );
- } else {
- return parent::lcfirst( $string );
}
+ return parent::lcfirst( $string );
}
/**
* @return string
*/
function ucfirst( $string ) {
- $variant = $this->getPreferredVariant();
- if ( ( $variant == 'kk-latn' || $variant == 'kk-tr' ) && $string[0] == 'i' ) {
- $string = 'İ' . substr( $string, 1 );
- } else {
- $string = parent::ucfirst( $string );
+ if ( $string[0] == 'i' ) {
+ $variant = $this->getPreferredVariant();
+ if ( $variant == 'kk-latn' || $variant == 'kk-tr' ) {
+ return 'İ' . substr( $string, 1 );
+ }
}
- return $string;
+ return parent::ucfirst( $string );
}
/**
* @return string
*/
function lcfirst( $string ) {
- $variant = $this->getPreferredVariant();
- if ( ( $variant == 'kk-latn' || $variant == 'kk-tr' ) && $string[0] == 'I' ) {
- $string = 'ı' . substr( $string, 1 );
- } else {
- $string = parent::lcfirst( $string );
+ if ( $string[0] == 'I' ) {
+ $variant = $this->getPreferredVariant();
+ if ( $variant == 'kk-latn' || $variant == 'kk-tr' ) {
+ return 'ı' . substr( $string, 1 );
+ }
}
- return $string;
+ return parent::lcfirst( $string );
}
/**
function ucfirst( $string ) {
if ( strlen( $string ) && $string[0] == 'i' ) {
return 'İ' . substr( $string, 1 );
- } else {
- return parent::ucfirst( $string );
}
+ return parent::ucfirst( $string );
}
/**
function lcfirst( $string ) {
if ( strlen( $string ) && $string[0] == 'I' ) {
return 'ı' . substr( $string, 1 );
- } else {
- return parent::lcfirst( $string );
}
+ return parent::lcfirst( $string );
}
}
"cannotdelete-title": "НэкIубгъоу \"$1\" тегъэкIыгъэн лъэкIырэп",
"badtitle": "ЦӀэ дэгъуэп",
"badtitletext": "УзкIэупчIэрэ нэкIубгъом ыцIэр къуанчэ, е нэкIы, е бзэзэпыщэ е интервики гъэнэфагъэп.\nМыхъущт символ агъэфедагъэнкIи мэхъу.",
- "title-invalid-characters": "УзыкIэупчIэрэ нэкIубгъуацIэм символ фыкъуагъэ хэт: \"$1\".",
+ "title-invalid-characters": "УзкIэупчIэрэ нэкIубгъуацIэм символ фыкъуагъэ хэт: \"$1\".",
"viewsource": "Еплъ лъапсэм",
"viewsource-title": "Еплъ лъапсэм $1 пае",
"protectedpagetext": "ЕIэзэнхэм ыкIи нэмыкI шIэнмэ яягъэ къэмыкIынэу мы нэкIубгъор ухъумагъэу щыт.",
"noemailcreate": "باید یک موتبرین ایمیل ادرسئ داخل بکنیت",
"passwordsent": "نوکین چیهرگال بئ سبت بوته ئین ایمیل ادرس ئا په «$1» ئا دیم داته بوت.\nمهربانی بکنیت شه آیی گیپتین ئا پد لوگین به ییت.",
"blocked-mailpassword": "شمئ آی پي ادرس شه دستکاری کورتینا بلاک بوته، په ای خاطرا شه پاسوردا پایده گ زورته ئه نه کنیت شه سوءاستفاده ئی دیمگیري ئی خاطرا.",
+ "eauthentsent": "یک تائیدین ایمیل په مورد نظرین ایمیل آدرسا دیم داته بوت.\nدیم شه ایشی که دیگه ایمیلئ په ای ایمیل ادرسا دیم داتینئ وڑ بیت، شما باید بعضی دستورانه که په ای مسئله ئی خاتیرا انت، اجرا کنێت.",
"mailerror": "خطا بی ایمیلی داتینی تا: $1",
"emailauthenticated": "شمی ایمیلی ادرس بی $2 سائت $3 تا تصدیق ئه بیئت.",
"emailnotauthenticated": "شمی ایمیلئ ادرس تا انون قبول نه بوته.\nایمیل په هیچ یک شه ویژه گی ئان دیم داته ئه نه بیئت.",
"accountcreatedtext": "کار زوروکئ حساب په [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|هبر و گپ]]) جوڑ بوته.",
"createaccount-title": "کار زوروکئ حساب جوڑ کورتین بی {{SITENAME}}",
"createaccount-text": "یک نفری په شمی ایمیلا یک کار زوروکین حسابئ بی {{SITENAME}} تا گو «$2» ناما جوڑ کورته ($4)، که آیی پاسورد ایش اینت : $3\nشما باید همی انون وتئ حسابئ تا داخل بئیت و وتئ پاسوردا تغیر بدهیت .\n\nاگه ای حساب اشتباهی جوڑ بوته ، ای پیام ئا نادیستگ بگیریت.",
+ "login-throttled": "شما بیخی باز وار په لوگین بوتینا کوشش کورته ایت.\nمهرباني بکنێت دیم شه آیی که پدا کوشش بکنیت $1 صبر کنیت.",
"login-abort-generic": "شمی لوگین ناکام ات - ساکت بوت",
"login-migrated-generic": "شمی کار زوروکین نام انتقال بوته، و شمی کار زوروکین نام دیگه بی ای ویکی ئی تا وجود نداریت.",
"loginlanguagelabel": "زبان: $1",
"enhancedrc-history": "истори",
"recentchanges": "Улшăнусем",
"recentchanges-legend": "Çĕнĕ улшăнусен ĕнерлевĕ",
+ "recentchanges-label-newpage": "Çĕнĕ страница тунă пулнă",
+ "recentchanges-label-minor": "Нумайах мар улăштарни",
"recentchanges-label-bot": "Ку улшăнăва бот тунă",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (пăхăр [[Special:NewPages|çĕнĕ страницăсен списокĕ]])",
"recentchanges-legend-plusminus": "(<em>±123</em>)",
"nextn-title": "Hurrengo $1 {{PLURAL:$1|emaitza|emaitzak}}",
"shown-title": "Erakutsi {{PLURAL:$1|emaitza $1|$1 emaitza}} orrialdeko",
"viewprevnext": "Ikusi ($1 {{int:pipe-separator}} $2) ($3).",
- "searchmenu-exists": "'''«[[:$1]]» izena duen orri bat bada wiki honetan.''' {{PLURAL:$2|0=|Ikus, gainera, aurkitutako beste bilaketa emaitzak.}}",
- "searchmenu-new": "<strong>Sortu «[[:$1]]» orria wiki honetan!<strong> {{PLURAL:$2|0=|Ikus, gainera, zure bilaketarekin aurkitutako orria.|Ikus, gainera, bilaketaren emaitzak.}}",
+ "searchmenu-exists": "<strong>«[[:$1]]» izena duen orri bat bada wiki honetan.</strong> {{PLURAL:$2|0=|Ikus, gainera, aurkitutako beste bilaketa emaitzak.}}",
+ "searchmenu-new": "<strong>Sortu «[[:$1]]» orria wiki honetan!</strong> {{PLURAL:$2|0=|Ikus, gainera, zure bilaketarekin aurkitutako orria.|Ikus, gainera, bilaketaren emaitzak.}}",
"searchprofile-articles": "Eduki-orriak",
"searchprofile-images": "Multimedia",
"searchprofile-everything": "Guztia",
"articleexists": "Izen hori duen artikulu bat badago edo hautatutako izena ez da baliozkoa. Mesedez, beste izen bat aukeratu.",
"cantmove-titleprotected": "Ezin duzu orrialde bat leku honetara mugitu izenburu berri hori sor ez dadin babesa duelako",
"movetalk": "Eztabaida orrialdea ere mugitu, ahal bada.",
- "move-subpages": "Azpiorrialde guztiak ($1-tik gora) mugitu",
- "move-talk-subpages": "Azpiorrialdeen eztabaida orrialde guztiak ($1-tik gora) mugitu",
+ "move-subpages": "Mugitu azpiorri guztiak ($1 gehienez)",
+ "move-talk-subpages": "Mugitu azpiorrien eztabaida orri guztiak (gehienez $1)",
"movepage-page-exists": "$1 orrialdea jada badago eta ezin da automatikoki gainetik idatzi.",
"movepage-page-moved": "«$1» orria «$2» izenera aldatu da.",
"movepage-page-unmoved": "$1 orrialdea ezin da $2(e)ra mugitu.",
"logentry-move-move-noredirect": "$1 {{GENDER:$2|wikilariak}} «$3» orria «$4» izenera aldatu du, birzuzenketarik utzi gabe",
"logentry-move-move_redir": "$1 {{GENDER:$2|wikilariak}} «$3» orria «$4» izenera aldatu du, birzuzenketaren gainetik",
"logentry-move-move_redir-noredirect": "$1 {{GENDER:wikilariak}} «$3» orria «$4» izenera aldatu du, birbideratze bat gainidatzita, birbideratzerik utzi gabe",
- "logentry-patrol-patrol": "$1(e)k $3 orrialdearen $4 berrikuzpena patruilatutzat {{GENDER:$2|markatu}} du",
+ "logentry-patrol-patrol": "$1(e)k $3 orrialdearen $4 berrikuspena patruilatutzat {{GENDER:$2|markatu}} du",
"logentry-newusers-newusers": "$1 erabiltzaile kontua sortu da",
"logentry-newusers-create": "$1 erabiltzaile kontua {{GENDER:$2|sortu da}}",
"logentry-newusers-create2": "$1 wikilariak $3 erabiltzaile kontua sortu du",
"missingarticle-rev": "(شمارهٔ نسخه: $1)",
"missingarticle-diff": "(تفاوت: $1، $2)",
"readonly_lag": "پایگاه داده به طور خودکار قفل شدهاست تا نسخههای پشتیبان با نسخهٔ اصلی هماهنگ شوند",
+ "nonwrite-api-promise-error": "سرآیند اچتیتیپی 'Promise-Non-Write-API-Action' ارسال شد ولی درخواست به یک رابط برنامهنویسی پودمان نوشتن بود.",
"internalerror": "خطای داخلی",
"internalerror_info": "خطای داخلی: $1",
"internalerror-fatal-exception": "نوع استثنای مخرب \"$1\"",
"showingresultsinrange": "نمایش در پائین تا {{PLURAL:$1|<strong>1</strong> نتیجه|<strong>$1</strong> نتیجه}} در محدودهٔ #<strong>$2</strong> تا #<strong>$3</strong>.",
"search-showingresults": "{{PLURAL:$4|نتایج <strong>$1</strong> از <strong>$3</strong>|نتایج <strong>$1 - $2</strong> از <strong>$3</strong>}}",
"search-nonefound": "نتیجهای منطبق با درخواست پیدا نشد.",
+ "search-nonefound-thiswiki": "نتیجهای منطبق با این درخواست در این وبگاه موجود نبود.",
"powersearch-legend": "جستجوی پیشرفته",
"powersearch-ns": "جستجو در فضاهای نام:",
"powersearch-togglelabel": "بررسی:",
"missingarticle-rev": "(numero della versione: $1)",
"missingarticle-diff": "(Diff: $1, $2)",
"readonly_lag": "Il database è stato bloccato automaticamente per consentire ai server con i database slave di sincronizzarsi con il master",
+ "nonwrite-api-promise-error": "È stata inviata l'intestazione HTTP 'Promise-Non-Write-API-Action', ma la richiesta era di un modulo API in scrittura.",
"internalerror": "Errore interno",
"internalerror_info": "Errore interno: $1",
"internalerror-fatal-exception": "Errore irreversibile di tipo \"$1\"",
"missingarticle-rev": "(версия № $1)",
"missingarticle-diff": "(разность: $1, $2)",
"readonly_lag": "База данных автоматически заблокирована от изменений на время, пока вторичные сервера базы данных не синхронизируются с первичным.",
+ "nonwrite-api-promise-error": "Был отправлен HTTP-заголовок 'Promise-Non-Write-API-Action', но запрос был к API-модулю записи.",
"internalerror": "Внутренняя ошибка",
"internalerror_info": "Внутренняя ошибка: $1",
"internalerror-fatal-exception": "Неустранимое исключение типа «$1»",
"listredirects": "Список перенаправлений",
"listduplicatedfiles": "Список файлов с дубликатами",
"listduplicatedfiles-summary": "Это список файлов, где самая последняя версия файла считается дубликатом последней версии некоторых других файлов. Учитываются только локальные файлы.",
- "listduplicatedfiles-entry": "У файла [[:File:$1|$1]] — [[$3|{{PLURAL:$2|один дубликат|$2 дубликата|$2 дубликатов}}]].",
+ "listduplicatedfiles-entry": "У файла [[:File:$1|$1]] — [[$3|{{PLURAL:$2|$2 дубликат|$2 дубликата|$2 дубликатов}}]].",
"unusedtemplates": "Неиспользуемые шаблоны",
"unusedtemplatestext": "Здесь перечислены все страницы пространства имён «{{ns:template}}», не включённые ни в какие другие страницы.\nНе забывайте проверять отсутствие ссылок на шаблон перед его удалением.",
"unusedtemplateswlh": "другие ссылки",
"tags-edit-manage-link": "Управление тегами",
"tags-edit-revision-selected": "{{PLURAL:$1|Выбранная версия|Выбранные версии}} [[:$2]]:",
"tags-edit-logentry-selected": "{{PLURAL:$1|1=Выбранная запись|Выбранные записи}} журнала:",
- "tags-edit-revision-legend": "Добавить или удалить теги из {{PLURAL:$1|this revision|all $1 revisions}}",
+ "tags-edit-revision-legend": "Добавить или удалить теги из {{PLURAL:$1|1=этой версии|всех $1 версий}}",
"tags-edit-logentry-legend": "Добавить или удалить теги из {{PLURAL:$1|this log entry|all $1 log entries}}",
"tags-edit-existing-tags": "Существующие метки:",
"tags-edit-existing-tags-none": "''Нет''",
"watchlist-details": "Ырытыы сирэйдэрин аахпатахха {{PLURAL:$1|$1 сирэйи кэтиигин|$1 сирэй эн кэтэбилгэр сылдьар}}.",
"wlheader-enotif": "Эл. почтанан биллэрии холбоммут.",
"wlheader-showupdated": "Бүтэһик киирииҥ кэннэ уларыйбыт сирэйдэр '''модьу''' бичигинэн бэлиэтэннилэр.",
- "wlnote": "Манна кэлиҥҥи {{PLURAL:$2|чаас|'''$2''' чаас}} иһигэр оҥоһуллубут бүтэһик $1 уларытыы көрдөрүлүннэ, бу кэмҥэ туругунан $3 $4.",
+ "wlnote": "Манна кэлиҥҥи {{PLURAL:$2|чаас|<strong>$2</strong> чаас}} иһигэр оҥоһуллубут бүтэһик <strong>$1</strong> уларытыы көрдөрүлүннэ, бу кэминээҕи туругунан $3, $4.",
"wlshowlast": "Бүтэһик $2 күҥҥэ $1 чааска көрдөр",
"watchlist-options": "Кэтээн көрүү туруоруутун уларытыы",
"watching": "Кэтээ...",
"changecontentmodel-nodirectediting": "$1 иһинээҕитин киэбин быһа уларытар сатаммат эбит",
"log-name-contentmodel": "Иһинээҕитин киэбин уларытыы сурунаала",
"log-description-contentmodel": "Сирэй иһинээҕитин киэбин кытта ситимнээх",
- "logentry-contentmodel-change": "$1 кыттааччы $3 сирэй иһинээҕитин мадьыалын мантан «$4» манна «$5» уларыппыт",
+ "logentry-contentmodel-change": "$1 кыттааччы $3 сирэй иһинээҕитин мадьыалын мантан «$4» манна «$5» {{GENDER:$2|уларыппыт}}",
"logentry-contentmodel-change-revertlink": "төннөрүү",
"logentry-contentmodel-change-revert": "төннөрүү",
"protectlogpage": "Харысхал сурунаала (көннөрүүттэн көмүскэммит билэлэр испииһэктэрэ)",
"logentry-managetags-activate": "$1 \"$4\" тиэги кыттааччылар уонна буоттар тутталларыгар {{GENDER:$2|арыйбыт}}",
"logentry-managetags-deactivate": "$1 \"$4\" тиэги кыттааччылар уонна буоттар туһамматтарын курдук {{GENDER:$2|гыммыт}}",
"log-name-tag": "Тиэк сурунаала",
+ "log-description-tag": "Бу сирэй кыттааччылар [[Special:Tags|тиэктэри]] хаһан эппиттэрин биитэр соппуттарын көрдөрөр. Тиэги атын уларытыы, сотуу <strong>иһинэн</strong> оҥордоххо манна көстүбэт.",
"rightsnone": "(суох)",
"revdelete-summary": "уларытыылар туһунан",
"feedback-adding": "Сирэй туһунан санаа этии...",
"deletepage": "Izbrišite stranicu",
"confirm": "Potvrdi / Потврди",
"excontent": "sadržaj je bio: '$1'",
- "excontentauthor": "sadržaj je bio: „$1“, a jedini urednik [[Special:Contributions/$2|$2]] ([[User talk:$2|razgovor]])",
+ "excontentauthor": "sadržaj je bio: \"$1\", a jedini urednik \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|razgovor]])",
"exbeforeblank": "sadržaj prije brisanja je bio: '$1'",
"delete-confirm": "Brisanje \"$1\"",
"delete-legend": "Obriši",
"tog-hideminor": "حالیہ تبدیلیوں میں معمولی ترامیم چھپائیں",
"tog-hidepatrolled": "حالیہ تبدیلیوں میں گشتی ترامیم چھپائیں",
"tog-newpageshidepatrolled": "جدید صفحات کی فہرست میں مراجعت شدہ صفحات چھپائیں",
- "tog-extendwatchlist": "زÛ\8cر Ù\86ظر Ù\81Û\81رست Ú©Û\8c تÙ\88سÛ\8cع Ú©Û\8cجئÛ\92 تاکÛ\81 تÙ\85اÙ\85 تبدÛ\8cÙ\84Û\8cاںØ\8c Ù\86Û\81 Ú©Û\81 صرÙ\81 سب سÛ\92 ØاÙ\84Û\8cÛ\81 تداÙ\88Û\8cÙ\86 دÛ\8cÚ©Ú¾Û\8c کجا سکیں",
- "tog-usenewrc": "حالیہ تبدیلیوں میں اور زیر نظر فہرست میں تبدیلیوں کو بلحاظ صفحہ گروہ بند کیجئے",
- "tog-numberheadings": "سرخیوں کو خودکار نمبر دیجئے",
- "tog-showtoolbar": "تدÙ\88Û\8cÙ\86Û\8c اÙ\88زارداÙ\86 دکھائÛ\8cÛ\92",
- "tog-editondblclick": "Ø·Ù\82Û\8cÙ\86 پر صÙ\81Øات Ú©Û\8c ترÙ\85Û\8cÙ\85 Ú©Û\8cجئÛ\92",
- "tog-editsectiononrightclick": "سطری عنوانات پر دایاں طق (رائیٹ کلک) کے ذریعے سطری ترمیم کاری فعال بناؤ",
- "tog-watchcreations": "میرے تخلیق کردہ صفحات اور میری زبر اثقال کردہ ملفات کو میری زیر نظر فہرست میں شامل کیا کیجئے",
- "tog-watchdefault": "Ù\85Û\8cرÛ\92 تدÙ\88Û\8cÙ\86 شدÛ\81 صÙ\81Øات اÙ\88ر Ù\85Ù\84Ù\81ات Ú©Ù\88 Ù\85Û\8cرÛ\8c زÛ\8cر Ù\86ظر Ù\81Û\81رست Ù\85Û\8cÚº شاÙ\85Ù\84 Ú©Û\8cا Ú©Û\8cجئÛ\92",
- "tog-watchmoves": "Ù\85Û\8cرÛ\92 Ù\85Ù\86تÙ\82Ù\84 کردÛ\81 صÙ\81Øات اÙ\88ر Ù\85Ù\84Ù\81ات Ú©Ù\88 Ù\85Û\8cرÛ\8c زÛ\8cر Ù\86ظر Ù\81Û\81رست Ù\85Û\8cÚº شاÙ\85Ù\84 Ú©Û\8cا Ú©Û\8cجئÛ\92",
- "tog-watchdeletion": "Ù\85Û\8cرÛ\92 ØØ°Ù\81 کردÛ\81 صÙ\81Øات اÙ\88ر Ù\85Ù\84Ù\81ات Ú©Ù\88 Ù\85Û\8cرÛ\8c زÛ\8cر Ù\86ظر Ù\81Û\81رست Ù\85Û\8cÚº شاÙ\85Ù\84 Ú©Û\8cا Ú©Û\8cجئÛ\92",
- "tog-watchrollback": "میں جن صفحات کو استرجع کروں وہ میری زیر نظر فہرست میں شامل کیا کریں",
- "tog-minordefault": "تمام ترمیمات کو ہمیشہ بطورِ معمولی ترمیم نشانزد کیا کرو",
- "tog-previewontop": "تدÙ\88Û\8cÙ\86Û\8c خاÙ\86Û\81 سÛ\92 Ù¾Û\81Ù\84Û\92 Ù\86Ù\85ائش دکھاؤ",
- "tog-previewonfirst": "Ù¾Û\81Ù\84Û\8c ترÙ\85Û\8cÙ\85 پر Ù\86Ù\85ائش دکھاؤ",
- "tog-enotifwatchlistpages": "جب Ù\85Û\8cرÛ\92 زÛ\8cر Ù\86ظر صÙ\81ØÛ\81 Û\8cا Ù\85Ù\84Ù\81 Ù\85Û\8cÚº Ú©Ù\88ئÛ\8c تبدÛ\8cÙ\84Û\8c Û\81Ù\88 تÙ\88 Ù\85جھÛ\92 برÙ\82Û\8c Ú\88اک بھÛ\8cجئÛ\92",
- "tog-enotifusertalkpages": "جب میرا تبادلۂ خیال صفحہ میں تبدیلی واقع ہو تو مجھے برقی ڈاک بھیجو",
- "tog-enotifminoredits": "Ù\85جھÛ\92 صÙ\81Øات اÙ\88ر Ù\85Ù\84Ù\81ات Ù\85Û\8cÚº Ú©Û\8c جاÙ\86Û\92 Ù\88اÙ\84Û\8c Ù\85عÙ\85Ù\88Ù\84Û\8c تراÙ\85Û\8cÙ\85 Ú©Û\8c خبر بھÛ\8c بذرÛ\8cعÛ\81 برÙ\82Û\8c Ú\88اک دÛ\8cجئÛ\92",
- "tog-enotifrevealaddr": "خبردارÛ\8c برÙ\82Û\8c خطÙ\88Ø· Ù\85Û\8cÚº Ù\85Û\8cرا برÙ\82Û\8c Ú\88اک پتÛ\81 ظاÛ\81ر کرÙ\88",
- "tog-shownumberswatching": "دÛ\8cÚ©Ú¾Ù\86Û\92 Ù\88اÙ\84Û\92 صارÙ\81Û\8cÙ\86 Ú©Û\8c تعداد دکھاؤ",
+ "tog-extendwatchlist": "ØاÙ\84Û\8cÛ\81 ترÛ\8cÙ\86 تبدÛ\8cÙ\84Û\8cÙ\88Úº Ú©Û\92 بجائÛ\92 جÙ\85Ù\84Û\81 تبدÛ\8cÙ\84Û\8cاں دÛ\8cÚ©Ú¾Ù\86Û\92 Ú©Û\92 Ù\84Û\8cÛ\92 زÛ\8cر Ù\86ظر Ù\81Û\81رست Ú©Û\8c تÙ\88سÛ\8cع کریں",
+ "tog-usenewrc": "حالیہ تبدیلیاں اور زیر نظر فہرست میں تبدیلیوں کو بلحاظ صفحہ گروہ بند کیجئے",
+ "tog-numberheadings": "سرخیوں کو خودکار نمبر دیں",
+ "tog-showtoolbar": "Ø¢Ù\84ات ترÙ\85Û\8cÙ\85 دکھائÛ\8cÚº",
+ "tog-editondblclick": "دÙ\88 Ú©Ù\84Ú© پر صÙ\81Øات Ú©Û\8c ترÙ\85Û\8cÙ\85 کرÛ\8cÚº",
+ "tog-editsectiononrightclick": "قطعہ کے عنوانات پر رائیٹ کلک کے ذریعے قطعہ کی ترمیم کاری فعال کریں",
+ "tog-watchcreations": "میرے تخلیق کردہ صفحات اور اپلوڈ کردہ فائلوں کو میری زیر نظر فہرست میں شامل کریں",
+ "tog-watchdefault": "Ù\85Û\8cرÛ\92 ترÙ\85Û\8cÙ\85 شدÛ\81 صÙ\81Øات اÙ\88ر Ù\81ائÙ\84Ù\88Úº Ú©Ù\88 Ù\85Û\8cرÛ\8c زÛ\8cر Ù\86ظر Ù\81Û\81رست Ù\85Û\8cÚº شاÙ\85Ù\84 کرÛ\8cÚº",
+ "tog-watchmoves": "Ù\85Û\8cرÛ\92 Ù\85Ù\86تÙ\82Ù\84 کردÛ\81 صÙ\81Øات اÙ\88ر Ù\81ائÙ\84Ù\88Úº Ú©Ù\88 Ù\85Û\8cرÛ\8c زÛ\8cر Ù\86ظر Ù\81Û\81رست Ù\85Û\8cÚº شاÙ\85Ù\84 کرÛ\8cÚº",
+ "tog-watchdeletion": "Ù\85Û\8cرÛ\92 ØØ°Ù\81 کردÛ\81 صÙ\81Øات اÙ\88ر Ù\81ائÙ\84Ù\88Úº Ú©Ù\88 Ù\85Û\8cرÛ\8c زÛ\8cر Ù\86ظر Ù\81Û\81رست Ù\85Û\8cÚº شاÙ\85Ù\84 کرÛ\8cÚº",
+ "tog-watchrollback": "میرے استرجع کردہ صفحات کو میری زیر نظر فہرست میں شامل کریں",
+ "tog-minordefault": "ہمیشہ میری تمام ترامیم کو معمولی ترمیم کے طور پر نشان زد کریں",
+ "tog-previewontop": "خاÙ\86Û\81 ترÙ\85Û\8cÙ\85 سÛ\92 Ù¾Û\81Ù\84Û\92 Ù\86Ù\85ائش دکھائÛ\8cÚº",
+ "tog-previewonfirst": "Ù¾Û\81Ù\84Û\8c ترÙ\85Û\8cÙ\85 پر Ù\86Ù\85ائش دکھائÛ\8cÚº",
+ "tog-enotifwatchlistpages": "جب Ù\85Û\8cرÛ\92 زÛ\8cر Ù\86ظر صÙ\81ØÛ\81 Û\8cا Ù\81ائÙ\84 Ù\85Û\8cÚº Ú©Ù\88ئÛ\8c تبدÛ\8cÙ\84Û\8c Û\81Ù\88 تÙ\88 Ù\85جھÛ\92 برÙ\82Û\8c Ú\88اک بھÛ\8cجÛ\8cÚº",
+ "tog-enotifusertalkpages": "جب میرے تبادلۂ خیال صفحہ میں تبدیلی ہو تو مجھے برقی ڈاک بھیجیں",
+ "tog-enotifminoredits": "Ù\85جھÛ\92 صÙ\81Øات اÙ\88ر Ù\81ائÙ\84Ù\88Úº Ù\85Û\8cÚº Ú©Û\8c جاÙ\86Û\92 Ù\88اÙ\84Û\8c Ù\85عÙ\85Ù\88Ù\84Û\8c تراÙ\85Û\8cÙ\85 Ú©Û\8c خبر بھÛ\8c بذرÛ\8cعÛ\81 برÙ\82Û\8c Ú\88اک بھÛ\8cجÛ\8cÚº",
+ "tog-enotifrevealaddr": "اطÙ\84اعاتÛ\8c برÙ\82Û\8c خطÙ\88Ø· Ù\85Û\8cÚº Ù\85Û\8cرا برÙ\82Û\8c Ú\88اک پتÛ\81 ظاÛ\81ر کرÛ\8cÚº",
+ "tog-shownumberswatching": "دÛ\8cÚ©Ú¾Ù\86Û\92 Ù\88اÙ\84Û\92 صارÙ\81Û\8cÙ\86 Ú©Û\8c تعداد دکھائÛ\8cÚº",
"tog-oldsig": "موجودہ دستخط:",
- "tog-fancysig": "(سادہ دستخط بلا خودکار ربط)",
- "tog-uselivepreview": "براÛ\81 راست Ù\86Ù\85ائش (آزÙ\85ائشÛ\8c) استعÙ\85اÙ\84 Ú©Û\8cجئÛ\92",
- "tog-forceeditsummary": "جب Ù\85Û\8cÚº ترÙ\85Û\8cÙ\85Û\8c Ø®Ù\84اصÛ\81 خاÙ\84Û\8c Ú\86Ú¾Ù\88Ú\91Ù\88Úº تÙ\88 Ù\85جھÛ\92 آگاÛ\81 کرÙ\88",
- "tog-watchlisthideown": "زیرِنظرفہرست سے میری ترمیمات چھپاؤ",
- "tog-watchlisthidebots": "زیرِنظرفہرست میں سے روبالی ترمیمات چھپاؤ",
- "tog-watchlisthideminor": "زیرِنظرفہرست سے معمولی ترمیمات چھپاؤ",
- "tog-watchlisthideliu": "زیرِنظرفہرست میں سے داخلِ نوشتہ شدہ صارفین کی ترمیمات چھپاؤ",
- "tog-watchlisthideanons": "زیرِنظرفہرست میں سے نامعلوم صارفین کی ترمیمات چھپاؤ",
- "tog-watchlisthidepatrolled": "زیرِنظرفہرست میں سے گشت شدہ ترمیمات چھپاؤ",
- "tog-ccmeonemails": "دیگر صارفین کو ارسال کردہ برقی خطوط کی نقول مجھے ارسال کریں۔",
- "tog-diffonly": "Ù\85ختÙ\84Ù\81ات Ú©Û\92 Ù\86Û\8cÚ\86Û\92 صÙ\81ØÛ\92 Ú©Û\8c Ù\85Ø´Ù\85Ù\88Ù\84ات Ù\85ت دکھاؤ",
- "tog-showhiddencats": "Ù¾Ù\88Ø´Û\8cدÛ\81 زÙ\85رÛ\81 جات دکھاؤ",
- "tog-norollbackdiff": "استرجع کی انجام دہی کے بعد فرق ترک کیجئے",
- "tog-useeditwarning": "خبردار Ù\85جھÛ\92 جب Ù\85Û\8cÚº غÛ\8cر Ù\85ØÙ\81Ù\88ظ کردÛ\81 تبدÛ\8cÙ\84Û\8cÙ\88Úº Ú©Û\92 ساتھ اÛ\8cÚ© ترÙ\85Û\8cÙ\85 Ú©Û\92 صÙ\81ØÛ\92 Ú©Ù\88 Ú\86Ú¾Ù\88Ú\91 دÙ\88",
- "tog-prefershttps": "دخول نوشتہ کے دوران محفوظ کنکشن استعمال کیجئے",
+ "tog-fancysig": "سادہ دستخط (بلا خودکار ربط)",
+ "tog-uselivepreview": "راست Ù\86Ù\85ائش استعÙ\85اÙ\84 کرÛ\8cÚº",
+ "tog-forceeditsummary": "Ø®Ù\84اصÛ\81 ترÙ\85Û\8cÙ\85 خاÙ\84Û\8c Ú\86Ú¾Ù\88Ú\91Ù\86Û\92 پر Ù\85جھÛ\92 آگاÛ\81 کرÛ\8cÚº",
+ "tog-watchlisthideown": "زیرِنظر فہرست سے میری ترامیم چھپائیں",
+ "tog-watchlisthidebots": "زیرِنظر فہرست سے روبہ جاتی ترامیم چھپائیں",
+ "tog-watchlisthideminor": "زیرِنظر فہرست سے معمولی ترامیم چھپائیں",
+ "tog-watchlisthideliu": "زیرِنظر فہرست سے داخلِ نوشتہ شدہ صارفین کی ترامیم چھپائیں",
+ "tog-watchlisthideanons": "زیرِنظر فہرست سے نامعلوم صارفین کی ترامیم چھپائیں",
+ "tog-watchlisthidepatrolled": "زیرِنظر فہرست سے مراجع شدہ ترامیم چھپائیں",
+ "tog-ccmeonemails": "دÛ\8cگر صارÙ\81Û\8cÙ\86 Ú©Ù\88 ارساÙ\84 کردÛ\81 برÙ\82Û\8c خطÙ\88Ø· Ú©Û\8c Ù\86Ù\82Ù\88Ù\84 Ù\85جھÛ\92 بھÛ\8c ارساÙ\84 کرÛ\8cÚºÛ\94",
+ "tog-diffonly": "Ù\81رÙ\82 Ú©Û\92 Ù\86Û\8cÚ\86Û\92 صÙ\81ØÛ\92 Ú©Û\92 Ù\85Ø´Ù\85Ù\88Ù\84ات Ù\86Û\81 دکھائÛ\8cÚº",
+ "tog-showhiddencats": "Ù¾Ù\88Ø´Û\8cدÛ\81 زÙ\85رÛ\81 جات دکھائÛ\8cÚº",
+ "tog-norollbackdiff": "استرجع کی انجام دہی کے بعد فرق ترک کریں",
+ "tog-useeditwarning": "غÛ\8cر Ù\85ØÙ\81Ù\88ظ تبدÛ\8cÙ\84Û\8cاں Ú\86Ú¾Ù\88Ú\91Ù\86Û\92 پر Ù\85جھÛ\92 آگاÛ\81 کرÛ\8cÚº",
+ "tog-prefershttps": "لاگ ان رہنے کے دوران ہمیشہ محفوظ کنیکشن استعمال کریں",
"underline-always": "ہمیشہ",
"underline-never": "کبھی نہیں",
- "underline-default": "جلد یا متصفح کا ڈیفالٹ",
- "editfont-style": "خاÙ\86Û\82 تدÙ\88Û\8cÙ\86 کا اÙ\86دازÙ\90 تØرÛ\8cر:",
- "editfont-default": "متصفح کا طے شدہ",
- "editfont-monospace": "یکفضائی نویسہ",
- "editfont-sansserif": "بÛ\92ØÙ\84Û\8cÛ\81 Ù\86Ù\88Û\8cسÛ\81",
- "editfont-serif": "ØÙ\84Û\8cÛ\81 Ù\86Ù\88Û\8cسÛ\81",
+ "underline-default": "جلد یا براؤزر کا ڈیفالٹ",
+ "editfont-style": "خاÙ\86Û\82 ترÙ\85Û\8cÙ\85 کا Ù\81اÙ\86Ù¹:",
+ "editfont-default": "براؤزر کا ڈیفالٹ",
+ "editfont-monospace": "مونوسپیسڈ فونٹ",
+ "editfont-sansserif": "سÙ\86س سÛ\8cرÙ\81 Ù\81Ù\88Ù\86Ù¹",
+ "editfont-serif": "سÛ\8cرÙ\81 Ù\81Ù\88Ù\86Ù¹",
"sunday": "اتوار",
"monday": "پير",
"tuesday": "منگل",
"november-date": "$1 نومبر",
"december-date": "$1 دسمبر",
"pagecategories": "{{PLURAL:$1|زمرہ|زمرہ جات}}",
- "category_header": "زمرہ \"$1\" میں مضامین",
+ "category_header": "زمرہ \"$1\" میں صفحات",
"subcategories": "ذیلی زمرہ جات",
- "category-media-header": "زÙ\85رÛ\81 \"$1\" Ù\85Û\8cÚº Ù\88سÛ\8cØ·",
- "category-empty": "‘‘اِس زمرہ میں ابھی کوئی صفحات یا وسیط موجود نہیں.’’",
+ "category-media-header": "زÙ\85رÛ\81 \"$1\" Ù\85Û\8cÚº Ù\85Û\8cÚ\88Û\8cا",
+ "category-empty": "<em>اس زمرہ میں ابھی کوئی صفحہ یا میڈیا موجود نہیں ہے۔</em>",
"hidden-categories": "{{PLURAL:$1|پوشیدہ زمرہ|پوشیدہ زمرہ جات}}",
"hidden-category-category": "پوشیدہ زمرہ جات",
- "category-subcat-count": "{{PLURAL:$2|اِس زمرہ میں صرف درج ذیل ذیلی زمرہ ہے.|اِس زمرہ میں درج ذیل {{PLURAL:$1|ذیلی زمرہ|$1 ذیلی زمرہ جات}}, کل $2 میں سے.}}",
+ "category-subcat-count": "{{PLURAL:$2|اِس زمرہ میں محض درج ذیل ذیلی زمرہ موجود ہے.|اِس زمرہ میں کل $2 میں سے درج ذیل {{PLURAL:$1|ذیلی زمرہ|$1 ذیلی زمرہ جات}} موجود ہیں۔}}",
"category-subcat-count-limited": "اِس زمرہ میں درج ذیل {{PLURAL:$1|ذیلی زمرہ ہے|$1 ذیلی زمرہ جات ہیں}}.",
- "category-article-count": "{{PLURAL:$2|اس زمرہ میں صرف درج ذیل صفحہ شامل کیا گیا ہے۔|اس زمرہ کے کل $2 صفحات میں سے $1 {{PLURAL:$1|صفحہ|صفحات}} درج ذیل {{PLURAL:$1|ہے|ہیں}}۔",
- "category-article-count-limited": "یہ درج ذیل {{PLURAL:$1|صفحہ|$1 صفحات}} اس زمرہ میں مشمول {{PLURAL:$1|ہے|ہیں}}۔",
- "category-file-count": "{{PLURAL:$2|اس زÙ\85رÛ\81 Ù\85Û\8cÚº صرÙ\81 درج Ø°Û\8cÙ\84 Ù\85Ù\84Ù\81 شاÙ\85Ù\84 Ú©Û\8c گئÛ\8c Û\81Û\92Û\94|اس زÙ\85رÛ\81 Ú©Û\8c Ú©Ù\84 $2 Ù\85Ù\84Ù\81ات Ù\85Û\8cÚº سÛ\92 $1 {{PLURAL:$1|Ù\85Ù\84Ù\81|Ù\85Ù\84Ù\81ات}} درج Ø°Û\8cÙ\84 {{PLURAL:$1|Û\81Û\92|Û\81Û\8cÚº}}۔",
- "category-file-count-limited": "یہ درج ذیل {{PLURAL:$1|صفحہ|$1 صفحات}} اس زمرہ میں شامل {{PLURAL:$1|ہے|ہیں}}۔",
- "listingcontinuesabbrev": "۔جاری",
+ "category-article-count": "{{PLURAL:$2|اس زمرہ میں محض درج ذیل صفحہ موجود ہے۔|اس زمرہ کے کل $2 صفحات میں سے $1 {{PLURAL:$1|صفحہ|صفحات}} درج ذیل {{PLURAL:$1|ہے|ہیں}}}}۔",
+ "category-article-count-limited": "درج ذیل {{PLURAL:$1|صفحہ|$1 صفحات}} اس زمرہ میں شامل {{PLURAL:$1|ہے|ہیں}}۔",
+ "category-file-count": "{{PLURAL:$2|اس زÙ\85رÛ\81 Ù\85Û\8cÚº صرÙ\81 درج Ø°Û\8cÙ\84 Ù\81ائÙ\84 Ù\85Ù\88جÙ\88د Û\81Û\92Û\94|اس زÙ\85رÛ\81 Ú©Û\8c Ú©Ù\84 $2 Ù\81ائÙ\84Ù\88Úº Ù\85Û\8cÚº سÛ\92 $1 {{PLURAL:$1|Ù\81ائÙ\84|Ù\81ائÙ\84Û\8cÚº}} درج Ø°Û\8cÙ\84 {{PLURAL:$1|Û\81Û\92|Û\81Û\8cÚº}}}}۔",
+ "category-file-count-limited": "درج ذیل {{PLURAL:$1|فائل|$1 فائلیں}} اس زمرہ میں شامل {{PLURAL:$1|ہے|ہیں}}۔",
+ "listingcontinuesabbrev": "جاری۔",
"index-category": "فہرست شدہ صفحات",
- "noindex-category": "غÛ\8cر Ù\85Ù\86درج صفحات",
- "broken-file-category": "صفحات بمعہ شکستہ فائل روابط",
+ "noindex-category": "غÛ\8cر Ù\81Û\81رست شدÛ\81 صفحات",
+ "broken-file-category": "صفحات مع شکستہ فائل روابط",
"categoryviewer-pagedlinks": "($1) ($2)",
"about": "تعارف",
- "article": "صÙ\81ØÛ\82 Ù\85Ø´Ù\85Ù\88Ù\84",
- "newwindow": "(نـئی ونـڈو میـں)",
+ "article": "صÙ\81ØÛ\81 Ù\85Ù\88اد",
+ "newwindow": "(نـئی ونـڈو میـں کھولیں)",
"cancel": "منسوخ",
- "moredotdotdot": "اور...",
+ "moredotdotdot": "مزید...",
"morenotlisted": "یہ فہرست مکمل نہیں ہے۔",
- "mypage": "میرا صفحہ",
+ "mypage": "صفحہ",
"mytalk": "تبادلۂ خیال",
- "anontalk": "اس IP کیلیے بات چیت",
+ "anontalk": "اس آئی پی پتہ کا تبادلۂ خیال",
"navigation": "رہنمائی",
"and": " اور",
"qbfind": "ڈھونڈ",
"nstab-template": "سانچہ",
"nstab-help": "معاونت",
"nstab-category": "زمرہ",
+ "mainpage-nstab": "صفحۂ اول",
"nosuchaction": "کوئی سا عمل نہیں",
"nosuchactiontext": "URL کی جانب سے مختص کیا گیا عمل درست نہیں.\nآپ نے شاید URL غلط لکھا، یا کسی غیر صحیح ربط کی پیروی کی ہے.\n{{اِس سے SITENAME کے زیرِ استعمال مصنع لطیف میں کھٹمل کی نشاندہی کا بھی اندیشہ ہے}}.",
"nosuchspecialpage": "کوئی ایسا خاص صفحہ نہیں",
"createacct-reason": "وجہ",
"createacct-reason-ph": "آپ دوسرا کھاتہ کیوں تخلیق کررہے ہیں",
"createacct-submit": "آپ کا کھاتا بنائیں",
- "createacct-another-submit": "دوسرا کھاتہ تخلیق کریں",
+ "createacct-another-submit": "کھاتہ بنائیں",
"createacct-benefit-heading": "{{SITENAME}} آپ جیسے لوگوں کی طرف سے بنایا گیا ہے ۔",
"createacct-benefit-body1": "{{PLURAL:$1|ترمیم|ترامیم}}",
"createacct-benefit-body2": "$1 {{PLURAL:$1|صفحہ|صفحات}}",
"nocreate-loggedin": "آپ کو نئے صفحات تخلیق کرنے کی اجازت نہیں ہے.",
"sectioneditnotsupported-title": "قطعہ کی تدوین حمایت شدہ نہیں ہے",
"sectioneditnotsupported-text": "اِس صفحہ میں قطعہ کی تدوین حمایت شدہ نہیں ہے.",
- "permissionserrors": "اخطائÛ\92 اجازت",
+ "permissionserrors": "خطائے اجازت",
"permissionserrorstext": "درج ذیل {{PLURAL:$1|وجہ|وجوہات}} کی بناء پر آپ کو ایسا کرنے کی اجازت نہیں ہے:",
"permissionserrorstext-withaction": "درج ذیل {{PLURAL:$1|وجہ|وجوہات}} کی بناء پر آپ کو $2 کرنے کی اجازت نہیں ہے:",
"recreate-moveddeleted-warn": "''' انتباہ: آپ ایک گزشتہ حذف شدہ صفحہ دوبارہ تخلیق کررہے ہیں. '''\n\nآپ کو اِس بات پر غور کرنا چاہئے کہ آیا اِس صفحہ کی تدوین جاری رکھنا موزوں ہے یا نہیں.\nصفحہ کا نوشتۂ حذف شدگی و منتقلی یہاں سہولت کی خاطر مہیّا کیا جارہا ہے:",
"revdelete-legend": "رویتی پابندیاں لگائیں",
"revdelete-hide-text": "نظرثانی متن چھپاؤ",
"revdelete-hide-image": "مشمولاتِ ملف چھپاؤ",
- "revdelete-hide-name": "عمل اور ہدف کو چھپاؤ",
+ "revdelete-hide-name": "ہدف اور پیرامیٹرز کو چھپائیں",
"revdelete-hide-comment": "ترمیمی تبصرہ چھپاؤ",
"revdelete-hide-user": "ترمیم کار کا اسمِ صارف / آئی.پی پتہ چُھپاؤ",
"revdelete-radio-same": "(تبدیل مت کرو)",
"badsig": "ناقص خام دستخط.\nHTML tags جانچئے.",
"badsiglength": "آپ کا دستخط کافی طویل ہے.\nیہ $1 {{PLURAL:$1|حرف|حروف}} سے زیادہ نہیں ہونا چاہئے.",
"yourgender": "جنس:",
- "gender-unknown": "غÛ\8cرÙ\85ختص شدÛ\81",
+ "gender-unknown": "آپ Ú©Û\92 تذکرÛ\81 Ú©Û\92 Ù\88Ù\82تØ\8c سÙ\88Ù\81Ù¹Ù\88Û\8cئر غÛ\8cر جاÙ\86بدار جÙ\86سÛ\8c اÙ\84Ù\81اظ استعÙ\85اÙ\84 کرÛ\92 گا اگر Ù\85Ù\85Ú©Ù\86 Û\81Ù\88",
"gender-male": "مرد",
"gender-female": "عورت",
"prefs-help-gender": "اختیاری: مصنعلطیف کی طرف سے صحیحالجنس تخاطب کیلئے استعمال ہوتا ہے. یہ معلومات عام ہوگی.",
"userrights-lookup-user": "گروہائے صارف کا انتظام",
"userrights-user-editname": "کوئی اسمصارف داخل کیجئے:",
"editusergroup": "ترمیم گروہائے صارف",
- "editinguser": "تبدیلئ اختیارات برائے صارف '''[[صارف:$1|$1]]''' $2",
+ "editinguser": "تبدیلی اختیارات صارف برائے {{GENDER:$1|صارف}} <strong>[[صارف:$1|$1]]</strong> $2",
"userrights-editusergroup": "ترمیم گروہائے صارف",
"saveusergroups": "گروہائے صارف محفوظ",
"userrights-groupsmember": "رکنِ:",
"boteditletter": " خودکار",
"rc_categories_any": "کوئی بھی",
"rc-change-size-new": "$1 {{PLURAL:$1|بائٹ|بائٹس}} تبدیلی کے بعد",
- "rc-enhanced-expand": "تفصیلات دِکھائیں (JavaScript درکار)",
+ "rc-enhanced-expand": "تفصیلات دکھائیں",
"rc-enhanced-hide": "تفصیلات چھپائیے",
"recentchangeslinked": "متعلقہ تبدیلیاں",
"recentchangeslinked-feed": "متعلقہ تبدیلیاں",
"uploadbtn": "زبراثقال ملف (اپ لوڈ فائل)",
"reuploaddesc": "زبراثقال ورقہ (فارم) کیجانب واپس۔",
"uploadnologin": "آپ داخل شدہ حالت میں نہیں",
- "uploadnologintext": "زبراثقال ملف (فائل اپ لوڈ) کے لیۓ آپکو [[Special:UserLogin|داخل شدہ]] حالت میں ہونا لازم ہے۔",
- "uploadtext": "\n'''یادآوری''': اگر آپ اپنی ملف (فائل) زبراثقال کرتے وقت ، خلاصہ کے خانے میں ، درج ذیل دو باتوں کی وضاحت نہیں کرتے تو ملف کو حذف کیا جاسکتا ہے:\n#ملف یا فائل کا '''مـاخـذ''' ، یعنی:\n#*اگر یہ آپ نے خود تخلیق کی ہے تو بیان کردیجیۓ۔\n#*اگر یہ روۓ خط (آن لائن) دستیاب ہے ، تو اس وقوع یعنی سائٹ کا '''رابطہ (لنک)''' دیجیۓ۔\n#*اگر آپ نے اسے کسی دوسری زبان کے {{SITENAME}} سے لیا ہے تو اسکا نام تحریر کردیجیۓ۔\n#صاحب ِحق ِطبع و نشر اور ملف کے اجازہ (لائسنس) کے بارے میں:\n#*ملف کے اجازہ کے بارے میں یہ تحریر کیجیۓ کہ اسکی موجودہ حیثیت کیا ہے۔\n#*اگر آپ خود اسکا حق ِطبع و نشر رکھتے ہیں تو آپ پر لازم ہے کہ آپ اسے ٹ [[دائرۂ عام]] ن (پبلک ڈومین) میں بھی آذاد کردیں۔\n\nجب کوئی صارف مستقل ایسی ملف زبراثقال کرتا رہے کہ جس کے اجازہ کے بارے میں غلط بیانی کی گئی ہو یا وہ مستقل ایسے عکس زبراثقال کرتا رہے کہ جنکے بارے میں کوئی بیان تحریر نہ کیا گیا ہو تو ایسی صورت میں پابندی لگاۓ جانے کا قوی امکان موجود ہے۔\n\nمِلَف (فائل) بھیجنے کیلیے درج ذیل ورقہ (فارم) استعمال کیجیے، اگر آپ اب تک ارسال کردہ تصاویر کو دیکھنا یا تلاش کرنا چاہتے ہیں تو [[Special:FileList|ارسال کردہ تصاویر]] کے ربط پر جائیے۔ <br /> تمام ارسال و حذف کی گئی تصاویر کو [[Special:Log/upload|نوشتۂ منتقلی]] میں درج کر لیا جاتا ہے۔\n\nتصویر کی منتقلی کے بعد، اسکو کسی صفحہ پر رکھنے کیلیے مندرجہ ذیل صورت میں رمـز (کوڈ) استعمال کیجیۓ۔\n\n'''<nowiki>[[تصویر:ملف کا نام|متبادل متن]]</nowiki>'''\n\n* مندرجہ بالا رموز آپ انگریزی میں بھی درج کرسکتے ہیں، یعنی\n<nowiki>[[Image:File name|Alt.text]]</nowiki>\n* ملف کے ساتھ براہ راست رابطہ کیلیے\nکی طرز میں ربط استعمال کیجیۓ۔ '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>'''\n* ملف کا نام ؛ حرف ابجد کے لیۓ حساس ہے لہذا اگر زبراثقال کرتے وقت ملف کا نام -- name:JPG ہے اور آپ رابطہ رکھتے وقت name:jpg یــا Name:jpg رکھتے ہیں تو ربط کام نہیں کرے گا",
+ "uploadnologintext": "فائلیں اپلوڈ کرنے کے لیے براہ کرم $1 ہوں",
+ "uploadtext": "\n'''اطلاع''': اگر آپ اپنی فائل اپلوڈ کرتے وقت خلاصہ کے خانے میں درج ذیل دو باتوں کی وضاحت نہیں کریں گے تو اس فائل کو حذف کیا جاسکتا ہے:\n# فائل کا '''مـاخـذ''' ، یعنی:\n#*اگر یہ آپ نے خود تخلیق کی ہے تو اسے بیان کریں۔\n#*اگر یہ آن لائن دستیاب ہے تو اس سائٹ کا '''ربط''' درج کریں۔\n#*اگر آپ نے اسے کسی دوسری زبان کے {{SITENAME}} سے لیا ہے تو اسکا نام تحریر کریں۔\n#صاحب حق طبع و نشر اور فائل کے اجازت نامہ کے بارے میں:\n#* فائل کے اجازت نامہ کے متعلق یہ درج کریں کہ اس کی موجودہ حیثیت کیا ہے۔\n#*اگر آپ خود اسکا حق طبع و نشر رکھتے ہیں تو آپ پر لازم ہے کہ آپ اسے [[دائرۂ عام]] (پبلک ڈومین) میں بھی شائع کریں۔\n\nجب کوئی صارف مستقل ایسی فائل اپلوڈ کرتا رہے جس کے اجازت نامہ کے بارے میں غلط بیانی کی گئی ہو یا وہ مستقل ایسی تصاویر اپلوڈ کرے جن کے بارے میں کوئی وضاحت موجود نہ ہو تو ایسی صورت میں اس صارف پر پابندی لگائے جانے کا قوی امکان موجود ہے۔\n\nفائل اپلوڈ کرنے کے لیے ذیل میں موجود فارم استعمال کریں، اگر آپ جملہ اپلوڈ کردہ تصاویر کو دیکھنا یا تلاش کرنا چاہتے ہیں تو [[Special:FileList|اس فہرست]] کو ملاحظہ فرمائیں۔ <br /> تمام اپلوڈ کردہ و حذف شدہ تصاویر کو [[Special:Log/upload|نوشتۂ منتقلی]] میں درج کر لیا جاتا ہے۔\n\nتصویر کی منتقلی کے بعد، اسکو کسی صفحہ پر رکھنے کیلیے مندرجہ ذیل طریقہ سے استعمال کریں۔\n\n'''<nowiki>[[تصویر:فائل کا نام|متبادل متن]]</nowiki>'''\n\n* مندرجہ بالا رموز آپ انگریزی میں بھی درج کرسکتے ہیں، یعنی\n<nowiki>[[Image:File name|Alt.text]]</nowiki>\n* فائل کا ربط درج کرنے کے لیے۔ '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>'''\n* ملف کا نام؛ حرف ابجد کے لیے حساس ہے لہذا اگر اپلوڈ کرتے وقت فائل کا نام -- name:JPG ہے اور آپ name:jpg یــا Name:jpg کا ربط درج کرتے ہیں تو ربط کام نہیں کرے گا۔",
"uploadlogpage": "نوشتۂ زبراثقال (اپ لوڈ لاگ)",
"uploadlogpagetext": "درج ذیل میں حالیہ زبراثقال (اپ لوڈ) کی گئی املاف (فائلوں) کی فہرست دی گئی ہے۔",
"filedesc": "خلاصہ",
"wlnote": "نیچےآخری $1 تبدیلیاں ہیں جو کے پیچھلے <b>$2</b> گھنٹوں میں کی گئیں۔",
"wlshowlast": "دکھائیں آخری $1 گھنٹے $2 دن",
"watchlist-options": "اختیارات برائے زیرِنظرفہرست",
+ "enotif_body": "جناب $WATCHINGUSERNAME!\n\n$PAGEINTRO $NEWPAGE\n\nخلاصہ ترمیم: $PAGESUMMARY $PAGEMINOREDIT\n\nصارف سے رابطہ کریں:\nبذریعہ برقی خط: $PAGEEDITOR_EMAIL\nبذریعہ ویکی: $PAGEEDITOR_WIKI\n\nاس صفحہ میں آئندہ ہونے والی تبدیلیوں کی اطلاعات آپ کو موصول نہیں ہوگی جب تک آپ لاگ ان ہو کر اس صفحہ کو ملاحظہ نہ کر لیں. نیز آپ اپنی زیر نظر فہرست میں موجود تمام صفحات سے اطلاعی علامتیں بھی ختم کر سکتے ہیں.\n\nنظام {{SITENAME}} برائے اطلاعات\n\n--\nاطلاعات بذریعہ برقی خط کی ترتیبات تبدیل کرنے کے لیے\n{{canonicalurl:{{#special:Preferences}}}} ملاحظہ فرمائیں\n\nاپنی زیر نظر فہرست کی ترتیبات میں تبدیلی کے لیے\n{{canonicalurl:{{#special:EditWatchlist}}}} ملاحظہ فرمائیں\n\nاس صفحہ کو اپنی زیر نظر فہرست سے حذف کرنے کے لیے\n$UNWATCHURL ملاحظہ کریں\n\nتجاویز اور مزید معاونت کے لیے ملاحظہ فرمائیں:\n$HELPPAGE",
"created": "بنا دیا گیا",
"changed": "تبدیل کردیاگیا",
"deletepage": "صفحہ ضائع کریں",
"sp-contributions-uploads": "اثقالات",
"sp-contributions-logs": "نوشتہ جات",
"sp-contributions-talk": "گفتگو",
- "sp-contributions-userrights": "صارÙ\81 Ú©Û\92 ØÙ\82Ù\88Ù\82 کا اÙ\86تظاÙ\85",
+ "sp-contributions-userrights": "اÙ\86تظاÙ\85 اختÛ\8cارات صارÙ\81",
"sp-contributions-search": "تلاش برائے مساہمات",
"sp-contributions-username": "آئی.پی پتہ یا اسمِ صارف:",
"sp-contributions-toponly": "صرف حالیہ ترین نظرثانی ترمیمات دِکھاؤ",
"contribslink": "شراکت",
"blocklogpage": "نوشتۂ پابندی",
"block-log-flags-nocreate": "کھاتے کی تخلیق غیرفعال",
- "move-page": "منتقلی",
+ "move-page": "منتقلی $1",
"move-page-legend": "منتقلئ صفحہ",
- "movepagetext": "نیچے دیا گیا تشکیلہ (فـارم) استعمال کرکے اس صفحہ کا عنوان دوبارہ منتخب کیا جاسکتا ہے، ساتھ ہی اس سے منسلک تاریخچہ بھی نۓ نام پر منتقل ہوجاۓ گا۔ اسکے بعد سے اس صفحے کا پرانا نام ، نۓ نام کی جانب -- لوٹایا گیا صفحہ -- کی حیثیت اختیار کرلے گا۔ لیکن یادآوری کرلیجیۓ دیگر صفحات پر ، پرانے صفحہ کی جانب دیۓ گۓ روابط (لنکس) تبدیل نہیں ہونگے؛ اس بات کو یقینی بنانا ضروری ہے کہ کوئی دوہرا یا شکستہ -- پلٹایا گیا ربط -- نہ رہ جاۓ۔\n\nلہذا یہ یقینی بنانا آپکی ذمہ داری ہے کہ تمام روابط درست صفحات کی جانب رہنمائی کرتے رہیں۔\n\nیہ بات بھی ذہن نشین کرلیجیۓ کہ اگر نۓ منتخب کردہ نام کا صفحہ پہلے سے ہی موجود ہو تو ہوسکتا ہے کہ صفحہ منتقل نہ ہو ، ؛ ہاں اگر پہلے سے موجود صفحہ خالی ہے ، یا وہ صرف ایک -- لوٹایا گیا صفحہ -- ہو اور اس سے کوئی تاریخچہ منسلک نہ ہو تو منتقلی ہوجاۓ گی۔ گویا ، کسی خامی کی صورت میں آپ صفحہ کو دوبارہ اسی پرانے نام کی جانب منتقل کرسکتے ہیں اور اس طرح پہلے سے موجود کسی صفحہ میں کوئی حذف و خامی نہیں ہوگی۔\n\n''' انـتـبـاہ !'''\n کسی اہم اور مقبول صفحہ کی منتقلی ، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیۓ ؛ منتقلی سے قبل براہ کرم یقین کرلیجۓ کہ آپ اسکے منطقی نتائج سے باخبر ہیں۔",
+ "movepagetext": "درج ذیل فارم کے ذریعہ صفحہ کو نیا نام دیا جاسکتا ہے، اس کے ساتھ صفحہ کا تاریخچہ بھی منتقل ہو جائے گا اور\nنئے عنوان کے جانب قدیم عنوان کو رجوع مکرر کردیا جائے گا۔\n\nاس بات کا یقین کر لیں کہ [[Special:DoubleRedirects|دوہرے]] یا [[Special:BrokenRedirects|شکستہ رجوع مکررات]] موجود نہ ہوں۔\n\nنیز آپ اس بات کو بھی یقینی بنانے کے ذمہ دار ہیں کہ روابط انہیں جگہوں سے مربوط رہیں جہاں ہونا چاہیے۔\n\nخیال رہے کہ یہ صفحہ منتقل '''نہیں''' ہوگا اگر نئے عنوان کے ساتھ صفحہ پہلے سے موجود ہو، ہاں اگر صفحہ خالی ہو اور اس کا گذشتہ ترمیمی تاریخچہ موجود نہ ہو تو منتقل کیا جا سکتا ہے۔\nاس کا مطلب ہے آپ سے اگر غلطی ہوجائے تو آپ صفحہ کو اسی جگہ لوٹا سکتے ہیں، تاہم موجود صفحہ پر برتحریر (overwrite) نہیں کرسکتے۔\n\n'''انتباہ!'''\nکسی اہم اور مقبول صفحہ کی منتقلی، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیے \nمنتقلی سے قبل براہ کرم یقین کرلیں کہ آپ اس کے منطقی نتائج سے باخبر ہیں۔",
"movepagetext-noredirectfixer": "درج ذیل ورقہ کے ذریعہ صفحہ کو نیا نام دیا جاسکتا ہے، اس کے ساتھ صفحہ کا تاریخچہ بھی منتقل ہوجائیگا۔\nنئے عنوان کے جانب قدیم عنوان کو رجوع مکرر کردیا جائیگا۔\n\nیقین کرلیں کہ [[Special:DoubleRedirects|مکرر]] یا [[Special:BrokenRedirects|شکستہ رجوع مکررات]] موجود نہیں ہیں۔\nآپ اس بات کو یقینی بنانے کے ذمہ دار ہیں کہ روابط انہیں جگہوں سے مربوط ہیں جن کو فرض کیا گیا ہے۔\n\nخیال رہے کہ یہ صفحہ منتقل '''نہیں''' ہوگا اگر نئے عنوان کے ساتھ صفحہ پہلے سے موجود ہو، سوائے اس کے کہ صفحہ خالی ہو اور اس کا گذشتہ ترمیمی تاریخچہ موجود نہ ہو۔\nاس کا مطلب ہے آپ سے اگر غلطی ہوجائے تو آپ صفحہ کو اسی جگہ لوٹا سکتے ہیں، تاہم موجود صفحہ پر برتحریر (overwrite) نہیں کرسکتے۔\n\n'''انتباہ!'''\nکسی اہم اور مقبول صفحہ کی منتقلی، غیرمتوقع اور پریشان کن بھی ہی ہوسکتی ہے اس لیۓ؛ \nمنتقلی سے قبل براہ کرم یقین کرلیجۓ کہ آپ اسکے منطقی نتائج سے باخبر ہیں۔",
- "newtitle": "نـیــا عـنــوان",
+ "newtitle": "نـیــا عـنــوان:",
"move-watch": "صفحہ زیر نظر",
"movepagebtn": "مـنـتـقـل",
"pagemovedsub": "انتقال کامیاب",
"delete_and_move": "حذف اور منتقل",
"delete_and_move_text": "==حذف شدگی لازم==\n\nمنتقلی کے سلسلے میں انتخاب کردہ مضمون \"[[:$1]]\" پہلے ہی موجود ہے۔ کیا آپ اسے حذف کرکے منتقلی کیلیۓ راستہ بنانا چاہتے ہیں؟",
"delete_and_move_confirm": "ہاں، صفحہ حذف کر دیا جائے",
- "delete_and_move_reason": "منتقلی کے سلسلے میں حذف",
+ "delete_and_move_reason": "[[$1]] سے منتقلی کے سلسلے میں حذف",
"export": "برآمد صفحات",
"allmessages": "نظامی پیغامات",
"allmessagesname": "نام",
$this->error( "Could not get file listing.", 1 );
}
- $nameBatch = array();
+ $pathBatch = array();
foreach ( $list as $path ) {
if ( preg_match( '#^(thumb|deleted)/#', $path ) ) {
continue; // handle ugly nested containers on stock installs
}
- $nameBatch[] = basename( $path );
- if ( count( $nameBatch ) >= $this->mBatchSize ) {
- $this->checkFiles( $repo, $nameBatch, $verbose );
- $nameBatch = array();
+ $pathBatch[] = $path;
+ if ( count( $pathBatch ) >= $this->mBatchSize ) {
+ $this->checkFiles( $repo, $pathBatch, $verbose );
+ $pathBatch = array();
}
}
- $this->checkFiles( $repo, $nameBatch, $verbose );
+ $this->checkFiles( $repo, $pathBatch, $verbose );
}
- protected function checkFiles( LocalRepo $repo, array $names, $verbose ) {
- if ( !count( $names ) ) {
+ protected function checkFiles( LocalRepo $repo, array $paths, $verbose ) {
+ if ( !count( $paths ) ) {
return;
}
$dbr = $repo->getSlaveDB();
+ $curNames = array();
+ $oldNames = array();
$imgIN = array();
$oiWheres = array();
- foreach ( $names as $name ) {
- if ( strpos( $name, '!' ) !== false ) {
+ foreach ( $paths as $path ) {
+ $name = basename( $path );
+ if ( preg_match( '#^archive/#', $path ) ) {
if ( $verbose ) {
$this->output( "Checking old file $name\n" );
}
- list( , $base ) = explode( '!', $name ); // <TS_MW>!<img_name>
+ $oldNames[] = $name;
+ list( , $base ) = explode( '!', $name, 2 ); // <TS_MW>!<img_name>
$oiWheres[] = $dbr->makeList(
array( 'oi_name' => $base, 'oi_archive_name' => $name ),
LIST_AND
$this->output( "Checking current file $name\n" );
}
+ $curNames[] = $name;
$imgIN[] = $name;
}
}
array(
$dbr->selectSQLText(
'image',
- array( 'name' => 'img_name' ),
+ array( 'name' => 'img_name', 'old' => 0 ),
$imgIN ? array( 'img_name' => $imgIN ) : '1=0'
),
$dbr->selectSQLText(
'oldimage',
- array( 'name' => 'oi_archive_name' ),
+ array( 'name' => 'oi_archive_name', 'old' => 1 ),
$oiWheres ? $dbr->makeList( $oiWheres, LIST_OR ) : '1=0'
)
),
__METHOD__
);
- $namesFound = array();
+ $curNamesFound = array();
+ $oldNamesFound = array();
foreach ( $res as $row ) {
- $namesFound[] = $row->name;
+ if ( $row->old ) {
+ $oldNamesFound[] = $row->name;
+ } else {
+ $curNamesFound[] = $row->name;
+ }
}
- $namesOrphans = array_diff( $names, $namesFound );
- foreach ( $namesOrphans as $name ) {
+ foreach ( array_diff( $curNames, $curNamesFound ) as $name ) {
+ $file = $repo->newFile( $name );
// Print name and public URL to ease recovery
- if ( strpos( $name, '!' ) !== false ) {
- list( , $base ) = explode( '!', $name ); // <TS_MW>!<img_name>
- $file = $repo->newFromArchiveName( Title::makeTitle( NS_FILE, $base ), $name );
+ if ( $file ) {
+ $this->output( $name . "\n" . $file->getCanonicalUrl() . "\n\n" );
} else {
- $file = $repo->newFile( $name );
+ $this->error( "Cannot get URL for bad file title '$name'" );
}
+ }
+
+ foreach ( array_diff( $oldNames, $oldNamesFound ) as $name ) {
+ list( , $base ) = explode( '!', $name, 2 ); // <TS_MW>!<img_name>
+ $file = $repo->newFromArchiveName( Title::makeTitle( NS_FILE, $base ), $name );
+ // Print name and public URL to ease recovery
$this->output( $name . "\n" . $file->getCanonicalUrl() . "\n\n" );
}
}
mccShowUsage();
exit( 0 );
}
-$mcc = new MWMemcached( array(
+$mcc = new MemcachedClient( array(
'persistent' => true,
'debug' => $debug,
) );
'scripts' => array(
'resources/lib/phpjs-sha1/sha1.js',
'resources/src/mediawiki/mediawiki.js',
+ 'resources/src/mediawiki/mediawiki.requestIdleCallback.js',
'resources/src/mediawiki/mediawiki.errorLogger.js',
),
'debugScripts' => 'resources/src/mediawiki/mediawiki.log.js',
"ooui-dialog-process-dismiss": "Odbaci",
"ooui-dialog-process-retry": "Pokušajte ponovo",
"ooui-dialog-process-continue": "Nastavi",
+ "ooui-selectfile-button-select": "Izaberi datoteku",
"ooui-selectfile-placeholder": "Nijedna datoteka nije izabrana"
}
"Polda18",
"Tchoř",
"ශ්වෙත",
- "Vojtěch Dostál"
+ "Vojtěch Dostál",
+ "Matěj Suchánek"
]
},
"ooui-outline-control-move-down": "Přesunout položku dolů",
"ooui-dialog-process-continue": "Pokračovat",
"ooui-selectfile-button-select": "Vybrat soubor",
"ooui-selectfile-not-supported": "Výběr souboru není podporován",
- "ooui-selectfile-placeholder": "Nebyl vybrán žádný soubor"
+ "ooui-selectfile-placeholder": "Nebyl vybrán žádný soubor",
+ "ooui-selectfile-dragdrop-placeholder": "Umístěte soubor sem"
}
"@metadata": {
"authors": [
"Malafaya",
- "十弌"
+ "十弌",
+ "飞舞回堂前"
]
},
- "ooui-toolbar-more": "還多"
+ "ooui-toolbar-more": "更多"
}
/*!
- * OOjs UI v0.13.1
+ * OOjs UI v0.13.2
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2015 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-11-03T21:42:28Z
+ * Date: 2015-11-10T23:33:07Z
*/
@-webkit-keyframes oo-ui-progressBarWidget-slide {
from {
}
.oo-ui-progressBarWidget {
max-width: 50em;
+ background-color: #ffffff;
border: 1px solid #cccccc;
border-radius: 0.25em;
overflow: hidden;
overflow: hidden;
}
.oo-ui-popupWidget-popup {
+ background-color: #ffffff;
border: 1px solid #cccccc;
border-radius: 0.25em;
- background-color: #ffffff;
box-shadow: 0 0.15em 0.5em 0 rgba(0, 0, 0, 0.2);
}
.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
box-sizing: border-box;
}
.oo-ui-dropdownInputWidget select {
- background: #ffffff;
+ background-color: #ffffff;
height: 2.5em;
padding: 0.5em;
font-size: inherit;
}
.oo-ui-menuSelectWidget {
position: absolute;
- background: #ffffff;
+ background-color: #ffffff;
margin-top: -1px;
border: 1px solid #cccccc;
border-radius: 0 0 0.25em 0.25em;
position: relative;
width: 100%;
max-width: 50em;
+ background-color: #ffffff;
margin-right: 0.5em;
}
.oo-ui-dropdownWidget-handle {
}
.oo-ui-selectFileWidget-info {
height: 2.4em;
+ background-color: #ffffff;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 0.25em;
}
}
.oo-ui-selectFileWidget-dropTarget {
line-height: 3.5em;
+ background-color: #ffffff;
border: 1px dashed #aaaaaa;
padding: 0.5em 1em;
margin-bottom: 0.5em;
- background: #ffffff;
text-align: center;
vertical-align: middle;
}
.oo-ui-capsuleItemWidget.oo-ui-widget-disabled > .oo-ui-indicatorElement-indicator {
opacity: 0.2;
}
-.oo-ui-comboBoxWidget {
+.oo-ui-comboBoxInputWidget {
display: inline-block;
position: relative;
width: 100%;
max-width: 50em;
margin-right: 0.5em;
}
-.oo-ui-comboBoxWidget > .oo-ui-menuSelectWidget {
+.oo-ui-comboBoxInputWidget > .oo-ui-menuSelectWidget {
z-index: 1;
width: 100%;
}
-.oo-ui-comboBoxWidget > .oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
+.oo-ui-comboBoxInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
cursor: pointer;
}
-.oo-ui-comboBoxWidget:last-child {
- margin-right: 0;
+.oo-ui-comboBoxInputWidget-php input::-webkit-calendar-picker-indicator {
+ opacity: 0 !important;
+ position: absolute;
+ right: 0;
+ top: 0;
+ height: 2.5em;
+ width: 2.5em;
+ padding: 0;
}
-.oo-ui-comboBoxWidget-handle {
- border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 0.25em;
+.oo-ui-comboBoxInputWidget-php > .oo-ui-indicatorElement-indicator {
+ pointer-events: none;
}
-.oo-ui-comboBoxWidget-handle:hover {
- border-color: rgba(0, 0, 0, 0.2);
+.oo-ui-comboBoxInputWidget:last-child {
+ margin-right: 0;
}
-.oo-ui-comboBoxWidget.oo-ui-widget-disabled .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator,
-.oo-ui-comboBoxWidget-empty .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+.oo-ui-comboBoxInputWidget.oo-ui-widget-disabled .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator,
+.oo-ui-comboBoxInputWidget-empty .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
cursor: default;
opacity: 0.2;
}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget {
+.oo-ui-comboBoxInputWidget > .oo-ui-selectWidget {
margin-top: -3px;
}
.oo-ui-searchWidget-query {
/*!
- * OOjs UI v0.13.1
+ * OOjs UI v0.13.2
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2015 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-11-03T21:42:20Z
+ * Date: 2015-11-10T23:32:59Z
*/
/**
* @class
/*!
- * OOjs UI v0.13.1
+ * OOjs UI v0.13.2
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2015 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-11-03T21:42:28Z
+ * Date: 2015-11-10T23:33:07Z
*/
@-webkit-keyframes oo-ui-progressBarWidget-slide {
from {
}
.oo-ui-progressBarWidget {
max-width: 50em;
+ background-color: #ffffff;
border: 1px solid #cccccc;
border-radius: 0.1em;
overflow: hidden;
overflow: hidden;
}
.oo-ui-popupWidget-popup {
+ background-color: #ffffff;
border: 1px solid #aaaaaa;
border-radius: 0.2em;
- background-color: #ffffff;
box-shadow: 0 0.15em 0 0 rgba(0, 0, 0, 0.15);
}
.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
box-sizing: border-box;
}
.oo-ui-dropdownInputWidget select {
- background: #ffffff;
+ background-color: #ffffff;
height: 2.275em;
font-size: inherit;
font-family: inherit;
}
.oo-ui-menuSelectWidget {
position: absolute;
- background: #ffffff;
+ background-color: #ffffff;
margin-top: -1px;
border: 1px solid #aaaaaa;
border-radius: 0 0 0.2em 0.2em;
position: relative;
width: 100%;
max-width: 50em;
- background: #ffffff;
+ background-color: #ffffff;
margin-right: 0.5em;
}
.oo-ui-dropdownWidget-handle {
.oo-ui-dropdownWidget-handle {
padding: 0.5em 0;
height: 2.275em;
+ line-height: 1.275;
border: 1px solid #cccccc;
border-radius: 0.1em;
}
}
.oo-ui-selectFileWidget-info {
height: 2.4em;
+ background-color: #ffffff;
border: 1px solid #cccccc;
border-radius: 0.1em;
}
}
.oo-ui-selectFileWidget-dropTarget {
line-height: 3.5em;
+ background-color: #ffffff;
border: 1px dashed #cccccc;
padding: 0.5em 1em;
margin-bottom: 0.5em;
- background: #ffffff;
text-align: center;
vertical-align: middle;
}
.oo-ui-capsuleItemWidget.oo-ui-widget-disabled > .oo-ui-indicatorElement-indicator {
opacity: 0.2;
}
-.oo-ui-comboBoxWidget {
+.oo-ui-comboBoxInputWidget {
display: inline-block;
position: relative;
width: 100%;
max-width: 50em;
margin-right: 0.5em;
}
-.oo-ui-comboBoxWidget > .oo-ui-menuSelectWidget {
+.oo-ui-comboBoxInputWidget > .oo-ui-menuSelectWidget {
z-index: 1;
width: 100%;
}
-.oo-ui-comboBoxWidget > .oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
+.oo-ui-comboBoxInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
cursor: pointer;
}
-.oo-ui-comboBoxWidget:last-child {
+.oo-ui-comboBoxInputWidget-php input::-webkit-calendar-picker-indicator {
+ opacity: 0 !important;
+ position: absolute;
+ right: 0;
+ top: 0;
+ height: 2.5em;
+ width: 2.5em;
+ padding: 0;
+}
+.oo-ui-comboBoxInputWidget-php > .oo-ui-indicatorElement-indicator {
+ pointer-events: none;
+}
+.oo-ui-comboBoxInputWidget:last-child {
margin-right: 0;
}
-.oo-ui-comboBoxWidget .oo-ui-textInputWidget input,
-.oo-ui-comboBoxWidget .oo-ui-textInputWidget textarea {
+.oo-ui-comboBoxInputWidget input,
+.oo-ui-comboBoxInputWidget textarea {
height: 2.35em;
}
.oo-ui-searchWidget-query {
/*!
- * OOjs UI v0.13.1
+ * OOjs UI v0.13.2
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2015 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-11-03T21:42:20Z
+ * Date: 2015-11-10T23:32:59Z
*/
/**
* @class
/*!
- * OOjs UI v0.13.1
+ * OOjs UI v0.13.2
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2015 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-11-03T21:42:20Z
+ * Date: 2015-11-10T23:32:59Z
*/
( function ( OO ) {
* @cfg {jQuery} [$container=this.$element] The container element. The lookup menu is rendered beneath the specified element.
* @cfg {boolean} [allowSuggestionsWhenEmpty=false] Request and display a lookup menu when the text input is empty.
* By default, the lookup menu is not generated and displayed until the user begins to type.
+ * @cfg {boolean} [highlightFirst=true] Whether the first lookup result should be highlighted (so, that the user can
+ * take it over into the input with simply pressing return) automatically or not.
*/
OO.ui.mixin.LookupElement = function OoUiMixinLookupElement( config ) {
// Configuration initialization
- config = config || {};
+ config = $.extend( { highlightFirst: true }, config );
// Properties
this.$overlay = config.$overlay || this.$element;
this.lookupRequest = null;
this.lookupsDisabled = false;
this.lookupInputFocused = false;
+ this.lookupHighlightFirstItem = config.highlightFirst;
// Events
this.$input.on( {
};
/**
- * Highlight the first selectable item in the menu.
+ * Highlight the first selectable item in the menu, if configured.
*
* @private
* @chainable
*/
OO.ui.mixin.LookupElement.prototype.initializeLookupMenuSelection = function () {
- if ( !this.lookupMenu.getSelectedItem() ) {
+ if ( this.lookupHighlightFirstItem && !this.lookupMenu.getSelectedItem() ) {
this.lookupMenu.highlightItem( this.lookupMenu.getFirstSelectableItem() );
}
};
};
/**
- * CapsuleMultiSelectWidgets are something like a {@link OO.ui.ComboBoxWidget combo box widget}
+ * CapsuleMultiSelectWidgets are something like a {@link OO.ui.ComboBoxInputWidget combo box widget}
* that allows for selecting multiple values.
*
* For more information about menus and options, please see the [OOjs UI documentation on MediaWiki][1].
};
/**
- * ComboBoxWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value
+ * ComboBoxInputWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value
* can be entered manually) and a {@link OO.ui.MenuSelectWidget menu of options} (from which
* a value can be chosen instead). Users can choose options from the combo box in one of two ways:
*
* - by choosing a value from the menu. The value of the chosen option will then appear in the text
* input field.
*
+ * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
+ *
* For more information about menus and options, please see the [OOjs UI documentation on MediaWiki][1].
*
* @example
- * // Example: A ComboBoxWidget.
- * var comboBox = new OO.ui.ComboBoxWidget( {
- * label: 'ComboBoxWidget',
- * input: { value: 'Option One' },
+ * // Example: A ComboBoxInputWidget.
+ * var comboBox = new OO.ui.ComboBoxInputWidget( {
+ * label: 'ComboBoxInputWidget',
+ * value: 'Option 1',
* menu: {
* items: [
* new OO.ui.MenuOptionWidget( {
* [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
*
* @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.mixin.TabIndexedElement
+ * @extends OO.ui.TextInputWidget
*
* @constructor
* @param {Object} [config] Configuration options
+ * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`
* @cfg {Object} [menu] Configuration options to pass to the {@link OO.ui.FloatingMenuSelectWidget menu select widget}.
- * @cfg {Object} [input] Configuration options to pass to the {@link OO.ui.TextInputWidget text input widget}.
* @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful in cases where
* the expanded menu is larger than its containing `<div>`. The specified overlay layer is usually on top of the
* containing `<div>` and has a larger area. By default, the menu uses relative positioning.
*/
-OO.ui.ComboBoxWidget = function OoUiComboBoxWidget( config ) {
+OO.ui.ComboBoxInputWidget = function OoUiComboBoxInputWidget( config ) {
// Configuration initialization
- config = config || {};
+ config = $.extend( {
+ indicator: 'down'
+ }, config );
+ // For backwards-compatibility with ComboBoxWidget config
+ $.extend( config, config.input );
// Parent constructor
- OO.ui.ComboBoxWidget.parent.call( this, config );
-
- // Properties (must be set before TabIndexedElement constructor call)
- this.$indicator = this.$( '<span>' );
-
- // Mixin constructors
- OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$indicator } ) );
+ OO.ui.ComboBoxInputWidget.parent.call( this, config );
// Properties
this.$overlay = config.$overlay || this.$element;
- this.input = new OO.ui.TextInputWidget( $.extend(
- {
- indicator: 'down',
- $indicator: this.$indicator,
- disabled: this.isDisabled()
- },
- config.input
- ) );
- this.input.$input.eq( 0 ).attr( {
- role: 'combobox',
- 'aria-autocomplete': 'list'
- } );
this.menu = new OO.ui.FloatingMenuSelectWidget( $.extend(
{
widget: this,
- input: this.input,
- $container: this.input.$element,
+ input: this,
+ $container: this.$element,
disabled: this.isDisabled()
},
config.menu
) );
+ // For backwards-compatibility with ComboBoxWidget
+ this.input = this;
// Events
this.$indicator.on( {
- click: this.onClick.bind( this ),
- keypress: this.onKeyPress.bind( this )
+ click: this.onIndicatorClick.bind( this ),
+ keypress: this.onIndicatorKeyPress.bind( this )
} );
- this.input.connect( this, {
+ this.connect( this, {
change: 'onInputChange',
enter: 'onInputEnter'
} );
} );
// Initialization
- this.$element.addClass( 'oo-ui-comboBoxWidget' ).append( this.input.$element );
+ this.$input.attr( {
+ role: 'combobox',
+ 'aria-autocomplete': 'list'
+ } );
+ // Do not override options set via config.menu.items
+ if ( config.options !== undefined ) {
+ this.setOptions( config.options );
+ }
+ // Extra class for backwards-compatibility with ComboBoxWidget
+ this.$element.addClass( 'oo-ui-comboBoxInputWidget oo-ui-comboBoxWidget' );
this.$overlay.append( this.menu.$element );
this.onMenuItemsChange();
};
/* Setup */
-OO.inheritClass( OO.ui.ComboBoxWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.ComboBoxWidget, OO.ui.mixin.TabIndexedElement );
+OO.inheritClass( OO.ui.ComboBoxInputWidget, OO.ui.TextInputWidget );
/* Methods */
* Get the combobox's menu.
* @return {OO.ui.FloatingMenuSelectWidget} Menu widget
*/
-OO.ui.ComboBoxWidget.prototype.getMenu = function () {
+OO.ui.ComboBoxInputWidget.prototype.getMenu = function () {
return this.menu;
};
* Get the combobox's text input widget.
* @return {OO.ui.TextInputWidget} Text input widget
*/
-OO.ui.ComboBoxWidget.prototype.getInput = function () {
- return this.input;
+OO.ui.ComboBoxInputWidget.prototype.getInput = function () {
+ return this;
};
/**
* @private
* @param {string} value New value
*/
-OO.ui.ComboBoxWidget.prototype.onInputChange = function ( value ) {
+OO.ui.ComboBoxInputWidget.prototype.onInputChange = function ( value ) {
var match = this.menu.getItemFromData( value );
this.menu.selectItem( match );
* @private
* @param {jQuery.Event} e Mouse click event
*/
-OO.ui.ComboBoxWidget.prototype.onClick = function ( e ) {
+OO.ui.ComboBoxInputWidget.prototype.onIndicatorClick = function ( e ) {
if ( !this.isDisabled() && e.which === 1 ) {
this.menu.toggle();
- this.input.$input[ 0 ].focus();
+ this.$input[ 0 ].focus();
}
return false;
};
* @private
* @param {jQuery.Event} e Key press event
*/
-OO.ui.ComboBoxWidget.prototype.onKeyPress = function ( e ) {
+OO.ui.ComboBoxInputWidget.prototype.onIndicatorKeyPress = function ( e ) {
if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
this.menu.toggle();
- this.input.$input[ 0 ].focus();
+ this.$input[ 0 ].focus();
return false;
}
};
*
* @private
*/
-OO.ui.ComboBoxWidget.prototype.onInputEnter = function () {
+OO.ui.ComboBoxInputWidget.prototype.onInputEnter = function () {
if ( !this.isDisabled() ) {
this.menu.toggle( false );
}
* @private
* @param {OO.ui.OptionWidget} item Chosen item
*/
-OO.ui.ComboBoxWidget.prototype.onMenuChoose = function ( item ) {
- this.input.setValue( item.getData() );
+OO.ui.ComboBoxInputWidget.prototype.onMenuChoose = function ( item ) {
+ this.setValue( item.getData() );
};
/**
*
* @private
*/
-OO.ui.ComboBoxWidget.prototype.onMenuItemsChange = function () {
- var match = this.menu.getItemFromData( this.input.getValue() );
+OO.ui.ComboBoxInputWidget.prototype.onMenuItemsChange = function () {
+ var match = this.menu.getItemFromData( this.getValue() );
this.menu.selectItem( match );
if ( this.menu.getHighlightedItem() ) {
this.menu.highlightItem( match );
}
- this.$element.toggleClass( 'oo-ui-comboBoxWidget-empty', this.menu.isEmpty() );
+ this.$element.toggleClass( 'oo-ui-comboBoxInputWidget-empty', this.menu.isEmpty() );
};
/**
* @inheritdoc
*/
-OO.ui.ComboBoxWidget.prototype.setDisabled = function ( disabled ) {
+OO.ui.ComboBoxInputWidget.prototype.setDisabled = function ( disabled ) {
// Parent method
- OO.ui.ComboBoxWidget.parent.prototype.setDisabled.call( this, disabled );
+ OO.ui.ComboBoxInputWidget.parent.prototype.setDisabled.call( this, disabled );
- if ( this.input ) {
- this.input.setDisabled( this.isDisabled() );
- }
if ( this.menu ) {
this.menu.setDisabled( this.isDisabled() );
}
return this;
};
+/**
+ * Set the options available for this input.
+ *
+ * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`
+ * @chainable
+ */
+OO.ui.ComboBoxInputWidget.prototype.setOptions = function ( options ) {
+ this.getMenu()
+ .clearItems()
+ .addItems( options.map( function ( opt ) {
+ return new OO.ui.MenuOptionWidget( {
+ data: opt.data,
+ label: opt.label !== undefined ? opt.label : opt.data
+ } );
+ } ) );
+
+ return this;
+};
+
+/**
+ * @class
+ * @deprecated Use OO.ui.ComboBoxInputWidget instead.
+ */
+OO.ui.ComboBoxWidget = OO.ui.ComboBoxInputWidget;
+
/**
* LabelWidgets help identify the function of interface elements. Each LabelWidget can
* be configured with a `label` option that is set to a string, a label node, or a function:
/**
* MenuSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains options and
* is used together with OO.ui.MenuOptionWidget. It is designed be used as part of another widget.
- * See {@link OO.ui.DropdownWidget DropdownWidget}, {@link OO.ui.ComboBoxWidget ComboBoxWidget},
+ * See {@link OO.ui.DropdownWidget DropdownWidget}, {@link OO.ui.ComboBoxInputWidget ComboBoxInputWidget},
* and {@link OO.ui.mixin.LookupElement LookupElement} for examples of widgets that contain menus.
* MenuSelectWidgets themselves are not instantiated directly, rather subclassed
* and customized to be opened, closed, and displayed as needed.
* @constructor
* @param {Object} [config] Configuration options
* @cfg {OO.ui.TextInputWidget} [input] Text input used to implement option highlighting for menu items that match
- * the text the user types. This config is used by {@link OO.ui.ComboBoxWidget ComboBoxWidget}
+ * the text the user types. This config is used by {@link OO.ui.ComboBoxInputWidget ComboBoxInputWidget}
* and {@link OO.ui.mixin.LookupElement LookupElement}
* @cfg {jQuery} [$input] Text input used to implement option highlighting for menu items that match
* the text the user types. This config is used by {@link OO.ui.CapsuleMultiSelectWidget CapsuleMultiSelectWidget}
* The menu's position is automatically calculated and maintained when the menu
* is toggled or the window is resized.
*
- * See OO.ui.ComboBoxWidget for an example of a widget that uses this class.
+ * See OO.ui.ComboBoxInputWidget for an example of a widget that uses this class.
*
* @class
* @extends OO.ui.MenuSelectWidget
"ltr": "images/icons/find-ltr.svg",
"rtl": "images/icons/find-rtl.svg"
} },
- "insert": { "file": "images/icons/insert.svg" },
+ "insert": { "file": "images/icons/add.svg" },
"layout": { "file": {
"ltr": "images/icons/layout-ltr.svg",
"rtl": "images/icons/layout-rtl.svg"
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="add">
- <path id="plus" d="M13 8h-2v3H8v2h3v3h2v-3h3v-2h-3z"/>
+ <path id="plus" d="M13 6h-2v5H6v2h5v5h2v-5h5v-2h-5z"/>
</g>
</svg>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="insert">
- <path d="M13 5h-2v6H5v2h6v6h2v-6h6v-2h-6z" id="plus"/>
- </g>
-</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M16 14l2 2V5h-4v2h2zm0 2L9 9 7 7 6 6 5 5 2 2 1 3l2 2H2v14h4v-2H4V7h1l2 2v10h4v-2H9v-6l6 6h-1v2h3l4 4 1-1-4-4zm-5-9V5H7l2 2zm8-2v2h2v10h-2l2 2h2V5z"/>
+ <g id="noWikiText-rtl">
+ <path d="M15 13l2 2V5h-3v2h1zM3 3L2 4l1 1v14h3v-2H5V7l2 2v10h3v-2H9v-6l6 6h-1v2h3l3 3 1-1-3-3zm7 4V5H7l2 2zm8-2v2h1v10l2 2V5z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g484">
- <path d="M8 14l-2 2V5h4v2H8zm0 2l7-7 2-2 1-1 1-1 3-3 1 1-2 2h1v14h-4v-2h2V7h-1l-2 2v10h-4v-2h2v-6l-6 6h1v2H7l-4 4-1-1 4-4zm5-9V5h4l-2 2zM5 5v2H3v10h2l-2 2H1V5z" id="path486"/>
+ <g id="noWikiText-rtl">
+ <path d="M9 13l-2 2V5h3v2H9zM21 3l1 1-1 1v14h-3v-2h1V7l-2 2v10h-3v-2h1v-6l-6 6h1v2H7l-3 3-1-1 3-3zm-7 4V5h3l-2 2zM6 5v2H5v10l-2 2V5z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M23 5h-4v2h2v10h-2v2h4z"/>
- </g>
- <g>
- <path d="M18 5h-4v2h2v10h-2v2h4z"/>
- </g>
- <g>
- <path d="M2 5h4v2H4v10h2v2H2z"/>
- </g>
- <g>
- <path d="M7 5h4v2H9v10h2v2H7z"/>
+ <g id="wikiText">
+ <path id="opening-bracket-inner" d="M7 19h3v-2H9V7h1V5H7z"/>
+ <path id="closing-bracket-inner" d="M17 19h-3v-2h1V7h-1V5h3z"/>
+ <path id="closing-bracket-outer" d="M21 19h-3v-2h1V7h-1V5h3z"/>
+ <path id="opening-bracket-outer" d="M3 19h3v-2H5V7h1V5H3z"/>
</g>
</svg>
"ltr": "images/icons/find-ltr.svg",
"rtl": "images/icons/find-rtl.svg"
} },
- "insert": { "file": "images/icons/insert.svg" },
+ "insert": { "file": "images/icons/add.svg" },
"layout": { "file": {
"ltr": "images/icons/layout-ltr.svg",
"rtl": "images/icons/layout-rtl.svg"
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #00AF89 }</style>
<g id="add">
- <path id="plus" d="M13 8h-2v3H8v2h3v3h2v-3h3v-2h-3z"/>
+ <path id="plus" d="M13 6h-2v5H6v2h5v5h2v-5h5v-2h-5z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
<g id="add">
- <path id="plus" d="M13 8h-2v3H8v2h3v3h2v-3h3v-2h-3z"/>
+ <path id="plus" d="M13 6h-2v5H6v2h5v5h2v-5h5v-2h-5z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="add">
- <path id="plus" d="M13 8h-2v3H8v2h3v3h2v-3h3v-2h-3z"/>
+ <path id="plus" d="M13 6h-2v5H6v2h5v5h2v-5h5v-2h-5z"/>
</g>
</svg>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
- <g id="insert">
- <path d="M13 5h-2v6H5v2h6v6h2v-6h6v-2h-6z" id="plus"/>
- </g>
-</svg>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="insert">
- <path d="M13 5h-2v6H5v2h6v6h2v-6h6v-2h-6z" id="plus"/>
- </g>
-</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
<g id="menu">
- <path id="lines" d="M6 15.5h12c.6 0 1 .4 1 1v1c0 .6-.4 1-1 1H6c-.6 0-1-.4-1-1v-1c0-.6.4-1 1-1zm-1-4v1c0 .6.4 1 1 1h12c.6 0 1-.4 1-1v-1c0-.6-.4-1-1-1H6c-.6 0-1 .4-1 1zm0-5v1c0 .6.4 1 1 1h12c.6 0 1-.4 1-1v-1c0-.6-.4-1-1-1H6c-.6 0-1 .4-1 1z"/>
+ <path id="lines" d="M6 15h12c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H6c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1zm-1-4v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1H6c-.553 0-1 .447-1 1zm0-5v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1V6c0-.553-.447-1-1-1H6c-.553 0-1 .447-1 1z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="menu">
- <path id="lines" d="M6 15.5h12c.6 0 1 .4 1 1v1c0 .6-.4 1-1 1H6c-.6 0-1-.4-1-1v-1c0-.6.4-1 1-1zm-1-4v1c0 .6.4 1 1 1h12c.6 0 1-.4 1-1v-1c0-.6-.4-1-1-1H6c-.6 0-1 .4-1 1zm0-5v1c0 .6.4 1 1 1h12c.6 0 1-.4 1-1v-1c0-.6-.4-1-1-1H6c-.6 0-1 .4-1 1z"/>
+ <path id="lines" d="M6 15h12c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H6c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1zm-1-4v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1H6c-.553 0-1 .447-1 1zm0-5v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1V6c0-.553-.447-1-1-1H6c-.553 0-1 .447-1 1z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
- <g>
- <path d="M16 14l2 2V5h-4v2h2zm0 2L9 9 7 7 6 6 5 5 2 2 1 3l2 2H2v14h4v-2H4V7h1l2 2v10h4v-2H9v-6l6 6h-1v2h3l4 4 1-1-4-4zm-5-9V5H7l2 2zm8-2v2h2v10h-2l2 2h2V5z"/>
+ <g id="noWikiText-rtl">
+ <path d="M15 13l2 2V5h-3v2h1zM3 3L2 4l1 1v14h3v-2H5V7l2 2v10h3v-2H9v-6l6 6h-1v2h3l3 3 1-1-3-3zm7 4V5H7l2 2zm8-2v2h1v10l2 2V5z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M16 14l2 2V5h-4v2h2zm0 2L9 9 7 7 6 6 5 5 2 2 1 3l2 2H2v14h4v-2H4V7h1l2 2v10h4v-2H9v-6l6 6h-1v2h3l4 4 1-1-4-4zm-5-9V5H7l2 2zm8-2v2h2v10h-2l2 2h2V5z"/>
+ <g id="noWikiText-rtl">
+ <path d="M15 13l2 2V5h-3v2h1zM3 3L2 4l1 1v14h3v-2H5V7l2 2v10h3v-2H9v-6l6 6h-1v2h3l3 3 1-1-3-3zm7 4V5H7l2 2zm8-2v2h1v10l2 2V5z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
- <g id="g484">
- <path d="M8 14l-2 2V5h4v2H8zm0 2l7-7 2-2 1-1 1-1 3-3 1 1-2 2h1v14h-4v-2h2V7h-1l-2 2v10h-4v-2h2v-6l-6 6h1v2H7l-4 4-1-1 4-4zm5-9V5h4l-2 2zM5 5v2H3v10h2l-2 2H1V5z" id="path486"/>
+ <g id="noWikiText-rtl">
+ <path d="M9 13l-2 2V5h3v2H9zM21 3l1 1-1 1v14h-3v-2h1V7l-2 2v10h-3v-2h1v-6l-6 6h1v2H7l-3 3-1-1 3-3zm-7 4V5h3l-2 2zM6 5v2H5v10l-2 2V5z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g484">
- <path d="M8 14l-2 2V5h4v2H8zm0 2l7-7 2-2 1-1 1-1 3-3 1 1-2 2h1v14h-4v-2h2V7h-1l-2 2v10h-4v-2h2v-6l-6 6h1v2H7l-4 4-1-1 4-4zm5-9V5h4l-2 2zM5 5v2H3v10h2l-2 2H1V5z" id="path486"/>
+ <g id="noWikiText-rtl">
+ <path d="M9 13l-2 2V5h3v2H9zM21 3l1 1-1 1v14h-3v-2h1V7l-2 2v10h-3v-2h1v-6l-6 6h1v2H7l-3 3-1-1 3-3zm-7 4V5h3l-2 2zM6 5v2H5v10l-2 2V5z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
- <g>
- <path d="M23 5h-4v2h2v10h-2v2h4z"/>
- </g>
- <g>
- <path d="M18 5h-4v2h2v10h-2v2h4z"/>
- </g>
- <g>
- <path d="M2 5h4v2H4v10h2v2H2z"/>
- </g>
- <g>
- <path d="M7 5h4v2H9v10h2v2H7z"/>
+ <g id="wikiText">
+ <path id="opening-bracket-inner" d="M7 19h3v-2H9V7h1V5H7z"/>
+ <path id="closing-bracket-inner" d="M17 19h-3v-2h1V7h-1V5h3z"/>
+ <path id="closing-bracket-outer" d="M21 19h-3v-2h1V7h-1V5h3z"/>
+ <path id="opening-bracket-outer" d="M3 19h3v-2H5V7h1V5H3z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M23 5h-4v2h2v10h-2v2h4z"/>
- </g>
- <g>
- <path d="M18 5h-4v2h2v10h-2v2h4z"/>
- </g>
- <g>
- <path d="M2 5h4v2H4v10h2v2H2z"/>
- </g>
- <g>
- <path d="M7 5h4v2H9v10h2v2H7z"/>
+ <g id="wikiText">
+ <path id="opening-bracket-inner" d="M7 19h3v-2H9V7h1V5H7z"/>
+ <path id="closing-bracket-inner" d="M17 19h-3v-2h1V7h-1V5h3z"/>
+ <path id="closing-bracket-outer" d="M21 19h-3v-2h1V7h-1V5h3z"/>
+ <path id="opening-bracket-outer" d="M3 19h3v-2H5V7h1V5H3z"/>
</g>
</svg>
-/**
+/*!
* HTML5 placeholder emulation for jQuery plugin
*
* This will automatically use the HTML5 placeholder attribute if supported, or emulate this behavior if not.
* @version 2.1.0
* @license MIT
*/
+
( function ( $ ) {
var isInputSupported = 'placeholder' in document.createElement( 'input' ),
-/**
+/*!
* TableSorter for MediaWiki
*
* Written 2011 Leo Koppelkamm
* and mw.language.months.
*
* Uses 'tableSorterCollation' in mw.config (if available)
- */
-/**
*
- * @description Create a sortable table with multi-column sorting capabilities
+ * Create a sortable table with multi-column sorting capabilities
*
- * @example $( 'table' ).tablesorter();
- * @desc Create a simple tablesorter interface.
+ * // Create a simple tablesorter interface
+ * $( 'table' ).tablesorter();
*
- * @example $( 'table' ).tablesorter( { sortList: [ { 0: 'desc' }, { 1: 'asc' } ] } );
- * @desc Create a tablesorter interface initially sorting on the first and second column.
+ * // Create a tablesorter interface, initially sorting on the first and second column
+ * $( 'table' ).tablesorter( { sortList: [ { 0: 'desc' }, { 1: 'asc' } ] } );
*
- * @option String cssHeader ( optional ) A string of the class name to be appended
- * to sortable tr elements in the thead of the table. Default value:
- * "header"
+ * @param {string} [cssHeader="header"] A string of the class name to be appended to sortable
+ * tr elements in the thead of the table.
*
- * @option String cssAsc ( optional ) A string of the class name to be appended to
- * sortable tr elements in the thead on a ascending sort. Default value:
- * "headerSortUp"
+ * @param {string} [cssAsc="headerSortUp"] A string of the class name to be appended to
+ * sortable tr elements in the thead on a ascending sort.
*
- * @option String cssDesc ( optional ) A string of the class name to be appended
- * to sortable tr elements in the thead on a descending sort. Default
- * value: "headerSortDown"
+ * @param {string} [cssDesc="headerSortDown"] A string of the class name to be appended to
+ * sortable tr elements in the thead on a descending sort.
*
- * @option String sortMultisortKey ( optional ) A string of the multi-column sort
- * key. Default value: "shiftKey"
+ * @param {string} [sortMultisortKey="shiftKey"] A string of the multi-column sort key.
*
- * @option Boolean cancelSelection ( optional ) Boolean flag indicating if
- * tablesorter should cancel selection of the table headers text.
- * Default value: true
+ * @param {boolean} [cancelSelection=true] Boolean flag indicating iftablesorter should cancel
+ * selection of the table headers text.
*
- * @option Array sortList ( optional ) An array containing objects specifying sorting.
- * By passing more than one object, multi-sorting will be applied. Object structure:
+ * @param {Array} [sortList] An array containing objects specifying sorting. By passing more
+ * than one object, multi-sorting will be applied. Object structure:
* { <Integer column index>: <String 'asc' or 'desc'> }
- * Default value: []
*
* @event sortEnd.tablesorter: Triggered as soon as any sorting has been applied.
*
- * @type jQuery
- *
- * @name tablesorter
- *
- * @cat Plugins/Tablesorter
- *
* @author Christian Bach/christian.bach@polyester.se
*/
-
( function ( $, mw ) {
var ts,
parsers = [];
* Inserts text at the beginning and end of a text selection, optionally
* inserting text at the caret when selection is empty.
*
- * @fixme document the options parameters
+ * FIXME document the options parameters
*/
encapsulateSelection: function ( options ) {
return this.each( function () {
*
* Will focus the textarea in some browsers (IE/Opera)
*
- * @fixme document the options parameters
+ * FIXME document the options parameters
*/
getCaretPosition: function ( options ) {
function getCaret( e ) {
return getCaret( this.get( 0 ) );
},
/**
- * @fixme document the options parameters
+ * FIXME document the options parameters
*/
setSelection: function ( options ) {
return this.each( function () {
* @param {boolean} options Whether to force a scroll even if the caret position
* is already visible. Defaults to false
*
- * @fixme document the options parameters (function body suggests options.force is a boolean, not options itself)
+ * FIXME document the options parameters (function body suggests options.force is a boolean, not options itself)
*/
scrollToCaretPosition: function ( options ) {
function getLineLength( e ) {
vertical-align: middle;
}
-/* math */
-span.texhtml {
- font-family: serif;
-}
-
/**
* Links
*/
font-style: italic;
}
-/* Math */
-.texvc {
- direction: ltr;
- unicode-bidi: embed;
-}
-
-img.tex {
- vertical-align: middle;
-}
-
-span.texhtml {
- font-family: serif;
-}
-
/**
* Add a bit of margin space between the preview and the toolbar.
* This replaces the ugly <p><br /></p> we used to insert into the page source
* internally and for dates accepted by #setDate and returned by #getDate.
*
* @private
- * @returns {string} Format
+ * @return {string} Format
*/
mw.widgets.CalendarWidget.prototype.getDateFormat = function () {
return {
* Get the date precision this calendar uses, 'day' or 'month'.
*
* @private
- * @returns {string} Precision, 'day' or 'month'
+ * @return {string} Precision, 'day' or 'month'
*/
mw.widgets.CalendarWidget.prototype.getPrecision = function () {
return this.precision;
* Get list of possible display layers.
*
* @private
- * @returns {string[]} Layers
+ * @return {string[]} Layers
*/
mw.widgets.CalendarWidget.prototype.getDisplayLayers = function () {
return [ 'month', 'year', 'duodecade' ].slice( this.precision === 'month' ? 1 : 0 );
* Get current date, in the format 'YYYY-MM-DD' or 'YYYY-MM', depending on precision. Digits will
* not be localised.
*
- * @returns {string|null} Date string
+ * @return {string|null} Date string
*/
mw.widgets.CalendarWidget.prototype.getDate = function () {
return this.date;
* @private
* @param {string} date Date string, to be valid, must be in 'YYYY-MM-DD' or 'YYYY-MM' format or
* (unless the field is required) empty
- * @returns {boolean}
+ * @return {boolean}
*/
mw.widgets.DateInputWidget.prototype.validateDate = function ( date ) {
var isValid;
/**
* @private
* @param {string} date Date string, to be valid, must be in 'YYYY-MM-DD' or 'YYYY-MM' format
- * @returns {boolean}
+ * @return {boolean}
*/
mw.widgets.DateInputWidget.prototype.isValidDate = function ( date ) {
// "Half-strict mode": for example, for the format 'YYYY-MM-DD', 2015-1-3 instead of 2015-01-03
* @private
* @param {string} date Date string, to be valid, must be empty (no date selected) or in
* 'YYYY-MM-DD' or 'YYYY-MM' format to be valid
- * @returns {boolean}
+ * @return {boolean}
*/
mw.widgets.DateInputWidget.prototype.isInRange = function ( date ) {
var momentDate = moment( date, 'YYYY-MM-DD' ),
mw.widgets.TitleSearchWidget.prototype.onQueryChange = function () {
var widget = this;
- this.getSuggestionsPromise().done( function ( response ) {
+ if ( this.currentRequest ) {
+ this.currentRequest.abort();
+ }
+
+ this.currentRequest = this.getSuggestionsPromise();
+ this.currentRequest.done( function ( response ) {
// Parent method
mw.widgets.TitleSearchWidget.parent.prototype.onQueryChange.call( widget );
widget.results.addItems( widget.getOptionsFromData( response.query || {} ) );
+
+ widget.currentRequest = false;
} );
};
* Get option widgets from the server response
*
* @param {Object} data Query result
- * @returns {OO.ui.OptionWidget[]} Menu items
+ * @return {OO.ui.OptionWidget[]} Menu items
*/
mw.widgets.TitleWidget.prototype.getOptionsFromData = function ( data ) {
var i, len, index, pageExists, pageExistsExact, suggestionPage, page, redirect, redirects,
* Get title object corresponding to given value, or #getQueryValue if not given.
*
* @param {string} [value] Value to get a title for
- * @returns {mw.Title|null} Title object, or null if value is invalid
+ * @return {mw.Title|null} Title object, or null if value is invalid
*/
mw.widgets.TitleWidget.prototype.getTitle = function ( value ) {
var title = value !== undefined ? value : this.getQueryValue(),
* Get list of menu items from a server response.
*
* @param {Object} data Query result
- * @returns {OO.ui.MenuOptionWidget[]} Menu items
+ * @return {OO.ui.MenuOptionWidget[]} Menu items
*/
mw.widgets.UserInputWidget.prototype.getLookupMenuOptionsFromData = function ( data ) {
var len, i, user,
*
* @protected
* @fires fileSaved
- * @returns {jQuery.Promise} Rejects the promise with an
+ * @return {jQuery.Promise} Rejects the promise with an
* {@link OO.ui.Error error}, or resolves if the upload was successful.
*/
mw.Upload.BookletLayout.prototype.saveFile = function () {
* state and state details.
*
* @protected
- * @returns {OO.ui.Error} Error to display for given state and details.
+ * @return {OO.ui.Error} Error to display for given state and details.
*/
mw.Upload.BookletLayout.prototype.getErrorMessageForStateDetails = function () {
var message,
*
* @protected
* @fires selectFile
- * @returns {OO.ui.FormLayout}
+ * @return {OO.ui.FormLayout}
*/
mw.Upload.BookletLayout.prototype.renderUploadForm = function () {
var fieldset;
* property.
*
* @protected
- * @returns {OO.ui.FormLayout}
+ * @return {OO.ui.FormLayout}
*/
mw.Upload.BookletLayout.prototype.renderInfoForm = function () {
var fieldset;
* sets the {@link #insertForm insertForm} property.
*
* @protected
- * @returns {OO.ui.FormLayout}
+ * @return {OO.ui.FormLayout}
*/
mw.Upload.BookletLayout.prototype.renderInsertForm = function () {
var fieldset;
* {@link #uploadForm upload form}.
*
* @protected
- * @returns {File|null}
+ * @return {File|null}
*/
mw.Upload.BookletLayout.prototype.getFile = function () {
return this.selectFileWidget.getValue();
* {@link #infoForm information form}.
*
* @protected
- * @returns {string}
+ * @return {string}
*/
mw.Upload.BookletLayout.prototype.getFilename = function () {
return this.filenameWidget.getValue();
* {@link #infoForm information form}.
*
* @protected
- * @returns {string}
+ * @return {string}
*/
mw.Upload.BookletLayout.prototype.getText = function () {
return this.descriptionWidget.getValue();
this.uploadBooklet.clear();
}, this );
};
-
}( jQuery, mediaWiki ) );
if ( val === undefined || val === null || val === '' ) {
return '';
}
- /* jshint latedef:false */
+
return pre + ( raw ? val : mw.Uri.encode( val ) ) + post;
- /* jshint latedef:true */
}
/**
}() );
/**
- * @class mw.Uri
- * @constructor
- *
* Construct a new URI object. Throws error if arguments are illegal/impossible, or
* otherwise don't parse.
*
+ * @class mw.Uri
+ * @constructor
* @param {Object|string} [uri] URI string, or an Object with appropriate properties (especially
* another URI object to clone). Object must have non-blank `protocol`, `host`, and `path`
* properties. If omitted (or set to `undefined`, `null` or empty string), then an object
* @param {boolean} [options.overrideKeys=false] Whether to let duplicate query parameters
* override each other (`true`) or automagically convert them to an array (`false`).
*/
- /* jshint latedef:false */
function Uri( uri, options ) {
var prop,
defaultUri = getDefaultUri();
* that the user will be assigned to that bucket
* @param {string} token A token that uniquely identifies the user for the
* duration of the experiment
- * @returns {string} The bucket
+ * @return {string} The bucket
*/
getBucket: function ( experiment, token ) {
var buckets = experiment.buckets,
/**
* Get the bug report link
*
- * @returns {string} Link to the external bug report form
+ * @return {string} Link to the external bug report form
*/
mw.Feedback.Dialog.prototype.getBugReportLink = function () {
return this.bugReportLink;
/* HTMLForm styles */
table.mw-htmlform-nolabel td.mw-label {
- width: 1px !important;
+ display: none;
}
.mw-htmlform-invalid-input td.mw-input input {
* The underscore in the name is to avoid a bug <https://github.com/senchalabs/jsduck/issues/304>.
* It is not part of the actual class name.
*
+ * The constructor is not publicly accessible; use mw.notification#notify instead.
+ * This does not insert anything into the document (see #start).
+ *
* @class mw.Notification_
* @alternateClassName mw.Notification
- *
- * @constructor The constructor is not publicly accessible; use mw.notification#notify instead.
- * This does not insert anything into the document (see #start).
+ * @constructor
* @private
*/
function Notification( message, options ) {
--- /dev/null
+/*!
+ * An interface for scheduling background tasks.
+ *
+ * Loosely based on https://w3c.github.io/requestidlecallback/
+ */
+( function ( mw, $ ) {
+ var tasks = [],
+ maxIdleDuration = 50,
+ timeout = null;
+
+ function schedule( trigger ) {
+ clearTimeout( timeout );
+ timeout = setTimeout( trigger, 700 );
+ }
+
+ function triggerIdle() {
+ var elapsed,
+ start = mw.now();
+
+ while ( tasks.length ) {
+ elapsed = mw.now() - start;
+ if ( elapsed < maxIdleDuration ) {
+ tasks.shift().callback();
+ } else {
+ // Idle moment expired, try again later
+ schedule( triggerIdle );
+ break;
+ }
+ }
+ }
+
+ mw.requestIdleCallbackInternal = function ( callback ) {
+ var task = { callback: callback };
+ tasks.push( task );
+
+ $( function () { schedule( triggerIdle ); } );
+ };
+
+ /**
+ * Schedule a deferred task to run in the background.
+ *
+ * @member mw
+ * @param {Function} callback
+ */
+ mw.requestIdleCallback = window.requestIdleCallback
+ ? function ( callback ) {
+ window.requestIdleCallback( callback );
+ }
+ : mw.requestIdleCallbackInternal;
+}( mediaWiki, jQuery ) );
# Plus any combination of these:
#
# cat add category links
-# (ignored by Parsoid, since it emits <link>s)
# ill add inter-language links
-# (ignored by Parsoid, since it emits <links>s)
+# (ignored by Parsoid, since it emits <link>s)
# subpage enable subpages (disabled by default)
# noxml don't check for XML well-formedness
# title=[[XXX]] run test using article title XXX
<span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":" [[Category:foo]]"}},"i":0}}]}'> </span><link rel="mw:PageProp/Category" href="./Category:Foo" about="#mwt1"> <!-- No pre-wrapping -->
!! end
-## We used to, but no longer wt2wt this test since the default serializer
-## will normalize all categories to serialize on their own line.
-## This wikitext usage is going to be fairly uncommon in production and
-## selser will take care of preserving formatting in those scenarios.
!! test
7b. Indent-pre and category links
!! options
-parsoid=wt2html
+parsoid=wt2html,wt2wt
!! wikitext
[[Category:foo]] a
[[Category:foo]] {{echo|b}}
-!! html/parsoid
+!! html
<pre><link rel="mw:PageProp/Category" href="./Category:Foo"> a
<link rel="mw:PageProp/Category" href="./Category:Foo"> <span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b"}},"i":0}}]}'>b</span></pre>
!! end
!! html
!! end
-## We used to, but no longer wt2wt this test since the default serializer
-## will normalize the include directives to serialize on their own line.
-## Selser will take care of preserving formatting in scenarios where they
-## intermingled with other wikitext.
!! test
Includes and comments at SOL
-!! options
-parsoid=wt2html,html2html
!! wikitext
<!-- comment --><noinclude><!-- comment --></noinclude><!-- comment -->== hu ==
</tbody></table>
!!end
-## We used to, but no longer wt2wt this test since the default serializer
-## will normalize the include directives to serialize on their own line.
-## Selser will take care of preserving formatting in scenarios where they
-## intermingled with other wikitext.
!!test
2. Table tag in SOL posn. should get reparsed correctly with valid TSR
!!options
-parsoid=wt2html
+parsoid=wt2html,wt2wt
!!wikitext
<includeonly>a</includeonly>{| {{{b}}}
|c
[[Category:Foo (bar)|Foo]]
!! end
-## We used to, but no longer wt2wt this test since the default serializer
-## will normalize all categories to serialize on their own line.
-## This wikitext usage is going to be fairly uncommon in production and
-## selser will take care of preserving formatting in those scenarios.
!! test
Category with link tail
!! options
cat
pst
-parsoid=wt2html
!! wikitext
123[[Category:Foo]]456
-!! html/php
+!! html
123[[Category:Foo]]456
-!! html/parsoid
-<p>123<link rel="mw:PageProp/Category" href="Category:Foo"/>456</p>
!! end
!! test
[[Category:{{echo|Foo}}|{{echo|Bar}}]]
!! end
-## We used to, but no longer wt2wt this test since the default serializer
-## will normalize all categories to serialize on their own line.
-## This wikitext usage is going to be fairly uncommon in production and
-## selser will take care of preserving formatting in those scenarios.
!! test
Category / paragraph interactions
-!! options
-parsoid=wt2html
!! wikitext
Foo [[Category:Baz]] Bar
[[Category:Baz]]
{{echo|[[Category:Baz]]}}
[[Category:Baz]]
-!! html/php
+!! html
<p>Foo Bar
</p><p>Foo
Bar
</p><p>Foo
Bar
</p>
-!! html/parsoid
-<p>Foo <link rel="mw:PageProp/Category" href="Category:Baz"/> Bar</p>
-<p>Foo <link rel="mw:PageProp/Category" href="Category:Baz"/> Bar</p>
-<p>Foo <link rel="mw:PageProp/Category" href="Category:Baz"/> Bar</p>
-<p>Foo <link rel="mw:PageProp/Category" href="Category:Baz"/> Bar</p>
-<p>Foo <link rel="mw:PageProp/Category" href="Category:Baz"/> <link rel="mw:PageProp/Category" href="Category:Baz"/> <link rel="mw:PageProp/Category" href="Category:Baz"/> Bar <link rel="mw:PageProp/Category" href="Category:Baz"/> <link rel="mw:PageProp/Category" href="Category:Baz"/> <link rel="mw:PageProp/Category" href="Category:Baz"/> <link rel="mw:PageProp/Category" href="Category:Baz"/> <link rel="mw:PageProp/Category" href="Category:Baz" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[[Category:Baz]]"}},"i":0}}]}'/></p>
-<link rel="mw:PageProp/Category" href="Category:Baz"/>
!! end
-## We used to, but no longer wt2wt this test since the default serializer
-## will normalize all categories to serialize on their own line.
-## This wikitext usage is going to be fairly uncommon in production and
-## selser will take care of preserving formatting in those scenarios.
-##
## The whitespace on the empty line is part of the test. Please do not delete
!! test
1. Categories and newlines: All preceding newlines should be suppressed (courtesy bug 87)
!! options
-parsoid=wt2html
+parsoid=wt2html,wt2wt
!! wikitext
This
[[Category:Foo]] and this should be part of same paragraph (not an indent-pre)
{{echo|[[Category:Foo]] and so should this!}}
-!! html/php
+!! html
<p>This and this should be part of same paragraph (not an indent-pre) and so should this!
</p>
!! html/parsoid
<link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid='{"stx":"simple","a":{"href":"./Category:Foo"},"sa":{"href":"Category:Foo"}}'/>
!! end
-## We used to, but no longer wt2wt this test since the default serializer
-## will normalize all categories to serialize on their own line.
-## This wikitext usage is going to be fairly uncommon in production and
-## selser will take care of preserving formatting in those scenarios.
!! test
6. Categories and newlines: migrateTrailingCategories dom pass should not migrate categories not preceded by newlines
-!! options
-parsoid=wt2html
!! wikitext
* a [[Category:Foo]]
!! html/parsoid
* {{echo|a
[[Category:Foo]]}}
!! html/parsoid
-<ul><li> <span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n[[Category:Foo]]"}},"i":0}}]}'>a</span><span about="#mwt1">
+<ul><li> <span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n[[Category:Foo]]"}},"i":0}}]}'>a
</span><link rel="mw:PageProp/Category" href="./Category:Foo" about="#mwt1" data-parsoid='{"stx":"simple","a":{"href":"./Category:Foo"},"sa":{"href":"Category:Foo"}}'/></li></ul>
!! end
</p>
!! end
-# We used to, but no longer wt2wt this test since the default serializer
-# will normalize all categories to serialize on their own line.
-# This wikitext usage is going to be fairly uncommon in production and
-# selser will take care of preventing whitespace insertion if this
-# occurs in an article.
-#
-# html2html disabled for the same reason (whitespace insertion between
-# x and y).
-#
-# html2wt disabled because it localizes the "Category" namespace.
+# html2wt localizes the "Category" namespace.
+# XXX the <link> element needs an empty data-parsoid attribute, or
+# else the html2html test fails because spaces are inserted.
!! test
Link prefix/suffixes aren't applied to category links
!! options
-parsoid=wt2html
+parsoid=wt2html,wt2wt,html2html
language=is
!! wikitext
x[[Category:Foo]]y
!! wikitext
{{Special:Prefixindex/Xyzzyx}}
!! html
-<div class="mw-prefixindex-body"><ul class="mw-prefixindex-list"><li> <a href="/wiki/Xyzzyx" title="Xyzzyx">Xyzzyx</a> </li>
-</ul></div>
+<ul class="mw-prefixindex-list"><li><a href="/wiki/Xyzzyx" title="Xyzzyx">Xyzzyx</a></li>
+</ul>
!! end
{{Special:Prefixindex/Xyzzyx}}
{{Special:Prefixindex/Xyzzyx}}
!! html
-<div class="mw-prefixindex-body"><ul class="mw-prefixindex-list"><li> <a href="/wiki/Xyzzyx" title="Xyzzyx">Xyzzyx</a> </li>
-</ul></div>
-<div class="mw-prefixindex-body"><ul class="mw-prefixindex-list"><li> <a href="/wiki/Xyzzyx" title="Xyzzyx">Xyzzyx</a> </li>
-</ul></div>
+<ul class="mw-prefixindex-list"><li><a href="/wiki/Xyzzyx" title="Xyzzyx">Xyzzyx</a></li>
+</ul>
+<ul class="mw-prefixindex-list"><li><a href="/wiki/Xyzzyx" title="Xyzzyx">Xyzzyx</a></li>
+</ul>
!! end
blah
!! endarticle
-## We used to, but no longer wt2wt this test since the default serializer
-## will normalize all categories to serialize on their own line.
-## This wikitext usage is going to be fairly uncommon in production and
-## selser will take care of preserving formatting in those scenarios.
!! test
Don't convert blue categorylinks to another variant (bug 33210)
!! options
-cat
-language=zh
-parsoid=wt2html
+language=zh cat
!! wikitext
[[A]][[Category:分类]]
-!! html/php
+!! html
<a href="/wiki/Category:%E5%88%86%E7%B1%BB" title="Category:分类">分类</a>
-!! html/parsoid
-<p><a rel="mw:WikiLink" href="A" title="A">A</a></p>
-<link rel="mw:PageProp/Category" href="Category:分类"/>
!! end
+
!! test
Stripping -{}- tags (language variants)
!! options
<p>this is not a link: http://example.com
</p>
!! wikitext
-<nowiki>this is not a link: http://example.com</nowiki>
+this is not a link: <nowiki>http://example.com</nowiki>
!! end
!! test
__TOC__ foo
-__TOC__
- bar
+__TOC__ bar
!! end
#### --------------- HTML tags ---------------
!! html/parsoid
<p>http://example.com is not a link.</p>
!! wikitext
-<nowiki>http://example.com is not a link.</nowiki>
+<nowiki>http://example.com</nowiki> is not a link.
!! end
!! test
!! html/parsoid
<p><a rel="mw:ExtLink" href="http://example.com">http://example.com</a> http://example.com is not a link.</p>
!! wikitext
-http://example.com<nowiki> http://example.com is not a link.</nowiki>
+http://example.com <nowiki>http://example.com</nowiki> is not a link.
!! end
!! test
# Tests spec'ing wikitext serialization norms |
# --------------------------------------------
-!! test
-1. Categories should always be serialized on their own line
-!! options
-parsoid=html2wt
-!! html/parsoid
-foo<link rel="mw:PageProp/Category" href="./Category:Foo">bar
-!! wikitext
-foo
-[[Category:Foo]]
-bar
-!! end
-
-!! test
-2. Categories that are part of templates should not introduce a line break
-!! wikitext
-foo {{echo|<span>bar</span> [[Category:baz]]}} bar
-!! html/parsoid
-<p>foo <span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<span>bar</span> [[Category:baz]]"}},"i":0}}]}'>bar</span><span about="#mwt1"> </span><link rel="mw:PageProp/Category" href="./Category:Baz" about="#mwt1" data-parsoid='{"stx":"simple","a":{"href":"./Category:Baz"},"sa":{"href":"Category:baz"}}'/> bar</p>
-!! end
-
!! test
Lists: Add space after bullets
!! options
);
}
+ function testMasterPos() {
+ $pos1 = new MySQLMasterPos( 'db1034-bin.000976', '843431247' );
+ $pos2 = new MySQLMasterPos( 'db1034-bin.000976', '843431248' );
+
+ $this->assertTrue( $pos1->hasReached( $pos1 ) );
+ $this->assertTrue( $pos2->hasReached( $pos2 ) );
+ $this->assertTrue( $pos2->hasReached( $pos1 ) );
+ $this->assertFalse( $pos1->hasReached( $pos2 ) );
+ }
}
$queue->flushCaches();
if ( $recycles ) {
$this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
- } else {
- $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
}
$job2 = $queue->pop();
$queue->flushCaches();
if ( $recycles ) {
$this->assertEquals( 2, $queue->getAcquiredCount(), "Active job count ($desc)" );
- } else {
- $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
}
$queue->ack( $job1 );
$queue->flushCaches();
if ( $recycles ) {
$this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
- } else {
- $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
}
$queue->ack( $job2 );
$this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
if ( $recycles ) {
$this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
- } else {
- $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
}
$queue->ack( $job1 );
$this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
}
+ /**
+ * @dataProvider provider_queueLists
+ * @covers JobQueue
+ */
+ public function testDeduplicationWhileClaimed( $queue, $recycles, $desc ) {
+ $queue = $this->$queue;
+ if ( !$queue ) {
+ $this->markTestSkipped( $desc );
+ }
+
+ $job = $this->newDedupedJob();
+ $queue->push( $job );
+
+ // De-duplication does not apply to already-claimed jobs
+ $j = $queue->pop();
+ $queue->push( $job );
+ $queue->ack( $j );
+
+ $j = $queue->pop();
+ // Make sure ack() of the twin did not delete the sibling data
+ $this->assertType( 'NullJob', $j );
+ }
+
/**
* @dataProvider provider_queueLists
* @covers JobQueue
'tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js',
'tests/qunit/suites/resources/jquery/jquery.textSelection.test.js',
'tests/qunit/data/mediawiki.jqueryMsg.data.js',
+ 'tests/qunit/suites/resources/mediawiki/mediawiki.requestIdleCallback.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.errorLogger.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js',
--- /dev/null
+( function ( mw ) {
+ QUnit.module( 'mediawiki.requestIdleCallback', QUnit.newMwEnvironment( {
+ setup: function () {
+ var time = mw.now(),
+ clock = this.clock = this.sandbox.useFakeTimers();
+
+ this.tick = function ( forward ) {
+ time += forward;
+ clock.tick( forward );
+ };
+ this.sandbox.stub( mw, 'now', function () {
+ return time;
+ } );
+
+ // Don't test the native version (if available)
+ this.mwRIC = mw.requestIdleCallback;
+ mw.requestIdleCallback = mw.requestIdleCallbackInternal;
+ },
+ teardown: function () {
+ mw.requestIdleCallback = this.mwRIC;
+ }
+ } ) );
+
+ // Basic scheduling of callbacks
+ QUnit.test( 'callback', 3, function ( assert ) {
+ var sequence,
+ tick = this.tick;
+
+ mw.requestIdleCallback( function () {
+ sequence.push( 'x' );
+ tick( 30 );
+ } );
+ mw.requestIdleCallback( function () {
+ tick( 5 );
+ sequence.push( 'y' );
+ tick( 30 );
+ } );
+ // Task Z is not run in the first sequence because the
+ // first two tasks consumed the available 50ms budget.
+ mw.requestIdleCallback( function () {
+ sequence.push( 'z' );
+ tick( 30 );
+ } );
+
+ sequence = [];
+ tick( 1000 );
+ assert.deepEqual( sequence, [ 'x', 'y' ] );
+
+ sequence = [];
+ tick( 1000 );
+ assert.deepEqual( sequence, [ 'z' ] );
+
+ sequence = [];
+ tick( 1000 );
+ assert.deepEqual( sequence, [] );
+ } );
+
+ // Schedule new callbacks within a callback that tick
+ // the clock. If the budget is exceeded, the newly scheduled
+ // task is delayed until the next idle period.
+ QUnit.test( 'nest-tick', 3, function ( assert ) {
+ var sequence,
+ tick = this.tick;
+
+ mw.requestIdleCallback( function () {
+ sequence.push( 'x' );
+ tick( 30 );
+ } );
+ // Task Y is a task that schedules another task.
+ mw.requestIdleCallback( function () {
+ function other() {
+ sequence.push( 'y' );
+ tick( 35 );
+ }
+ mw.requestIdleCallback( other );
+ } );
+ mw.requestIdleCallback( function () {
+ sequence.push( 'z' );
+ tick( 30 );
+ } );
+
+ sequence = [];
+ tick( 1000 );
+ assert.deepEqual( sequence, [ 'x', 'z' ] );
+
+ sequence = [];
+ tick( 1000 );
+ assert.deepEqual( sequence, [ 'y' ] );
+
+ sequence = [];
+ tick( 1000 );
+ assert.deepEqual( sequence, [] );
+ } );
+
+ // Schedule new callbacks within a callback that run quickly.
+ // Note how the newly scheduled task gets to run as part of the
+ // current idle period (budget allowing).
+ QUnit.test( 'nest-quick', 2, function ( assert ) {
+ var sequence,
+ tick = this.tick;
+
+ mw.requestIdleCallback( function () {
+ sequence.push( 'x' );
+ mw.requestIdleCallback( function () {
+ sequence.push( 'x-expand' );
+ } );
+ } );
+ mw.requestIdleCallback( function () {
+ sequence.push( 'y' );
+ } );
+
+ sequence = [];
+ tick( 1000 );
+ assert.deepEqual( sequence, [ 'x', 'y', 'x-expand' ] );
+
+ sequence = [];
+ tick( 1000 );
+ assert.deepEqual( sequence, [] );
+ } );
+
+}( mediaWiki ) );