"OO": false
},
"rules": {
- "max-len": 0
+ "quote-props": [ "error", "as-needed" ],
+ "max-len": "off",
+ "jquery/no-global-selector": "off"
}
}
Étienne Beaulé <beauleetienne0@gmail.com>
Željko Filipin <zeljko.filipin@gmail.com>
Željko Filipin <zeljko.filipin@gmail.com> <zfilipin@wikimedia.org>
+星耀晨曦 <razesoldier@outlook.com>
+星耀晨曦 <razesoldier@outlook.com> <liguangjie4399@hotmail.com>
* rahul21
* Raimond Spekking
* Ramunas Geciauskas
-* RazeSoldier
* Remember the dot
* René Kijewski
* Reza
* The PasswordPolicy 'PasswordCannotBePopular' has been deprecated. To
follow best practices, it is reccommended to use 'PasswordNotInLargeBlacklist'
instead which blacklists 100,000 commonly used passwords.
+* (T208862) Action::requiresUnblock() is now called from
+ Title::getUserPermissionsErrors() and Title::userCan(). Previously, the method
+ was only called in Action::checkCanExecute(). Actions should ensure that their
+ requiresUnblock() returns the proper result (the default is `true`).
* …
=== Other changes in 1.33 ===
* prohibited from editing any page on the site (other than their own talk
* page).
*
+ * @since 1.33
* @param null|bool $x
* @return bool
*/
/**
* Get block information used in different block error messages
*
+ * @since 1.33
* @param IContextSource $context
* @return array
*/
* Getting the restrictions will perform a database query if the restrictions
* are not already loaded.
*
+ * @since 1.33
* @return Restriction[]
*/
public function getRestrictions() {
/**
* Set Restrictions.
*
+ * @since 1.33
* @param Restriction[] $restrictions
- *
* @return self
*/
public function setRestrictions( array $restrictions ) {
* Password policy for the wiki.
* Structured as
* [
- * 'policies' => [ <group> => [ <policy> => <value>, ... ], ... ],
+ * 'policies' => [ <group> => [ <policy> => <settings>, ... ], ... ],
* 'checks' => [ <policy> => <callback>, ... ],
* ]
* where <group> is a user group, <policy> is a password policy name
* (arbitrary string) defined in the 'checks' part, <callback> is the
- * PHP callable implementing the policy check, <value> is a number,
- * boolean or null that gets passed to the callback.
+ * PHP callable implementing the policy check, <settings> is an array
+ * of options with the following keys:
+ * - value: (number, boolean or null) the value to pass to the callback
+ * - forceChange: (bool, default false) if the password is invalid, do
+ * not let the user log in without changing the password
+ * As a shorthand for [ 'value' => <value> ], simply <value> can be written.
+ * When multiple password policies are defined for a user, the settings
+ * arrays are merged, and for fields which are set in both arrays, the
+ * larger value (as understood by PHP's 'max' method) is taken.
*
* A user's effective policy is the superset of all policy statements
* from the policies for the groups where the user is a member. If more
* @note Consider using a TitleValue object instead. TitleValue is more lightweight
* and does not rely on global state or the database.
*/
-class Title implements LinkTarget {
+class Title implements LinkTarget, IDBAccessObject {
/** @var MapCacheLRU */
static private $titleCache = null;
}
$useReplica = ( $rigor !== 'secure' );
- if ( ( $action == 'edit' || $action == 'create' )
- && !$user->isBlockedFrom( $this, $useReplica )
- ) {
- // Don't block the user from editing their own talk page unless they've been
- // explicitly blocked from that too.
- } elseif ( $user->isBlocked() && $user->getBlock()->prevents( $action ) !== false ) {
+ $block = $user->getBlock( $useReplica );
+
+ // The block may explicitly allow an action (like "read" or "upload").
+ if ( $block && $block->prevents( $action ) === false ) {
+ return $errors;
+ }
+
+ // Determine if the user is blocked from this action on this page.
+ // What gets passed into this method is a user right, not an action nmae.
+ // There is no way to instantiate an action by restriction. However, this
+ // will get the action where the restriction is the same. This may result
+ // in actions being blocked that shouldn't be.
+ if ( Action::exists( $action ) ) {
// @todo FIXME: Pass the relevant context into this function.
- $errors[] = $user->getBlock()->getPermissionsError( RequestContext::getMain() );
+ $action = Action::factory( $action, WikiPage::factory( $this ), RequestContext::getMain() );
+ } else {
+ $action = null;
+ }
+
+ // If no action object is returned, assume that the action requires unblock
+ // which is the default.
+ if ( !$action || $action->requiresUnblock() ) {
+ if ( $user->isBlockedFrom( $this, $useReplica ) ) {
+ // @todo FIXME: Pass the relevant context into this function.
+ $errors[] = $block
+ ? $block->getPermissionsError( RequestContext::getMain() )
+ : [ 'actionblockedtext' ];
+ }
}
return $errors;
* indicating who can move or edit the page from the page table, (pre 1.10) rows.
* Edit and move sections are separated by a colon
* Example: "edit=autoconfirmed,sysop:move=sysop"
- * @param bool $readLatest When true, skip replicas and read from the master DB.
*/
- public function loadRestrictionsFromRows(
- $rows, $oldFashionedRestrictions = null, $readLatest = false
- ) {
- $whichDb = $readLatest ? DB_MASTER : DB_REPLICA;
- $dbr = wfGetDB( $whichDb );
+ public function loadRestrictionsFromRows( $rows, $oldFashionedRestrictions = null ) {
+ // This function will only read rows from a table that we migrated away
+ // from before adding READ_LATEST support to loadRestrictions, so we
+ // don't need to support reading from DB_MASTER here.
+ $dbr = wfGetDB( DB_REPLICA );
$restrictionTypes = $this->getRestrictionTypes();
* indicating who can move or edit the page from the page table, (pre 1.10) rows.
* Edit and move sections are separated by a colon
* Example: "edit=autoconfirmed,sysop:move=sysop"
- * @param bool $readLatest When true, skip replicas and read from the master DB.
+ * @param int $flags A bit field. If self::READ_LATEST is set, skip replicas and read
+ * from the master DB.
*/
- public function loadRestrictions( $oldFashionedRestrictions = null, $readLatest = false ) {
+ public function loadRestrictions( $oldFashionedRestrictions = null, $flags = 0 ) {
+ $readLatest = DBAccessObjectUtils::hasFlags( $flags, self::READ_LATEST );
if ( $this->mRestrictionsLoaded && !$readLatest ) {
return;
}
+ // TODO: should probably pass $flags into getArticleID, but it seems hacky
+ // to mix READ_LATEST and GAID_FOR_UPDATE, even if they have the same value.
+ // Maybe deprecate GAID_FOR_UPDATE now that we implement IDBAccessObject?
$id = $this->getArticleID();
if ( $id ) {
- $cache = ObjectCache::getMainWANInstance();
$fname = __METHOD__;
- $rows = $cache->getWithSetCallback(
- // Page protections always leave a new null revision
- $cache->makeKey( 'page-restrictions', $id, $this->getLatestRevID(), $readLatest ),
- $cache::TTL_DAY,
- function ( $curValue, &$ttl, array &$setOpts ) use ( $fname, $readLatest ) {
- $whichDb = $readLatest ? DB_MASTER : DB_REPLICA;
- $dbr = wfGetDB( $whichDb );
-
- $setOpts += Database::getCacheSetOptions( $dbr );
-
- return iterator_to_array(
- $dbr->select(
- 'page_restrictions',
- [ 'pr_type', 'pr_expiry', 'pr_level', 'pr_cascade' ],
- [ 'pr_page' => $this->getArticleID() ],
- $fname
- )
- );
- }
- );
+ $loadRestrictionsFromDb = function ( Database $dbr ) use ( $fname, $id ) {
+ return iterator_to_array(
+ $dbr->select(
+ 'page_restrictions',
+ [ 'pr_type', 'pr_expiry', 'pr_level', 'pr_cascade' ],
+ [ 'pr_page' => $id ],
+ $fname
+ )
+ );
+ };
+
+ if ( $readLatest ) {
+ $dbr = wfGetDB( DB_MASTER );
+ $rows = $loadRestrictionsFromDb( $dbr );
+ } else {
+ $cache = ObjectCache::getMainWANInstance();
+ $rows = $cache->getWithSetCallback(
+ // Page protections always leave a new null revision
+ $cache->makeKey( 'page-restrictions', $id, $this->getLatestRevID() ),
+ $cache::TTL_DAY,
+ function ( $curValue, &$ttl, array &$setOpts ) use ( $loadRestrictionsFromDb ) {
+ $dbr = wfGetDB( DB_REPLICA );
+
+ $setOpts += Database::getCacheSetOptions( $dbr );
+
+ return $loadRestrictionsFromDb( $dbr );
+ }
+ );
+ }
- $this->loadRestrictionsFromRows( $rows, $oldFashionedRestrictions, $readLatest );
+ $this->loadRestrictionsFromRows( $rows, $oldFashionedRestrictions );
} else {
$title_protection = $this->getTitleProtectionInternal();
"apihelp-expandtemplates-param-title": "頁面標題。",
"apihelp-expandtemplates-param-text": "要轉換的 Wikitext。",
"apihelp-expandtemplates-param-revid": "修訂 ID,用於 <code><nowiki>{{REVISIONID}}</nowiki></code> 和相似變數。",
+ "apihelp-expandtemplates-param-prop": "所要取得的資訊部份。\n\n請注意若沒有選定值,結果會包含 wiki 文字,輸出內容會採用棄用格式。",
"apihelp-expandtemplates-paramvalue-prop-wikitext": "展開的 wiki 文字。",
"apihelp-expandtemplates-paramvalue-prop-categories": "任何呈現在輸入中,且未在 wiki 文字輸出裡表現出的分類。",
"apihelp-expandtemplates-paramvalue-prop-properties": "透過在 wiki 文字裡擴充魔術字所定義的頁面屬性。",
"apihelp-feedrecentchanges-param-hidecategorization": "隱藏分類成員更改。",
"apihelp-feedrecentchanges-param-tagfilter": "按標籤篩選。",
"apihelp-feedrecentchanges-param-target": "僅顯示從該頁面所連結頁面上的變更。",
+ "apihelp-feedrecentchanges-param-showlinkedto": "改成顯示出連結到所選頁面的那些頁面之變更。",
"apihelp-feedrecentchanges-example-simple": "顯示近期變更。",
"apihelp-feedrecentchanges-example-30days": "顯示近期30天內的變動",
"apihelp-feedwatchlist-summary": "返回監視清單摘要。",
$reset = $this->getPasswordResetData( $username, $data );
if ( !$reset && $this->config->get( 'InvalidPasswordReset' ) && !$status->isGood() ) {
+ $hard = $status->getValue()['forceChange'] ?? false;
$reset = (object)[
- 'msg' => $status->getMessage( 'resetpass-validity-soft' ),
- 'hard' => false,
+ 'msg' => $status->getMessage( $hard ? 'resetpass-validity' : 'resetpass-validity-soft' ),
+ 'hard' => $hard,
];
}
/**
* Retrieves the restrictions from the database by block id.
*
+ * @since 1.33
* @param int|array $blockId
* @param IDatabase|null $db
* @return Restriction[]
/**
* Inserts the restrictions into the database.
*
+ * @since 1.33
* @param Restriction[] $restrictions
* @return bool
*/
* Updates the list of restrictions. This method does not allow removing all
* of the restrictions. To do that, use ::deleteByBlockId().
*
+ * @since 1.33
* @param Restriction[] $restrictions
* @return bool
*/
/**
* Updates the list of restrictions by parent id.
*
+ * @since 1.33
* @param int $parentBlockId
* @param Restriction[] $restrictions
* @return bool
/**
* Delete the restrictions.
*
+ * @since 1.33
* @param Restriction[]|null $restrictions
* @throws MWException
* @return bool
/**
* Delete the restrictions by Block ID.
*
+ * @since 1.33
* @param int|array $blockId
* @throws MWException
* @return bool
/**
* Delete the restrictions by Parent Block ID.
*
+ * @since 1.33
* @param int|array $parentBlockId
* @throws MWException
* @return bool
* equality check as the restrictions do not have to contain the same block
* ids.
*
+ * @since 1.33
* @param Restriction[] $a
* @param Restriction[] $b
* @return bool
/**
* Set the blockId on a set of restrictions and return a new set.
*
+ * @since 1.33
* @param int $blockId
* @param Restriction[] $restrictions
* @return Restriction[]
/**
* Create Restriction.
*
+ * @since 1.33
* @param int $blockId
* @param int $value
*/
/**
* Set the title.
*
+ * @since 1.33
* @param \Title $title
* @return self
*/
/**
* Get Title.
*
+ * @since 1.33
* @return \Title|null
*/
public function getTitle() {
/**
* Gets the id of the block.
*
+ * @since 1.33
* @return int
*/
public function getBlockId();
/**
* Sets the id of the block.
*
+ * @since 1.33
* @param int $blockId
* @return self
*/
/**
* Gets the value of the restriction.
*
+ * @since 1.33
* @return int
*/
public function getValue();
/**
* Gets the type of restriction
*
+ * @since 1.33
* @return string
*/
public function getType();
/**
* Gets the id of the type of restriction. This id is used in the database.
*
+ * @since 1.33
* @return string
*/
public function getTypeId();
/**
* Creates a new Restriction from a database row.
*
+ * @since 1.33
* @param \stdClass $row
* @return self
*/
/**
* Convert a restriction object into a row array for insertion.
*
+ * @since 1.33
* @return array
*/
public function toRow();
/**
* Determine if a restriction matches a given title.
*
+ * @since 1.33
* @param \Title $title
* @return bool
*/
/**
* Determine if a restriction equals another restriction.
*
+ * @since 1.33
* @param Restriction $other
* @return bool
*/
/**
* Create a unique hash of the block restriction based on the type and value.
*
+ * @since 1.33
* @return string
*/
public function getHash();
* Upload a file directly into archive. Generally for Special:Import.
*
* @param string $srcPath File system path of the source file
- * @param string $archiveName Full archive name of the file, in the form
- * $timestamp!$filename, where $filename must match $this->getName()
* @param string $timestamp
* @param string $comment
* @param User $user
* @return Status
*/
- function uploadOld( $srcPath, $archiveName, $timestamp, $comment, $user ) {
+ public function uploadOld( $srcPath, $timestamp, $comment, $user ) {
$this->lock();
+ $archiveName = $this->getArchiveName();
$dstRel = $this->getArchiveRel( $archiveName );
$status = $this->publishTo( $srcPath, $dstRel );
$languages[$languageCode] = $languageCode;
}
+ ksort( $languages );
+
foreach ( $languages as $code => $name ) {
$this->mParams['options'][$code . ' - ' . $name] = $code;
}
?: User::newFromName( $importableRevision->getUser(), false );
# Do the actual upload
- if ( $archiveName ) {
- $status = $file->uploadOld( $source, $archiveName,
- $importableRevision->getTimestamp(), $importableRevision->getComment(), $user );
+ if ( $file instanceof OldLocalFile ) {
+ $status = $file->uploadOld(
+ $source,
+ $importableRevision->getTimestamp(),
+ $importableRevision->getComment(),
+ $user
+ );
} else {
$flags = 0;
$status = $file->upload(
"config-install-mainpage-failed": "Не вдається вставити головну сторінку: $1",
"config-install-done": "<strong>Вітаємо!</strong>\nВи успішно встановили MediaWiki.\n\nІнсталятор згенерував файл <code>LocalSettings.php</code>, який містить усі Ваші налаштування.\n\nВам необхідно завантажити його і помістити у кореневу папку Вашої вікі (туди ж, де index.php). Завантаження мало початись автоматично.\n\nЯкщо завантаження не почалось або Ви його скасували, можете заново його почати, натиснувши на посилання внизу:\n\n$3\n\n<strong>Примітка</strong>: Якщо Ви не зробите цього зараз, цей файл не буде доступним пізніше, коли Ви вийдете з встановлення, не скачавши його.\n\nПісля виконання дій, описаних вище, Ви зможете <strong>[$2 увійти у свою вікі]</strong>.",
"config-install-done-path": "<strong>Вітаємо!</strong>\nВи встановили Медіавікі.\n\nІнсталятор створив файл <code>LocalSettings.php</code>.\nУ ньому містяться всі Ваші налаштування.\n\nВам потрібно завантажити його й помістити в <code>$4</code>. Завантаження повинно було автоматично розпочатись.\n\nЯкщо завантаження не було запропоновано, або Ви його скасували, Ви можете перезапустити завантаження натиснувши на посилання нижче:\n\n$3\n\n<strong>Зверніть увагу:</strong> Якщо Ви не зробите це зараз, цей згенерований файл налаштувань не буде доступним для Вас пізніше якщо Ви вийдете зі встановлення не завантаживши його.\n\nКоли це було зроблено Ви можете <strong>[$2 зайти до своєї вікі]</strong>.",
- "config-install-success": "Mediawiki Ñ\83Ñ\81пÑ\96Ñ\88но вÑ\81Ñ\82ановлено. Ð\97аÑ\80аз ви можеÑ\82е пеÑ\80ейÑ\82и до <$1$2>, Ñ\89об пеÑ\80еглÑ\8fнÑ\83Ñ\82и Ñ\81воÑ\8e вÑ\96кÑ\96. ЯкÑ\89о Ñ\83 ваÑ\81 Ñ\94 пиÑ\82аннÑ\8f, ознайомÑ\82еÑ\81Ñ\8f з наÑ\88им FAQ: <https://www.mediawiki.org/wiki/Manual:FAQ> або використовуйте один з форумів підтримки, які вказано на цій сторінці.",
+ "config-install-success": "Mediawiki Ñ\83Ñ\81пÑ\96Ñ\88но вÑ\81Ñ\82ановлено. Ð\97аÑ\80аз Ð\92и можеÑ\82е пеÑ\80ейÑ\82и до <$1$2>, Ñ\89об пеÑ\80еглÑ\8fнÑ\83Ñ\82и Ñ\81воÑ\8e вÑ\96кÑ\96. ЯкÑ\89о Ñ\83 Ð\92аÑ\81 Ñ\94 пиÑ\82аннÑ\8f, ознайомÑ\82еÑ\81Ñ\8f з наÑ\88им FAQ: <https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> або використовуйте один з форумів підтримки, які вказано на цій сторінці.",
"config-download-localsettings": "Завантажити <code>LocalSettings.php</code>",
"config-help": "допомога",
"config-help-tooltip": "натисніть, щоб розгорнути",
"config-nofile": "Файл \"$1\" не знайдено. Його видалено?",
- "config-extension-link": "Чи знаєте ви, що ваше вікі підтримує [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions розширення]?\n\nВи можете переглядати [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category розширення по категорії] або в [https://www.mediawiki.org/wiki/Extension_Matrix матрицю розширень] щоб побачити повний список розширень.",
+ "config-extension-link": "Чи знали Ви, що Ваша вікі підтримує [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions розширення]?\n\nМожете переглянути [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category розширення за категорією]",
"config-skins-screenshots": "$1 (скріншоти: $2)",
"config-extensions-requires": "$1 (вимагає $2)",
"config-screenshot": "скріншот",
+ "config-extension-not-found": "Не вдалося знайти файл реєстрації для розширення «$1»",
+ "config-extension-dependency": "При встановленні розширення «$1» виникла помилка залежності: $2",
"mainpagetext": "<strong>Програмне забезпечення «MediaWiki» встановлено.</strong>",
"mainpagedocfooter": "Інформацію про роботу з цією вікі можна знайти на сторінці [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Довідка:Вміст].\n\n== Деякі корисні ресурси ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Список налаштувань];\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Часті питання з приводу MediaWiki];\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Розсилка повідомлень про появу нових версій MediaWiki];\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Локалізувати MediaWiki своєю мовою]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Дізнатися, як боротися зі спамом у своїй вікі]"
}
* );
* @endcode
*
+ * Example usage (key that is expensive with too many DB dependencies for "check keys"):
+ * @code
+ * $catToys = $cache->getWithSetCallback(
+ * // Key to store the cached value under
+ * $cache->makeKey( 'cat-toys', $catId ),
+ * // Time-to-live (seconds)
+ * $cache::TTL_HOUR,
+ * // Function that derives the new key value
+ * function ( $oldValue, &$ttl, array &$setOpts ) {
+ * // Determine new value from the DB
+ * $dbr = wfGetDB( DB_REPLICA );
+ * // Account for any snapshot/replica DB lag
+ * $setOpts += Database::getCacheSetOptions( $dbr );
+ *
+ * return CatToys::newFromResults( $dbr->select( ... ) );
+ * },
+ * [
+ * // Get the highest timestamp of any of the cat's toys
+ * 'touchedCallback' => function ( $value ) use ( $catId ) {
+ * $dbr = wfGetDB( DB_REPLICA );
+ * $ts = $dbr->selectField( 'cat_toys', 'MAX(ct_touched)', ... );
+ *
+ * return wfTimestampOrNull( TS_UNIX, $ts );
+ * },
+ * // Avoid DB queries for repeated access
+ * 'pcTTL' => $cache::TTL_PROC_SHORT
+ * ]
+ * );
+ * @endcode
+ *
* Example usage (hot key holding most recent 100 events):
* @code
* $lastCatActions = $cache->getWithSetCallback(
* expired for this specified time. This is useful if adaptiveTTL() is used on the old
* value's as-of time when it is verified as still being correct.
* Default: WANObjectCache::STALE_TTL_NONE
- * - touchedCallback: A callback that takes the current value and returns a timestamp that
- * indicates the last time a dynamic dependency changed. Null can be returned if there
+ * - touchedCallback: A callback that takes the current value and returns a UNIX timestamp
+ * indicating the last time a dynamic dependency changed. Null can be returned if there
* are no relevant dependency changes to check. This can be used to check against things
* like last-modified times of files or DB timestamp fields. This should generally not be
* used for small and easily queried values in a DB if the callback itself ends up doing
}
$this->loadPageData( 'fromdbmaster' );
+ $this->mTitle->loadRestrictions( null, Title::READ_LATEST );
$restrictionTypes = $this->mTitle->getRestrictionTypes();
$id = $this->getId();
/**
* @param array $policies
* @param array $checks mapping statement to its checking function. Checking functions are
- * called with the policy value for this user, the user object, and the password to check.
+ * called with the policy value for this user, the user object, and the password to check.
*/
public function __construct( array $policies, array $checks ) {
if ( !isset( $policies['default'] ) ) {
* @param User $user who's policy we are checking
* @param string $password the password to check
* @return Status error to indicate the password didn't meet the policy, or fatal to
- * indicate the user shouldn't be allowed to login.
+ * indicate the user shouldn't be allowed to login. The status value will be an array,
+ * potentially with the following keys:
+ * - forceChange: do not allow the user to login without changing the password if invalid.
*/
public function checkUserPassword( User $user, $password ) {
$effectivePolicy = $this->getPoliciesForUser( $user );
* @param string $password the password to check
* @param array $groups list of groups to which we assume the user belongs
* @return Status error to indicate the password didn't meet the policy, or fatal to
- * indicate the user shouldn't be allowed to login.
+ * indicate the user shouldn't be allowed to login. The status value will be an array,
+ * potentially with the following keys:
+ * - forceChange: do not allow the user to login without changing the password if invalid.
*/
public function checkUserPasswordForGroups( User $user, $password, array $groups ) {
$effectivePolicy = self::getPoliciesForGroups(
* @return Status
*/
private function checkPolicies( User $user, $password, $policies, $policyCheckFunctions ) {
- $status = Status::newGood();
- foreach ( $policies as $policy => $value ) {
+ $status = Status::newGood( [] );
+ $forceChange = false;
+ foreach ( $policies as $policy => $settings ) {
if ( !isset( $policyCheckFunctions[$policy] ) ) {
throw new DomainException( "Invalid password policy config. No check defined for '$policy'." );
}
- $status->merge(
- call_user_func(
- $policyCheckFunctions[$policy],
- $value,
- $user,
- $password
- )
+ if ( !is_array( $settings ) ) {
+ // legacy format
+ $settings = [ 'value' => $settings ];
+ }
+ if ( !array_key_exists( 'value', $settings ) ) {
+ throw new DomainException( "Invalid password policy config. No value defined for '$policy'." );
+ }
+ $value = $settings['value'];
+ /** @var StatusValue $policyStatus */
+ $policyStatus = call_user_func(
+ $policyCheckFunctions[$policy],
+ $value,
+ $user,
+ $password
);
+ if ( !$policyStatus->isGood() && !empty( $settings['forceChange'] ) ) {
+ $forceChange = true;
+ }
+ $status->merge( $policyStatus );
+ }
+ if ( $status->isOK() && $forceChange ) {
+ $status->value['forceChange'] = true;
}
return $status;
}
/**
* Utility function to get a policy that is the most restrictive of $p1 and $p2. For
* simplicity, we setup the policy values so the maximum value is always more restrictive.
+ * It is also used recursively to merge settings within the same policy.
* @param array $p1
* @param array $p2
* @return array containing the more restrictive values of $p1 and $p2
$ret[$key] = $p2[$key];
} elseif ( !isset( $p2[$key] ) ) {
$ret[$key] = $p1[$key];
- } else {
+ } elseif ( !is_array( $p1[$key] ) && !is_array( $p2[$key] ) ) {
$ret[$key] = max( $p1[$key], $p2[$key] );
+ } else {
+ if ( !is_array( $p1[$key] ) ) {
+ $p1[$key] = [ 'value' => $p1[$key] ];
+ } elseif ( !is_array( $p2[$key] ) ) {
+ $p2[$key] = [ 'value' => $p2[$key] ];
+ }
+ $ret[$key] = self::maxOfPolicies( $p1[$key], $p2[$key] );
}
}
return $ret;
$userGroups = $targetUser->getGroups();
if ( $userGroups !== $conflictCheck ) {
- $out->addWikiMsg( 'userrights-conflict' );
+ $out->wrapWikiMsg( '<span class="error">$1</span>', 'userrights-conflict' );
} else {
$status = $this->saveUserGroups(
$this->mTarget,
}
# image filters can pull in url, which could be svg that executes scripts
+ # Only allow url( "#foo" ). Do not allow url( http://example.com )
if ( $strippedElement == 'image'
&& $stripped == 'filter'
- && preg_match( '!url\s*\(!sim', $value )
+ && preg_match( '!url\s*\(\s*["\']?[^#]!sim', $value )
) {
wfDebug( __METHOD__ . ": Found image filter with url: "
. "\"<$strippedElement $stripped='$value'...\" in uploaded file.\n" );
/**
* Check if this is a valid password for this user
*
- * Create a Status object based on the password's validity.
- * The Status should be set to fatal if the user should not
- * be allowed to log in, and should have any errors that
- * would block changing the password.
- *
- * If the return value of this is not OK, the password
- * should not be checked. If the return value is not Good,
- * the password can be checked, but the user should not be
- * able to set their password to this.
+ * Returns a Status object with a set of messages describing
+ * problems with the password. If the return status is fatal,
+ * the action should be refused and the password should not be
+ * checked at all (this is mainly meant for DoS mitigation).
+ * If the return value is OK but not good, the password can be checked,
+ * but the user should not be able to set their password to this.
+ * The value of the returned Status object will be an array which
+ * can have the following fields:
+ * - forceChange (bool): if set to true, the user should not be
+ * allowed to log with this password unless they change it during
+ * the login process (see ResetPasswordSecondaryAuthenticationProvider).
*
* @param string $password Desired password
* @return Status
$wgPasswordPolicy['checks']
);
- $status = Status::newGood();
+ $status = Status::newGood( [] );
$result = false; // init $result to false for the internal checks
if ( !Hooks::run( 'isValidPassword', [ $password, &$result, $this ] ) ) {
}
if ( $result === false ) {
- $status->merge( $upp->checkUserPassword( $this, $password ) );
+ $status->merge( $upp->checkUserPassword( $this, $password ), true );
return $status;
} elseif ( $result === true ) {
return $status;
/**
* Get whether the user is blocked from using Special:Upload
*
+ * @since 1.33
* @return bool
*/
public function isBlockedFromUpload() {
"statistics": "Статыстыка",
"statistics-header-pages": "Статыстыка старонак",
"statistics-header-edits": "Статыстыка рэдагаваньняў",
- "statistics-header-users": "СÑ\82аÑ\82Ñ\8bÑ\81Ñ\82Ñ\8bка Ñ\9eдзелÑ\83",
+ "statistics-header-users": "СÑ\82аÑ\82Ñ\8bÑ\81Ñ\82Ñ\8bка Ñ\9eдзелÑ\8cнÑ\96каÑ\9e",
"statistics-header-hooks": "Іншая статыстыка",
"statistics-articles": "Колькасьць старонак са зьместам",
"statistics-pages": "Колькасьць старонак",
"logentry-delete-delete": "$1 {{GENDER:$2|выдаліў|выдаліла}} старонку $3",
"logentry-delete-delete_redir": "$1 {{GENDER:$2|выдаліў|выдаліла}} перанакіраванне $3 шляхам перазапісу",
"logentry-delete-restore": "$1 {{GENDER:$2|аднавіў|аднавіла}} старонку $3 ($4)",
+ "logentry-delete-restore-nocount": "$1 {{GENDER:$2|аднавіў|аднавіла}} старонку $3",
"restore-count-revisions": "{{PLURAL:$1|1 версія|$1 версіі|$1 версій}}",
"logentry-delete-event": "$1 {{GENDER:$2|змяніў|змяніла}} бачнасць {{PLURAL:$5|запісу журнала|$5 запісаў журнала}} $3: $4",
"logentry-delete-revision": "$1 {{GENDER:$2|змяніў|змяніла}} бачнасць {{PLURAL:$5|версіі|$5 версій|$5 версій}} старонкі $3: $4",
},
"tog-underline": "هومپیڤٱندا زیر خٱتدار",
"tog-hideminor": "دٱم تی نٱبیڌن آلشتا کۊچیر",
+ "tog-hidepatrolled": "بؽدیار نڤیڌن آلشڌٱل کوچیر",
+ "tog-newpageshidepatrolled": "بٱلٛگیٱل لرهٱرڌاْ زاْ فاٛئرست بٱلٛگیٱل نۊ بؽدیار ڤۊهاْ",
+ "tog-hidecategorization": "بؽدیارنیڌن رٱئڌاٛڤٱنی بٱلٛگیٱل",
"tog-extendwatchlist": "گپ کردن نوم گه آ مو سی دیئن همه آلشتا نه فقط هونو که بیشتر ز همه انجوم ابون.",
"tog-usenewrc": "جٱرغاٛ کاری آلشتا ڤا آلشتکاری بٱلگاٛیلسۊن و سئیل بٱرگسۊن",
"tog-numberheadings": "شوماراٛ ڤٱندن خودٱنجوم سی سربٱلگاٛیل",
"tog-watchdefault": "اٛزاف کردن بٱلگاٛیٱل و جانیایٱلی کاٛ مو مئن سئیل برگوم ڤیرایشدسۊن کردوماٛ",
"tog-watchmoves": "اْزاف کردن بٱلگاٛیٱلی کاٛ خوم جا ب جاسۊن کردوماٛ سی سئل بٱرگوم",
"tog-watchdeletion": "اٛزاف کردن بٱلگاٛیٱل و جانیایٱلی کاٛ خوم ز مئن سئیل بٱرگوم پاکسا کردوماٛ",
+ "tog-watchuploads": "پٱرڤٱنداٛیٱل نۊئی کاْ باراْنم ڤاْ فاٛئرسڌ دیناگریٱل مو بالاڤٱن ڤۊ",
+ "tog-watchrollback": "بالاڤٱن کرڌن بٱلٛگیٱلؽ کاْ اْؤورگٱرنیم ڤاْ فاٛئرسڌ دیناگریٱل مو",
"tog-minordefault": "دیاری کردن جۊر ڤیرایشتا ناقس",
"tog-previewontop": "دیاری کردن پیش سئیل پیش ز ڤیرایشد جٱڤٱ",
"tog-previewonfirst": "دیاری کردن پیش سئیل مئن ٱڤلین ڤیرایشد",
"tog-watchlisthidebots": "قایم کردن اصلاحات بوت زه لیست پیگیریها",
"tog-watchlisthideminor": "قایم کردن اصلاحات ریز زه لیست پیگیریها",
"tog-watchlisthideliu": "قایم کردن اصلاحات انجام وابیده بوسیله کاربران داخل سیستم وابیده زه لیست پیگیریها",
+ "tog-watchlistreloadautomatically": "راتؽ کاْ یٱ پاْلایاٛ آلشڌآڤیڌ فاٛئرسڌ دیناگری بؽنگوڌ(خوڌکار)ڤ رۊز ڤۊهاْ(هوجاْ ڤاْ جاڤا اسکریپت)",
+ "tog-watchlistunwatchlinks": "فرٱنیڌن دیاری کونٱنڌیٱل نڤیڌ دیناگری/دیناگری ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}})ڤاْ بٱلٛگیٱل دیناگری آلشڌدار (سی عملیات کلؽز ۉ بلؽز کرڌن، جاڤاسکریپت هوجاْ هؽڌآ)",
"tog-watchlisthideanons": "قایم کردن اصلاحات انجام شده بوسیله کاربران داخل سیستم نشده زه لیست پیگیری",
+ "tog-watchlisthidepatrolled": "تٱپنیڌن پٱخڌارٱل ساوا زاْ لیسڌ دیناگریٱل\nتٱپنیڌن پٱخڌارٱل بۊت زاْ لیسڌ دیناگریٱل\nتٱپنیڌن پٱخڌارٱل مو زاْ لیسڌ دیناگریٱل",
+ "tog-watchlisthidecategorization": "تٱپنیڌن رٱئڌڤٱنی بٱلٛگیٱل",
"tog-ccmeonemails": "ارسال کپی امیلهایی که مو به کاربران دیه ارسال کردم به مو",
"tog-diffonly": "بٱلگاٛیی نٱ کاٛ مئنۊناٛ فٱرخداراٛ نشۊن مٱڌاٛ",
"tog-showhiddencats": "دیاری کردن جٱرغاٛ بٱندیٱل نادیار",
"tooltip-preferences-save": "Uložit nastavení",
"tooltip-summary": "Zadejte stručné shrnutí",
"interlanguage-link-title": "$1 – $2",
- "common.css": "/* Zde uvedené CSS bude ovlivňovat všechny styly */",
+ "common.css": "/* Zde uvedené CSS bude ovlivňovat všechny vzhledy */",
"print.css": "/* Zde uvedené CSS bude ovlivňovat tiskový výstup */",
"noscript.css": "/* Zde uvedené CSS bude ovlivňovat uživatele s vypnutým JavaScriptem */",
"group-autoconfirmed.css": "/* Zde uvedené CSS bude ovlivňovat pouze automaticky schválené uživatele */",
"group-sysop.css": "/* Zde uvedené CSS bude ovlivňovat pouze správce */",
"group-bureaucrat.css": "/* Zde uvedené CSS bude ovlivňovat pouze byrokraty */",
"common.json": "/* Zde uvedený JSON se načte pro všechny uživatele při načtení každé stránky. */",
- "common.js": "/* Zde uvedený JavaScript bude použit pro všechny uživatele při načtení každé stránky. */",
+ "common.js": "/* Zde uvedený JavaScript bude použit pro všechny uživatele při načtení každé stránky */",
"group-autoconfirmed.js": "/* Zde uvedený JavaScript bude použit pouze pro automaticky schválené uživatele */",
"group-user.js": "/* Zde uvedený JavaScript bude použit pouze pro registrované uživatele */",
"group-bot.js": "/* Zde uvedený JavaScript bude použit pouze pro roboty */",
"resetpass-abort-generic": "Die Passwortänderung wurde durch eine Erweiterung abgebrochen.",
"resetpass-expired": "Dein Passwort ist abgelaufen. Bitte lege ein neues Passwort zur Anmeldung fest.",
"resetpass-expired-soft": "Dein Passwort ist abgelaufen und muss geändert werden. Bitte wähle jetzt ein neues Passwort aus oder klicke auf „{{int:authprovider-resetpass-skip-label}}“, um es später zu ändern.",
+ "resetpass-validity": "Dein Passwort ist nicht gültig: $1\n\nBitte lege zur Anmeldung ein neues Passwort fest.",
"resetpass-validity-soft": "Dein Passwort ist ungültig: $1\n\nBitte wähle jetzt ein neues Passwort aus oder klicke auf „{{int:authprovider-resetpass-skip-label}}“, um es später zu ändern.",
"passwordreset": "Passwort zurücksetzen",
"passwordreset-text-one": "Fülle dieses Formular aus, um ein temporäres Passwort per E-Mail zu erhalten.",
"resetpass-abort-generic": "Password change has been aborted by an extension.",
"resetpass-expired": "Your password has expired. Please set a new password to log in.",
"resetpass-expired-soft": "Your password has expired and needs to be changed. Please choose a new password now, or click \"{{int:authprovider-resetpass-skip-label}}\" to change it later.",
+ "resetpass-validity": "Your password is not valid: $1\n\nPlease set a new password to log in.",
"resetpass-validity-soft": "Your password is not valid: $1\n\nPlease choose a new password now, or click \"{{int:authprovider-resetpass-skip-label}}\" to change it later.",
"passwordreset": "Reset password",
"passwordreset-text-one": "Complete this form to receive a temporary password via email.",
"blockedtext": "<strong>Your username or IP address has been blocked.</strong>\n\nThe block was made by $1.\nThe reason given is <em>$2</em>.\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n\nYou can contact $1 or another [[{{MediaWiki:Grouppage-sysop}}|administrator]] to discuss the block.\nYou cannot use the \"{{int:emailuser}}\" feature unless a valid email address is specified in your [[Special:Preferences|account preferences]] and you have not been blocked from using it.\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
"autoblockedtext": "Your IP address has been automatically blocked because it was used by another user, who was blocked by $1.\nThe reason given is:\n\n:<em>$2</em>\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n\nYou may contact $1 or one of the other [[{{MediaWiki:Grouppage-sysop}}|administrators]] to discuss the block.\n\nNote that you may not use the \"{{int:emailuser}}\" feature unless you have a valid email address registered in your [[Special:Preferences|user preferences]] and you have not been blocked from using it.\n\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
"systemblockedtext": "Your username or IP address has been automatically blocked by MediaWiki.\nThe reason given is:\n\n:<em>$2</em>\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n\nYour current IP address is $3.\nPlease include all above details in any queries you make.",
+ "actionblockedtext": "You have been blocked from performing this action.",
"blockednoreason": "no reason given",
"whitelistedittext": "Please $1 to edit pages.",
"confirmedittext": "You must confirm your email address before editing pages.\nPlease set and validate your email address through your [[Special:Preferences|user preferences]].",
"exif-photometricinterpretation-3": "Палітра",
"exif-photometricinterpretation-4": "Маска празрыстасьці",
"exif-photometricinterpretation-5": "Падзелены (імаверна, CMYK)",
+ "exif-photometricinterpretation-8": "CIE L*a*b*",
"exif-unknowndate": "Невядомая дата",
"exif-orientation-1": "Звычайная",
"exif-orientation-2": "Адлюстраваная па гарызанталі",
"exif-compression-4": "CCITT Group 4 codification fax",
"exif-copyrighted-true": "Sub copyright",
"exif-copyrighted-false": "Stato de copyright non definite",
+ "exif-photometricinterpretation-0": "Nigro e blanco (blanco es 0)",
"exif-photometricinterpretation-1": "Nigre e blanc (0 pro nigre)",
+ "exif-photometricinterpretation-3": "Paletta",
+ "exif-photometricinterpretation-4": "Masca de transparentia",
+ "exif-photometricinterpretation-5": "Separate (probabilemente CMYK)",
+ "exif-photometricinterpretation-8": "CIE L*a*b*",
+ "exif-photometricinterpretation-9": "CIE L*a*b* (codification ICC)",
+ "exif-photometricinterpretation-10": "CIE L*a*b* (codification ITU)",
"exif-unknowndate": "Data incognite",
"exif-orientation-1": "Normal",
"exif-orientation-2": "Invertite horizontalmente",
"Ua2004",
"Ата",
"Максим Підліснюк",
- "Тест"
+ "Тест",
+ "Piramidion"
]
},
"exif-imagewidth": "Ширина",
"exif-compression-34712": "JPEG2000",
"exif-copyrighted-true": "Охороняється законом про авторське право",
"exif-copyrighted-false": "Авторські права не встановлено",
+ "exif-photometricinterpretation-0": "Чорний і білий (Білий — це 0)",
"exif-photometricinterpretation-1": "Чорний і білий (білий — 0)",
"exif-photometricinterpretation-2": "RGB",
+ "exif-photometricinterpretation-3": "Палітра",
+ "exif-photometricinterpretation-4": "Маска прозорості",
+ "exif-photometricinterpretation-5": "Відокремлено (ймовірно CMYK)",
"exif-photometricinterpretation-6": "YCbCr",
+ "exif-photometricinterpretation-8": "CIE L*a*b*",
+ "exif-photometricinterpretation-9": "CIE L*a*b* (ICC-кодування)",
+ "exif-photometricinterpretation-10": "CIE L*a*b* (ITU-кодування)",
"exif-unknowndate": "Невідома дата",
"exif-orientation-1": "Нормальна",
"exif-orientation-2": "Відображено по горизонталі",
"accmailtext": "Un mot de passe généré aléatoirement pour [[User talk:$1|$1]] a été envoyé à $2.\nIl peut être modifié sur la page ''[[Special:ChangePassword|Changement de mot de passe]]'' après connexion.",
"newarticle": "(Nouveau)",
"newarticletext": "Vous avez suivi un lien vers une page qui n’existe pas encore. \nAfin de créer cette page, entrez votre texte dans la boîte ci-après (vous pouvez consulter [$1 la page d’aide] pour plus d’informations). \nSi vous êtes arrivé{{GENDER:||e}} ici par erreur, cliquez sur le bouton <strong>Retour</strong> de votre navigateur.",
- "anontalkpagetext": "----\n<em>Vous êtes sur la page de discussion d’un utilisateur anonyme qui n’a pas encore créé de compte ou qui n’en utilise pas</em>.\nPour cette raison, nous devons utiliser son adresse IP pour les identifier.\nUne adresse IP peut être partagée par plusieurs utilisateurs.\nSi vous êtes un{{GENDER:||e|}} utilisat{{GENDER:|eur|rice|eur}} anonyme et si vous constatez que des commentaires qui ne vous concernent pas vous ont été adressés, vous pouvez [[Special:CreateAccount|créer un compte]] ou [[Special:UserLogin|vous connecter]] afin d’éviter toute confusion future avec d’autres contributeurs anonymes.",
+ "anontalkpagetext": "----\n<em>Vous êtes sur la page de discussion d’un utilisateur anonyme qui n’a pas encore créé de compte ou qui n’en utilise pas</em>.\nPour cette raison, nous devons utiliser son adresse IP pour l'identifier.\nUne telle adresse IP peut être partagée par plusieurs utilisateurs.\nSi vous êtes un{{GENDER:||e|}} utilisat{{GENDER:|eur|rice|eur}} anonyme et si vous constatez que des commentaires qui ne vous concernent pas vous ont été adressés, vous pouvez [[Special:CreateAccount|créer un compte]] ou [[Special:UserLogin|vous connecter]] afin d’éviter toute confusion future avec d’autres contributeurs anonymes.",
"noarticletext": "Il n’y a pour l’instant aucun texte sur cette page.\nVous pouvez [[Special:Search/{{PAGENAME}}|lancer une recherche sur ce titre]] dans les autres pages,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rechercher dans les opérations liées]\nou [{{fullurl:{{FULLPAGENAME}}|action=edit}} créer cette page]</span>.",
"noarticletext-nopermission": "Il n'y a pour l'instant aucun texte sur cette page.\nVous pouvez [[Special:Search/{{PAGENAME}}|faire une recherche sur ce titre]] dans les autres pages,\nou <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rechercher dans les journaux associés]</span>, mais vous n'avez pas la permission de créer cette page.",
"missing-revision": "La révision nº $1 de la page intitulée « {{FULLPAGENAME}} » n’existe pas.\n\nCela survient en général en suivant un lien historique désuet vers une page qui a été supprimée.\nVous pouvez trouver plus de détails dans le [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} journal des suppressions].",
"special-characters-title-emdash": "tiret cadratin",
"special-characters-title-minus": "signe moins",
"mw-widgets-abandonedit": "Êtes-vous sûr de vouloir quitter le mode d’édition sans enregistrer d’abord ?",
- "mw-widgets-abandonedit-discard": "Ignorer les modifications",
+ "mw-widgets-abandonedit-discard": "Annuler les modifications",
"mw-widgets-abandonedit-keep": "Continuer à modifier",
"mw-widgets-abandonedit-title": "Êtes-vous sûr ?",
"mw-widgets-dateinput-no-date": "Aucune date sélectionnée",
"thu": "Ham",
"fri": "Jum",
"sat": "Sah",
- "january": "Januwari",
- "february": "Peburuari",
+ "january": "Januari",
+ "february": "Pebruari",
"march": "Maret",
"april": "April",
"may_long": "Mei",
"october": "Oktober",
"november": "Nopember",
"december": "Desember",
- "january-gen": "Januwari",
+ "january-gen": "Januari",
"february-gen": "Pebruari",
"march-gen": "Maret",
"april-gen": "April",
"newmessagesdifflinkplural": "{{PLURAL:$1|biloli'o|999=u biloli'o}} pulitiyo",
"youhavenewmessagesmulti": "Yio lo'otapu tahuli bohu to $1",
"editsection": "boli'a",
- "editold": "boli'",
+ "editold": "boli'a",
"viewsourceold": "Bilohi bungoliyo",
"editlink": "boli'a",
"viewsourcelink": "Bilohi bungoliyo",
"resetpass-abort-generic": "שינוי הסיסמה בוטל על־ידי הרחבה.",
"resetpass-expired": "סיסמתך פקעה. נא להגדיר סיסמה חדשה כדי להיכנס.",
"resetpass-expired-soft": "הסיסמה שלך פקעה, וצריך לשנות אותה. יש לבחור סיסמה חדשה כעת, או ללחוץ על \"{{int:authprovider-resetpass-skip-label}}\" כדי לשנות אותה מאוחר יותר.",
+ "resetpass-validity": "סיסמתך אינה חוקית: $1\n\nנא להגדיר סיסמה חדשה כדי להיכנס.",
"resetpass-validity-soft": "הסיסמה שלך אינה תקינה: $1\n\nיש לבחור סיסמה חדשה כעת או ללחוץ על \"{{int:authprovider-resetpass-skip-label}}\" כדי לשנות את הסיסמה מאוחר יותר.",
"passwordreset": "איפוס סיסמה",
"passwordreset-text-one": "יש למלא טופס זה כדי לקבל סיסמה זמנית בדוא\"ל.",
"Macofe",
"Fitoschido",
"Baloch Khan",
- "Muhraz"
+ "Muhraz",
+ "Ardzun"
]
},
"tog-underline": "Garih bawahi tautan:",
"permalink": "Pautan parmanen",
"print": "Cetak",
"view": "Baco",
+ "view-foreign": "Caliak di $1",
"edit": "Suntiang",
"create": "Buek",
+ "create-local": "Tambah sumber deskripsi lokal",
"delete": "Hapuih",
"undelete_short": "Batal hapuih $1 {{PLURAL:$1|suntiangan}}",
"viewdeleted_short": "Lihek {{PLURAL:$1|$1 suntiangan}} nan dihapuih",
"otherlanguages": "Dalam bahaso lain",
"redirectedfrom": "(Dialiahkan dari $1)",
"redirectpagesub": "Laman pangaliahan",
+ "redirectto": "Dialiahkan ka",
"lastmodifiedat": "Laman ko tarakhia diubah pado $2, tanggal $1.",
"viewcount": "Laman ko lah dicaliak {{PLURAL:$1|$1 kali}}.",
"protectedpage": "Laman nan dilinduangi",
"actionthrottled": "Tindakan tabateh",
"actionthrottledtext": "Sanak tabateh untuak malakuan tindakan ko banyak-banyak dalam wakatu singkek. Cubo lah laik satalah bara minit.",
"protectedpagetext": "Laman ko alah dikunci untuak manghindari panyuntiangan.",
- "viewsourcetext": "Sanak dapek malihek atau manyalin sumber laman iko:",
+ "viewsourcetext": "Sanak dapek mancaliak atau manyalin sumber laman iko:",
"viewyourtext": "Sanak dapek mancaliak jo mangkopi sumber untuak \"suntiangan sanak\" ka laman ko",
"protectedinterface": "Laman ko baisi teks antarmuko untuak digunoan dek parangkaik lunak di wiki ko sajo, dan alah dikunci untuak maindaan kasalahan. \nUntuak manambah atau maubah tajamahan di kasado wiki, harap gunoan [https://translatewiki.net/ translatewiki.net], yaitu proyek palokalan MediaWiki.",
"editinginterface": "'''Paringatan:''' Sanak manyuntiang laman nan digunoan untuak manyadiokan teks antarmuko untuak parangkaik lunak.\nParubahan teks ko akan mampangaruhi tampilan pado antarmuko pangguno untuak pangguno lain.\nUntuak tajamahan, harap gunoan [https://translatewiki.net/wiki/Main_Page?setlang=min translatewiki.net], proyek palokalan MediaWiki.",
"userlogin-noaccount": "Alun ado akun?",
"userlogin-joinproject": "Join {{SITENAME}}",
"createaccount": "Buek akun",
- "userlogin-resetpassword-link": "Buek ulang kato sandi",
+ "userlogin-resetpassword-link": "Lupo kato sandi Sanak?",
+ "userlogin-helplink2": "Bantuan masuak log",
"createacct-emailrequired": "Alamaik surel",
"createacct-emailoptional": "Alamaik surel (opsional)",
"createacct-email-ph": "Masuakan alamaik surel Sanak",
"loginlanguagelabel": "Baso: $1",
"suspicious-userlogout": "Pamintaan Sanak untuak kalua log ditulak karano tampaknyo dikirim oleh paramban nan rusak atau proksi panyinggah.",
"pt-login": "Masuak log",
+ "pt-login-button": "Masuak log",
"pt-createaccount": "Buek akun",
"pt-userlogout": "Kalua log",
"php-mail-error-unknown": "Kasalahan nan indak jaleh dalam fungsi mail() PHP",
"preview": "Caliak",
"showpreview": "Pratonton",
"showdiff": "Parubahan",
- "anoneditwarning": "'''Ingek:''' Sanak alun masuak log.\nAlamat IP sanak tacatat pado riwayaik suntiangan laman ko.",
+ "anoneditwarning": "'''Ingek:''' Sanak alun masuak log.\nAlamat IP sanak tacatat pado riwayaik suntiangan laman ko. Kok Sanak <strong>[$1 log in]</strong> atau <strong>[$2 mambuek akun]</strong>, suantiang Sanak ka didistribusian kapado namo pangguno Sanak, sarato baragam kauntuangan lainnyo.",
"anonpreviewwarning": "''Sanak alun masuak log. Manyimpan laman akan manyababkan alamaik IP Sanak tacatat pado riwayat suntiangan laman iko.''",
"missingsummary": "'''Paringatan:''' Sanak indak mamasuakan ringkasan panyuntiangan. Jikok Sanak baliak manakan tombol Simpan, suntiangan Sanak akan disimpan tanpa ringkasan panyuntiangan.",
"missingcommenttext": "Masuakan komentar Sanak di bawah ko.",
"permissionserrorstext": "Sanak indak ado hak untuak malakuannyo dek {{PLURAL:$1|alasan}} barikuik:",
"permissionserrorstext-withaction": "Sanak indak punyo hak akses untuak $2, dek {{PLURAL:$1|alasan}} barikuik:",
"recreate-moveddeleted-warn": "'''Ingek: Sanak mambuek ulang suatu laman nan alah dihapuih.'''\n\nHarap ditimbang apo rancak malanjuikan suntiangan Sanak.\nBarikuik ko log pangapuihan jo pamindahan dari laman ko:",
- "moveddeleted-notice": "Laman ko alah dihapuih.\nSabagai reperensi, barikuik adolah log pangapuihan dan pamindahannyo.",
+ "moveddeleted-notice": "Laman ko alah dihapuih.\nSabagai referensi, barikuik adolah log pangapuihan jo pamindahannyo.",
"log-fulllog": "Liek saluruah log",
"edit-hook-aborted": "Suntiangan dibatalan samo kait parser\ntanpa ado katarangan.",
"edit-gone-missing": "Indak dapek mampabarui laman.\nMungkin alah dihapuih.",
"histlegend": "Bandiangan piliahan: Tandoi revisi untuak mambandiangan dan takan enter atau tombol di bawah.<br />\nContoh: '''({{int:cur}})''' = bedo jo versi tarakhia, '''({{int:last}})''' = bedo jo versi sabalunnyo, '''{{int:minoreditletter}}''' = suntiangan ketek.",
"history-fieldset-title": "Talusuri riwayaik",
"history-show-deleted": "Hanyo nan dihapuih",
- "histfirst": "Nan lamo",
- "histlast": "Nan baru",
+ "histfirst": "Nan paliang lamo",
+ "histlast": "Nan paliang baru",
"historysize": "({{PLURAL:$1|$1 bita}})",
"historyempty": "(kosong)",
"history-feed-title": "Riwayat revisi",
"shown-title": "Tampilkan $1 {{PLURAL:$1|hasil}} per laman",
"viewprevnext": "Caliak ($1 {{int:pipe-separator}} $2) ($3)",
"searchmenu-exists": "'''Ado laman nan banamo \"[[:$1]]\" pado wiki ko.'''",
- "searchmenu-new": "'''Buek laman \"[[:$1]]\" di wiki ko!'''",
+ "searchmenu-new": "<strong>Buek laman \"[[:$1]]\" di wiki ko!</strong> {{PLURAL:$2|0=|Caliak pulo laman nan ditamukan dari pancarian Sanal.|Caliak pulo hasia pancarian nan ditamukan.}}",
"searchprofile-articles": "Laman isi",
"searchprofile-images": "Multimedia",
"searchprofile-everything": "Sadonyo",
"searchrelated": "bakaitan",
"searchall": "sado",
"showingresults": "Di bawah ko dikaluaan sampai {{PLURAL:$1|'''$1''' hasil}}, dimulai dari #'''$2'''.",
+ "search-showingresults": "{{PLURAL:$4|Hasia <strong>$1</strong> dari <strong>$3</strong>|Hasia <strong>$1 - $2</strong> dari <strong>$3</strong>}}",
"search-nonefound": "Indak ado hasil nan cocok sasuai jo parmintaan",
"powersearch-legend": "Pencarian lanjut",
"powersearch-ns": "Mancari di ruangnamo:",
"action-writeapi": "manggunoan panulisan API",
"action-import": "impor laman ko dari wiki lain",
"nchanges": "$1 {{PLURAL:$1|parubahan}}",
+ "enhancedrc-history": "riwayaik",
"recentchanges": "Parubahan baru",
"recentchanges-legend": "Piliahan parubahan baru",
"recentchanges-summary": "Caliak parubahan tabaru pado wiki di laman ko.<br />\n;Patunjuak:(<span style=\"color:blue;\">bedo</span>) parubahan, (<span style=\"color:blue;\">sijarah</span>) riwayaik parubahan, '''B''' laman baru, '''b''' suntiangan bot, '''k''' suntiangan ketek, <span class=\"unpatrolled\">!</span> parubahan alun dipatroli,<br /><span style=\"color:green;\">'''(+ ''bita'')'''</span> isi laman batambah, <span style=\"color:red;\">(- ''bita'')</span> isi laman bakurang, (← Ikhtisar otomatih), (→ <span style=\"color:grey;\">Suntiangan bagian</span>)",
+ "recentchanges-noresult": "Indak ado parubahan dalam rantang wakatu ko nan sasuai jo kriteria.",
"recentchanges-feed-description": "Tamuan parubahan baru dalam umpan wiki ko",
"recentchanges-label-newpage": "Suntiangan ko mambuek laman baru",
"recentchanges-label-minor": "Iko suntiangan ketek",
"rcnotefrom": "Di bawah ko ado parubahan mulai dari '''$2''' (sampai '''$1''' parubahan).",
"rclistfrom": "Tunjuakan parubahan baru mulai dari tanggal $3 $2",
"rcshowhideminor": "$1 suntiangan ketek",
+ "rcshowhideminor-show": "Tunjuakan",
+ "rcshowhideminor-hide": "Suruakan",
"rcshowhidebots": "$1 bot",
+ "rcshowhidebots-show": "Tunjuakan",
+ "rcshowhidebots-hide": "Suruakan",
"rcshowhideliu": "$1 pangguno tadaftar",
+ "rcshowhideliu-show": "Tunjuakan",
+ "rcshowhideliu-hide": "Suruakan",
"rcshowhideanons": "$1 pangguno anon",
+ "rcshowhideanons-show": "Tunjuakan",
+ "rcshowhideanons-hide": "Suruakan",
"rcshowhidepatr": "$1 suntiangan tapatroli",
"rcshowhidemine": "$1 suntiangan denai",
+ "rcshowhidemine-show": "Tunjuakan",
+ "rcshowhidemine-hide": "Suruakan",
"rclinks": "Tunjuakkan $1 parubahan tabaru dalam $2 hari nan tarakhia",
"diff": "bedo",
"hist": "sijarah",
"imagelinks": "Panggunoan berkas",
"linkstoimage": "{{PLURAL:$1|Halaman|$1 halaman}} nan iko manggunoan berkas nan iko:",
"linkstoimage-more": "Labiah dari $1 {{PLURAL:$1|laman}} ado pautan ka berkas ko.\nDaftar barikuik manunjuakan {{PLURAL:$1|$1 laman jo pautan langsuang}} ka berkas ko.\nAdo juo tasadio [[Special:WhatLinksHere/$2|daftar langkoknyo]].",
- "nolinkstoimage": "Indak ado laman nan bapauik ka berkas ko.",
+ "nolinkstoimage": "Indak ado laman nan manggunokan berkas ko.",
"morelinkstoimage": "Caliak [[Special:WhatLinksHere/$1|pautan baliak]] ka berkas ko.",
"linkstoimage-redirect": "$1 (pangaliahan berkas) $2",
"duplicatesoffile": "Sabanyak {{PLURAL:$1|$1 berkas barikuik}} marupoan duplikat dari berkas ko ([[Special:FileDuplicateSearch/$2|rincian labiah lanjuik]]):",
"apisandbox": "Bak kasiak API",
"booksources": "Sumber buku",
"booksources-search-legend": "Cari di sumber buku",
+ "booksources-search": "Cari",
"specialloguserlabel": "Pangguno:",
"speciallogtitlelabel": "Target (judul atau pangguno):",
"log": "Log",
"contributions": "Jariah {{GENDER:$1|pangguno}}",
"contributions-title": "Jariah pangguno untuak $1",
"mycontris": "Jariah",
- "contribsub2": "Untuak $1 ($2)",
+ "anoncontribs": "Jariah",
+ "contribsub2": "Untuak {{GENDER:$3|$1}} ($2)",
"uctop": "kini",
"month": "Dari bulan (dan sabalunnyo):",
"year": "Dari taun (dan sabalunnyo):",
"sp-contributions-search": "Cari jariah",
"sp-contributions-username": "Alamaik IP atau namo pangguno:",
"sp-contributions-toponly": "Hanyo manampilan suntiangan nan tarakhia",
+ "sp-contributions-newonly": "Hanyo manampilan suntiangan nan tarakhia",
"sp-contributions-submit": "Cari",
"whatlinkshere": "Pautan baliak",
"whatlinkshere-title": "Laman nan takaik ka \"$1\"",
"importstart": "Mangimpor laman...",
"importnosources": "Indak ado sumber impor transwiki nan lah dibuek dan pamuatan riwayaik sacaro langsuang alah dinon-aktipan.",
"importlogpagetext": "Administrasi laman impor jo riwayaik panyuntiangannyo dari wiki lain.",
- "tooltip-pt-userpage": "Laman pangguno Sanak",
+ "tooltip-pt-userpage": "Laman {{GENDER:|pangguno Sanak}}",
"tooltip-pt-anonuserpage": "Laman pangguno IP Sanak",
- "tooltip-pt-mytalk": "Laman rundiang Sanak",
+ "tooltip-pt-mytalk": "Laman rundiang {{GENDER:|Sanak}}",
"tooltip-pt-anontalk": "Parundiangan tantang suntiangan dari IP ko",
- "tooltip-pt-preferences": "Pangaturan denai",
+ "tooltip-pt-preferences": "Piliahan {{GENDER:|Sanak}}",
"tooltip-pt-watchlist": "Daftar laman nan dipantau.",
- "tooltip-pt-mycontris": "Daftar jariah Sanak",
+ "tooltip-pt-mycontris": "Daftar jariah {{GENDER:|Sanak}}",
"tooltip-pt-login": "Sanak disaranan untuak masuak log; walaupun indak wajib",
"tooltip-pt-logout": "Kalua log",
"tooltip-pt-createaccount": "Sanak dianjuaan mambuek akun dan masuak log; walaupun hal iko indak aruih",
"tooltip-t-recentchangeslinked": "Parubahan baru laman nan bakaik jo laman ko",
"tooltip-feed-rss": "Umpan RSS untuak laman ko",
"tooltip-feed-atom": "Umpan Atom untuak laman ko",
- "tooltip-t-contributions": "Caliak daftar jariah pangguno ko",
+ "tooltip-t-contributions": "Daftar kontribusi {{GENDER:$1|pangguno iko}}",
"tooltip-t-emailuser": "Kirimkan surel pado pangguno ko",
"tooltip-t-upload": "Muek berkas",
"tooltip-t-specialpages": "Daftar kasado laman istimewa",
"logentry-newusers-autocreate": "Akun pangguno $1 alah {{GENDER:$2|dibuek}} sacaro otomatih",
"logentry-rights-rights": "$1 {{GENDER:$2|maubah}} kaanggotaan kalompok $3 dari $4 manjadi $5",
"logentry-rights-rights-legacy": "$1 {{GENDER:$2|maubah}} kaanggotaan kalompok $3",
+ "logentry-upload-upload": "$1 {{GENDER:$2|mangunggah}} $3",
"rightsnone": "(indak ado)",
"searchsuggest-search": "Cari {{SITENAME}}",
"searchsuggest-containing": "Barisi...",
"resetpass-abort-generic": "Generic error message shown on [[Special:ChangePassword]] when an extension aborts a password change from a hook.",
"resetpass-expired": "Generic error message shown on [[Special:ChangePassword]] when a user's password is expired",
"resetpass-expired-soft": "Generic warning message shown on [[Special:ChangePassword]] when a user needs to reset their password, but they are not prevented from logging in at this time",
+ "resetpass-validity": "Warning message shown on [[Special:ChangePassword]] when a user needs to reset their password, because their password is not valid.\n\nParameters:\n* $1 - error message",
"resetpass-validity-soft": "Warning message shown on [[Special:ChangePassword]] when a user needs to reset their password, because their password is not valid.\n\nRefers to {{msg-mw|authprovider-resetpass-skip-label}}.\n\nParameters:\n* $1 - error message",
"passwordreset": "Title of [[Special:PasswordReset]].\n{{Identical|Reset password}}",
"passwordreset-text-one": "Text on [[Special:PasswordReset]] that appears when there is only one way of resetting the password.\n\n{{msg-mw|Passwordreset-text-many}} will be used, when there are multiple ways of resetting the password.",
"blockedtext": "Text displayed to blocked users.\n\n\"email this user\" should be consistent with {{msg-mw|Emailuser}}.\n\nParameters:\n* $1 - the blocking sysop (with a link to his/her userpage)\n* $2 - the reason for the block\n* $3 - the current IP address of the blocked user\n* $4 - (Unused) the blocking sysop's username (plain text, without the link)\n* $5 - the unique numeric identifier of the applied autoblock\n* $6 - the expiry of the block\n* $7 - the intended target of the block (what the blocking user specified in the blocking form)\n* $8 - the timestamp when the block started\nSee also:\n* {{msg-mw|Grouppage-sysop}}\n* {{msg-mw|Autoblockedtext|notext=1}}\n* {{msg-mw|Systemblockedtext|notext=1}}",
"autoblockedtext": "Text displayed to automatically blocked users.\n\n\"email this user\" should be consistent with {{msg-mw|Emailuser}}.\n\nParameters:\n* $1 - the blocking sysop (with a link to his/her userpage)\n* $2 - the reason for the block (in case of autoblocks: {{msg-mw|autoblocker}})\n* $3 - the current IP address of the blocked user\n* $4 - (Unused) the blocking sysop's username (plain text, without the link). Use it for GENDER.\n* $5 - the unique numeric identifier of the applied autoblock\n* $6 - the expiry of the block\n* $7 - the intended target of the block (what the blocking user specified in the blocking form)\n* $8 - the timestamp when the block started\nSee also:\n* {{msg-mw|Grouppage-sysop}}\n* {{msg-mw|Blockedtext|notext=1}}\n* {{msg-mw|Systemblockedtext|notext=1}}",
"systemblockedtext": "Text displayed to requests blocked by MediaWiki configuration.\n\n\"email this user\" should be consistent with {{msg-mw|Emailuser}}.\n\nParameters:\n* $1 - (Unused) A dummy user attributed as the blocker, possibly as a link to a user page.\n* $2 - the reason for the block\n* $3 - the current IP address of the blocked user\n* $4 - (Unused) the dummy blocking user's username (plain text, without the link).\n* $5 - A short string indicating the type of system block.\n* $6 - the expiry of the block\n* $7 - the intended target of the block\n* $8 - the timestamp when the block started\nSee also:\n* {{msg-mw|Grouppage-sysop}}\n* {{msg-mw|Blockedtext|notext=1}}\n* {{msg-mw|Autoblockedtext|notext=1}}",
+ "actionblockedtext": "Text displayed when a user is blocked from perofmring an action, but no matching block for the user exists. This can happen if an extension forces a user to be blocked.",
"blockednoreason": "Substituted with <code>$2</code> in the following message if the reason is not given:\n* {{msg-mw|cantcreateaccount-text}}.\n{{Identical|No reason given}}",
"whitelistedittext": "Used as error message. Parameters:\n* $1 - a link to [[Special:UserLogin]] with {{msg-mw|loginreqlink}} as link description\n* $2 - an URL to the same\n\nSee also:\n* {{msg-mw|Nocreatetext}}\n* {{msg-mw|Uploadnologintext}}\n* {{msg-mw|Loginreqpagetext}}",
"confirmedittext": "Used as error message.",
"tog-watchdefault": "Men tahrirlagan sahifa va fayllar kuzatuv roʻyxatimga qoʻshilsin",
"tog-watchmoves": "Men nomini koʻchirgan sahifa va fayllar kuzatuv roʻyxatimga qoʻshilsin",
"tog-watchdeletion": "Men oʻchirgan sahifa va fayllarni kuzatuv roʻyxatimga qoʻsh",
- "tog-minordefault": "Sukut boʻyicha barcha tahrirlarimni «kichik tahrir» etib belgilash",
+ "tog-watchuploads": "Yuklagan fayllarim kuzatuv roʻyxatimga qoʻshilsin",
+ "tog-watchrollback": "Tezda qaytarish harakatini amalga oshirganimdan keyin oʻsha sahifa kuzatuv roʻyxatimga qoʻshilsin",
+ "tog-minordefault": "Sukut boʻyicha barcha tahrirlarimni «kichik tahrir» deb belgilansin",
"tog-previewontop": "Koʻrib chiqish imkoniyati tahrir oynasi tepasida boʻlsin",
- "tog-previewonfirst": "Tahrirlashga oʻtgandayoq koʻrib chiqishni boshlash",
+ "tog-previewonfirst": "Tahrirlashga oʻtgandayoq koʻrib chiqish boshlansin",
"tog-enotifwatchlistpages": "Kuzatuv roʻyxatimdagi sahifa yoki fayllar oʻzgartirilsa, menga bu haqda xat yuborilsin",
"tog-enotifusertalkpages": "Munozara sahifam oʻzgartirilsa, menga bu haqda xat yuborilsin",
- "tog-enotifminoredits": "Kichik tahrir qilinsa ham e-pochtamga bu haqda xat yuborilsin",
- "tog-enotifrevealaddr": "Xabar beruvchi xatlarda e-pochta manzilim koʻrsatilsin",
- "tog-shownumberswatching": "Sahifani kuzatuv roʻyxatiga olgan foydalanuvchilar sonini koʻrsatish",
- "tog-oldsig": "Joriy imzo:",
+ "tog-enotifminoredits": "Sahifa va fayllarga kichik oʻzgarish kiritilsa ham elektron pochtamga bu haqda xat yuborilsin",
+ "tog-enotifrevealaddr": "Xabar beruvchi xatlarda elektron pochta manzilim koʻrsatilsin",
+ "tog-shownumberswatching": "Sahifani kuzatuv roʻyxatiga qoʻshgan foydalanuvchilar soni koʻrsatilsin",
+ "tog-oldsig": "Joriy imzoingiz:",
"tog-fancysig": "Imzoni viki-belgi qilib koʻrsatish (avtomatik ishoratsiz)",
- "tog-uselivepreview": "Tez koʻrib chiqish",
- "tog-forceeditsummary": "Qisqa tavsif oynasi toʻldirilmagani haqida ogohlantirish koʻrsatish",
+ "tog-uselivepreview": "Oʻzgarishlarni sahifani yangilamasdan koʻrib chiqish",
+ "tog-forceeditsummary": "Qisqa tavsif oynasi toʻldirilmagani haqida ogohlantirish berilsin",
"tog-watchlisthideown": "Oʻz tahrirlarim kuzatuv roʻyxatimda koʻrsatilmasin",
"tog-watchlisthidebots": "Botlar qilgan tahrirlar kuzatuv roʻyxatimda koʻrsatilmasin",
"tog-watchlisthideminor": "Kichik tahrirlar kuzatuv roʻyxatimda koʻrsatilmasin",
"tog-watchlisthideliu": "Tizimga kirgan foydalanuvchilar tahrirlari kuzatuv roʻyxatimda koʻrsatilmasin",
- "tog-watchlisthideanons": "Anonim foydalanuvchilar tahrirlari kuzatuv roʻyxatimda koʻrsatilmasin",
+ "tog-watchlisthideanons": "Anonimlarning tahrirlari kuzatuv roʻyxatimda koʻrsatilmasin",
"tog-watchlisthidepatrolled": "Tekshirilgan tahrirlar kuzatuv roʻyxatimda koʻrsatilmasin",
+ "tog-watchlisthidecategorization": "Sahifalarning turkumlari yashirilsin",
"tog-ccmeonemails": "Boshqa ishtirokchilarga yozgan xatimning nusxasi oʻzimga yuborilsin",
"tog-diffonly": "Versiyalar taqqoslanayotganda, pastda sahifa matni koʻrsatilmasin",
- "tog-showhiddencats": "Yashirin turkumlarni koʻrsatish",
- "tog-norollbackdiff": "Tahrir qaytarilganda, versiyalar taqqosi koʻrsatilmasin",
- "tog-useeditwarning": "Oʻzgarishlarni saqlamay sahifadan chiqib ketayotganim haqida ogohlantir",
- "tog-prefershttps": "Doim himoyalangan holda kirish",
+ "tog-showhiddencats": "Yashirin turkumlar koʻrsatilsin",
+ "tog-norollbackdiff": "Biron tahrir tezda qaytarilsa, versiyalar taqqosini koʻrsatishning hojati yoʻq",
+ "tog-useeditwarning": "Oʻzgarishlarni saqlamay sahifadan chiqib ketayotganim haqida ogohlantirish berilsin",
+ "tog-prefershttps": "Tizimga kirganimdan keyin doim himoyalangan aloqadan foydalanilsin",
"underline-always": "Har doim",
"underline-never": "Hech qachon",
- "underline-default": "Bezak mavzusi yoki brauzer andozasi boʻyicha",
+ "underline-default": "Brauzer sozlamalaridan foydalanilsin",
"editfont-style": "Tahrirlash maydonidagi shrift turi:",
"editfont-monospace": "Teng enli shrift (Monospaced)",
"editfont-sansserif": "Kertiksiz shrift (Sans-serif)",
"category_header": "„$1“ turkumidagi sahifalar",
"subcategories": "Ostturkumlar",
"category-media-header": "„$1“ turkumidagi fayllar",
- "category-empty": "''Ushbu turkumda hozircha sahifa yoki fayllar yoʻq.''",
+ "category-empty": "<em>Ushbu turkumda hozircha sahifa yoki fayllar yoʻq.</em>",
"hidden-categories": "{{PLURAL:$1|Yashirin turkum}}",
"hidden-category-category": "Yashirin turkumlar",
"category-subcat-count": "{{PLURAL:$2|Ushbu turkumda faqat bitta ostturkum mavjud.|Quyida ushbu turkumga kiruvchi $2 ta ostturkumdan $1 tasi koʻrsatilgan.}}",
"mytalk": "Munozara",
"anontalk": "Ushbu IP-manzil munozarasi",
"navigation": "Saytda harakatlanish",
- "and": " va",
+ "and": " va",
"faq": "TSS",
"actions": "Amallar",
"namespaces": "Nomfazolar",
"viewsourcelink": "manbasini koʻrish",
"editsectionhint": "Boʻlimni tahrirlash: $1",
"toc": "Mundarija",
- "showtoc": "koʻrsatish",
+ "showtoc": "koʻrsat",
"hidetoc": "yashirish",
"collapsible-collapse": "Yigʻish",
"collapsible-expand": "Yoyish",
"viewsource-title": "$1 sahifasining manbasini koʻrish",
"actionthrottled": "Tezlik cheklovi",
"protectedpagetext": "Bu sahifa tahrirlash va boshqa oʻzgarishlar kiritishdan himoyalangan.",
- "viewsourcetext": "Siz bu sahifaning manbasini koʻrishingiz va uni nusxasini olishingiz mumkin:",
+ "viewsourcetext": "Siz bu sahifaning ichki kodini koʻrishingiz va undan nusxa olishingiz mumkin:",
"protectedinterface": "Ushbu sahifada dasturiy taʼminot interfeysi xabari mavjud. Bezoriliklardan saqlash uchun uni oʻzgartirish taʼqiqlangan.\nUshbu xabar tarjimasini qoʻshish yoki oʻzgartirish uchun, iltimos, MediaWikining [https://translatewiki.net/ translatewiki.net] mahalliylashtirish saytidan foydalaning.",
"editinginterface": "<strong>Eʼtibor bering:</strong> Siz interfeys matnini aks ettiruvchi sahifani tahrirlamoqdasiz.\nUning oʻzgartirilishi boshqa foydalanuvchilar uchun ham interfeys oʻzgarishiga olib keladi.",
"translateinterface": "Ushbu xabar tarjimasini qoʻshish yoki oʻzgartirish uchun, iltimos, MediaWikining [https://translatewiki.net/ translatewiki.net] mahalliylashtirish saytidan foydalaning.",
"subject": "Mavzu/sarlavha",
"minoredit": "Bu kichik tahrir",
"watchthis": "Sahifani kuzatish",
- "savearticle": "Saqla",
- "publishpage": "Sahifani chop et",
- "publishchanges": "Oʻzgarishlarni chop et",
+ "savearticle": "Chop etish",
+ "savechanges": "Oʻzgarishlarni saqlash",
+ "publishpage": "Sahifani chop etish",
+ "publishchanges": "Oʻzgarishlarni chop etish",
"preview": "Ko‘rib chiqish",
"showpreview": "Koʻrib chiqish",
"showdiff": "Kiritilgan o‘zgarishlar",
"rev-deleted-user": "(muallif nomi oʻchirilgan)",
"rev-deleted-event": "(jurnal tafsilotlari o‘chirildi)",
"rev-delundel": "koʻrsatish/yashirish",
- "rev-showdeleted": "koʻrsatish",
+ "rev-showdeleted": "koʻrsat",
"revdelete-show-file-submit": "Ha",
"revdelete-confirm": "Iltimos, haqiqatdan ham shu harakatni amalga oshirmoqchiligingizni, uning oqibatlarini tushunib turganingizni va harakatingiz [[{{MediaWiki:Policy-url}}|qoidalarga]] asosanlanganini tasdiqlang.",
"revdelete-hide-text": "Sahifaning ushbu versiyasi matnini yashirish",
"prefs-signature": "Imzo",
"prefs-dateformat": "Sana formati",
"prefs-timeoffset": "Vaqt farqi",
- "prefs-advancedediting": "Qoʻshimcha moslamalar",
+ "prefs-advancedediting": "Asosiy bandlar",
+ "prefs-editor": "Tahrirlagich",
"prefs-advancedrc": "Qoʻshimcha moslamalar",
"prefs-advancedrendering": "Qoʻshimcha moslamalar",
"prefs-advancedsearchoptions": "Qoʻshimcha moslamalar",
"userrights": "Huquqlarini oʻzgartirish",
"userrights-lookup-user": "Foydalanuvchini tanlash",
"userrights-user-editname": "Foydalanuvchi nomi:",
- "editusergroup": "Shu foydalanuvchi huquqlarini oʻzgartirish",
+ "editusergroup": "Qaysi guruhlarga aʼzo ekanligini koʻrish",
"editinguser": "{{GENDER:$1|Foydalanuvchi}} <strong>[[User:$1|$1]]</strong> $2 huquqlarini oʻzgartirish",
"userrights-editusergroup": "Guruhlardagi aʼzoligini oʻzgartirish",
"saveusergroups": "Oʻzgarishlarni saqlash",
"newuserlogpage": "Foydalanuvchilarni roʻyxatga olish qaydlari",
"newuserlogpagetext": "Yaqinda roʻyxatdan oʻtgan foydalanuvchilar roʻyxati",
"rightslog": "Foydalanuvchi huquqlari koʻrsatilgan qaydlar",
- "rightslogtext": "Foydalanuvchi huquqlarini oʻzgartirish qaydlari.",
+ "rightslogtext": "Bu sahifada foydalanuvchilarning huquqlarini oʻzgartirish qaydlari koʻrsatilgan.",
"action-edit": "ushbu sahifani tahrirlash",
"action-move": "bu sahifani koʻchirish",
"action-move-subpages": "Bu sahifani va uning ostsahifalarini koʻchirish",
"recentchanges-label-plusminus": "Sahifa vazni qanchaga oʻzgargani (bayt)",
"recentchanges-legend-heading": "<strong>Izoh:</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|alohida roʻyxat]])",
+ "recentchanges-submit": "Koʻrsat",
+ "rcfilters-activefilters-show": "Koʻrsat",
"rcnotefrom": "Quyida <strong>$3, $4</strong> dan keyin sodir boʻlgan oʻzgarishlar koʻrsatilgan (oxirgi <strong>$1</strong> tasi).",
"rclistfrom": "$3, $2 dan keyin sodir boʻlgan oʻzgarishlarni koʻrsat",
"rcshowhideminor": "Kichik tahrirlarni $1",
- "rcshowhideminor-show": "koʻrsat",
+ "rcshowhideminor-show": "Koʻrsat",
"rcshowhideminor-hide": "yashir",
"rcshowhidebots": "Botlarni $1",
- "rcshowhidebots-show": "koʻrsat",
+ "rcshowhidebots-show": "Koʻrsat",
"rcshowhidebots-hide": "yashir",
"rcshowhideliu": "Roʻyxatdan oʻtganlarni $1",
"rcshowhideliu-show": "koʻrsat",
"rcshowhideliu-hide": "yashir",
"rcshowhideanons": "Anonimlarni $1",
- "rcshowhideanons-show": "koʻrsat",
+ "rcshowhideanons-show": "Koʻrsat",
"rcshowhideanons-hide": "yashir",
"rcshowhidepatr": "Tekshirilgan tahrirlarni $1",
+ "rcshowhidepatr-show": "Koʻrsat",
"rcshowhidepatr-hide": "yashir",
"rcshowhidemine": "Oʻz tahrirlarimni $1",
- "rcshowhidemine-show": "koʻrsat",
+ "rcshowhidemine-show": "Koʻrsat",
"rcshowhidemine-hide": "yashir",
"rclinks": "Oxirgi $2 kun ichida sodir boʻlgan $1 ta oʻzgarish koʻrsatildi",
"diff": "farq",
"hist": "tarix",
- "hide": "yashir",
- "show": "koʻrsat",
+ "hide": "Yashir",
+ "show": "Koʻrsat",
"minoreditletter": "k",
"newpageletter": "Y",
"boteditletter": "b",
"statistics-header-users": "Foydalanuvchilar statistikasi",
"statistics-articles": "Maqolalar",
"statistics-pages": "Sahifalar",
- "statistics-pages-desc": "Ushbu vikidagi barcha sahifalar, jumladan munozara, yoʻnaltirish va hk.",
+ "statistics-pages-desc": "Ushbu vikidagi barcha sahifalar, shu jumladan munozara sahifalari, qayta yoʻnaltiruvchi va boshqa sahifalar",
"statistics-files": "Yuklangan fayllar",
"statistics-edits": "{{SITENAME}}dagi tahrirlarning umumiy soni",
"statistics-edits-average": "Oʻrtacha tahrirlar soni (sahifa boshiga)",
"pageswithprop-prop": "Xossa nomi:",
"pageswithprop-submit": "Oʻtish",
"brokenredirects-edit": "tahrirlash",
+ "withoutinterwiki-submit": "Koʻrsat",
"nbytes": "$1 {{PLURAL:$1|bayt}}",
"ncategories": "$1 {{PLURAL:$1|turkum|turkumlar}}",
"nmembers": "$1 {{PLURAL:$1|ta sahifa}}",
"wantedcategories": "Talab qilinayotgan turkumlar",
"mostcategories": "Eng koʻp turkumli sahifalar",
"prefixindex": "Prefiksli barcha sahifalar",
+ "prefixindex-submit": "Koʻrsat",
"prefixindex-strip": "Natijalar roʻyxatida prefiks koʻrsatilmasin",
"protectedpages": "Himoyalangan sahifalar",
"listusers": "Foydalanuvchilar roʻyxati",
"usercreated": "$1, $2 da {{GENDER:$3|roʻyxatdan oʻtgan}}",
"newpages": "Yangi sahifalar",
+ "newpages-submit": "Koʻrsat",
"move": "Ko‘chirish",
"movethispage": "Bu sahifani koʻchirish",
"pager-newer-n": "{{PLURAL:$1|yangiroq 1|yangiroq $1}}",
"specialloguserlabel": "Ijrochi:",
"speciallogtitlelabel": "Moʻljal:",
"log": "Qaydlar",
+ "logeventslist-submit": "Koʻrsat",
"all-logs-page": "Barcha ochiq qaydlar",
"alllogstext": "{{SITENAME}}dagi barcha jurnallar roʻyxati.\nNatijalarni jurnal nomi, foydalanuvchi nomi (harflar katta-kichikligi inobatga olinadi) yoki sahifa nomi boʻyicha saralashingiz mumkin.\n* Biror foydalanuvchi amalga oshirgan qaydni topish uchun uning foydalanuvchi nomini „Ijrochi“ oynasiga kiriting.\n* Biror foydalanuvchi yoki sahifaga nisbatan amalga oshirilgan qaydni topish uchun ulardan birining nomini „Moʻljal“ oynasiga kiriting.",
"logempty": "Talabga mos yozuvlar mavjud emas.",
"allpages-hide-redirects": "Yoʻnaltirishlarni yashirish",
"cachedspecial-refresh-now": "Oxirgi versiyasini koʻrish",
"categories": "Turkumlar",
+ "categories-submit": "Koʻrsat",
"categoriespagetext": "Quyidagi {{PLURAL:$1|turkumda|turkumlarda}} sahifa yoki media-fayllar mavjud.\n[[Special:UnusedCategories|Ishlatilmayotgan turkumlar]] bu yerda koʻrsatilmaydi.\nShuningdek qarang: [[Special:WantedCategories|talab qilinayotgan turkumlar]].",
"categoriesfrom": "Quyidagidan boshlanuvchi turkumlarni koʻrsatish:",
"deletedcontributions": "Foydalanuvchining o‘chirilgan hissasi",
"linksearch-ok": "Qidirish",
"linksearch-line": "$2 ichidan $1 ga havola",
"listusersfrom": "Quyidagidan boshlanuvchi foydalanuvchilarni koʻrsatish:",
- "listusers-submit": "Koʻrsatish",
+ "listusers-submit": "Koʻrsat",
"listusers-noresult": "Foydalanuvchilar topilmadi.",
"listusers-blocked": "(chetlashtirilgan)",
"activeusers": "Faol foydalanuvchilar roʻyxati",
"wlheader-showupdated": "Siz oxirgi marta kirganingizdan keyin oʻzgartirilgan sahifalar '''qalin''' yozuv bilan ajratib koʻrsatilgan.",
"wlnote": "Quyida oxirgi $2 soat ichida sodir boʻlgan {{PLURAL:$1|oxirgi oʻzgarish|<strong>$1</strong> ta oʻzgarishlar}} koʻrsatilgan. $3, $4.",
"wlshowlast": "Oxirgi $1 soatdagi $2 kundagi tahrirlarni koʻrsatish",
+ "watchlist-submit": "Koʻrsat",
"watchlist-options": "Kuzatuv roʻyxati moslamalari",
"watching": "Kuzatish...",
"unwatching": "Kuzatuv roʻyxatidan oʻchirilmoqda...",
"delete-confirm": "$1 — oʻchirish",
"delete-legend": "Sahifani o‘chirish",
"historywarning": "<strong>Diqqat:</strong> Siz oʻchirmoqchi boʻlayotgan sahifaning tarixida $1 ta {{PLURAL:$1|versiyasi}} bor:",
+ "historyaction-submit": "Koʻrsat",
"confirmdeletetext": "Siz ushbu sahifani va uning tarixini butunlay oʻchirib tashlamoqchi boʻlyapsiz. Iltimos, [[Special:Whatlinkshere/{{FULLPAGENAMEE}}|bogʻlangan sahifalar]] bilan tanishib chiqishni unutmang.",
"actioncomplete": "Bajarildi",
"actionfailed": "Jarayon amalga oshmadi",
"contributions-title": "{{GENDER:$1|Foydalanuvchi}} $1 hissasi",
"mycontris": "Hissam",
"anoncontribs": "Qoʻshilgan hissa",
- "contribsub2": "$1 uchun ($2)",
+ "contribsub2": "$1ning tahrirlari ($2)",
"nocontribs": "Belgilangan shartlarga muvofiq oʻzgarishlar topilmadi.",
"uctop": "joriy",
"month": "Oydan (va avvalroq)",
"year": "Yildan (va avvalroq)",
+ "date": "Shu sanadan avvalroq:",
"sp-contributions-newbies": "Faqatgina yangi foydalanuvchilarning hissalarini koʻrsat",
"sp-contributions-newbies-sub": "Yangi hisob yozuvlaridan",
"sp-contributions-newbies-title": "Yangi hisob yozuvlarining hissalari",
"tooltip-ca-nstab-category": "Turkum sahifasini koʻrish",
"tooltip-minoredit": "Kichik o‘zgartirish sifatida belgilash",
"tooltip-save": "Oʻzgarishlarni saqlash",
+ "tooltip-publish": "Siz kiritgan oʻzgarishlarni chop etish",
"tooltip-preview": "Oʻzgarishlarni koʻrib chiqish; Iltimos, saqlashdan oldin undan foydalaning!",
"tooltip-diff": "Matnga qanday oʻzgarishlar kiritganligingizni koʻrish.",
"tooltip-compareselectedversions": "Bu sahifaning ikki tanlangan versiyalari orasidagi farqni koʻrish.",
"watchlisttools-raw": "Kuzatuv roʻyxatimni tahrirlash",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|munozara]])",
"duplicate-defaultsort": "'''Diqqat:''' \"$2\" boshlang'ich saralash kaliti oldingi \"$1\" boshlang'ich saralash kalitini qayta aniqlayapti.",
+ "version": "Versiyasi",
"version-specialpages": "Maxsus sahifalar",
+ "version-ext-colheader-version": "Versiyasi",
+ "version-software-version": "Versiyasi",
+ "version-libraries-version": "Versiyasi",
"specialpages": "Maxsus sahifalar",
"tag-filter": "[[Special:Tags|Nishonlar]] filtri:",
"tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Teg|Teglar}}]]: $2",
"special-characters-group-khmer": "Kxmer",
"special-characters-title-emdash": "uzun tire",
"special-characters-title-minus": "minus belgisi",
- "mw-widgets-abandonedit": "Siz haqiqatdan ham oʻzgarishlarni saqlamasdan koʻrish tartibiga oʻtishni xohlaysizmi?"
+ "mw-widgets-abandonedit": "Siz haqiqatdan ham oʻzgarishlarni saqlamasdan koʻrish tartibiga oʻtishni xohlaysizmi?",
+ "log-action-filter-block": "Chetlatish turi:",
+ "log-action-filter-rights": "Huquqlarni oʻzgartirish turi:",
+ "log-action-filter-all": "Barchasi",
+ "log-action-filter-block-block": "Chetlatish",
+ "log-action-filter-block-reblock": "Chetlatish turini oʻzgartirish",
+ "log-action-filter-block-unblock": "Chetlatishni bekor qilish",
+ "log-action-filter-rights-rights": "Qoʻlda kiritilgan oʻzgarish",
+ "authprovider-resetpass-skip-label": "Qoldirib ketish"
}
"booksources-search": "זוכן",
"booksources-text": "אונטן איז א ליסטע פון סייטס וואס פֿארקויפֿן נייע און גענוצטע ביכער און האבן אויך נאך אינפֿארמאציע וועגן די ביכער וואס איר זוכט:",
"booksources-invalid-isbn": "דאָס געגעבענע ISBN זעט נישט אויס צו זיין גילטיק; קאנטראלירט פֿאַר גרײַזן בײַם קאפּירן פון דעם ערשטיקן מקור.",
+ "magiclink-tracking-rfc": "בלעטער וואס ניצן מאגישע RFC-לינקען",
+ "magiclink-tracking-pmid": "בלעטער וואס ניצן מאגישע PMID-לינקען",
+ "magiclink-tracking-isbn": "בלעטער וואס ניצן מאגישע ISBN-לינקען",
"specialloguserlabel": "אויספֿירער:",
"speciallogtitlelabel": "ציל (טיטל אדער {{ns:user}}:באניצער־נאמען פאר א באניצער):",
"log": "לאגביכער",
"edit-gone-missing": "不能更新页面。\n它可能刚刚被删除。",
"edit-conflict": "编辑冲突。",
"edit-no-change": "因为没有文字更改,您的编辑已被忽略。",
+ "edit-slots-cannot-add": "下列{{PLURAL:$1|栏位|栏位}}在此不受支持:$2。",
+ "edit-slots-cannot-remove": "下列{{PLURAL:$1|栏位|栏位}}是必需的且无法被移除:$2。",
"postedit-confirmation-created": "页面已创建。",
"postedit-confirmation-restored": "页面已恢复。",
"postedit-confirmation-saved": "您的编辑已保存。",
$( '.config-help-field-data' ).hide()
.closest( '.config-help-field-container' ).find( '.config-help-field-hint' )
.show()
- .click( function () {
+ .on( 'click', function () {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-slide
$( this ).closest( '.config-help-field-container' ).find( '.config-help-field-data' )
.slideToggle( 'fast' );
} );
$( document.getElementById( $( this ).attr( 'rel' ) ) ).hide();
} );
$( document.getElementById( $( '.dbRadio:checked' ).attr( 'rel' ) ) ).show();
- $( '.dbRadio' ).click( function () {
+ $( '.dbRadio' ).on( 'click', function () {
var $checked = $( '.dbRadio:checked' ),
$wrapper = $( document.getElementById( $checked.attr( 'rel' ) ) );
if ( $wrapper.is( ':hidden' ) ) {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-animate-toggle
$( '.dbWrapper' ).hide( 'slow' );
+ // eslint-disable-next-line jquery/no-animate-toggle
$wrapper.show( 'slow' );
}
} );
} );
// Show/hide Creative Commons thingy
- $( '.licenseRadio' ).click( function () {
+ $( '.licenseRadio' ).on( 'click', function () {
var $wrapper = $( '#config-cc-wrapper' );
if ( $( '#config__LicenseCode_cc-choose' ).is( ':checked' ) ) {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-animate-toggle
$wrapper.show( 'slow' );
} else {
+ // eslint-disable-next-line jquery/no-animate-toggle
$wrapper.hide( 'slow' );
}
} );
// Show/hide random stuff (email, upload)
- $( '.showHideRadio' ).click( function () {
+ $( '.showHideRadio' ).on( 'click', function () {
var $wrapper = $( '#' + $( this ).attr( 'rel' ) );
if ( $( this ).is( ':checked' ) ) {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-animate-toggle
$wrapper.show( 'slow' );
} else {
+ // eslint-disable-next-line jquery/no-animate-toggle
$wrapper.hide( 'slow' );
}
} );
- $( '.hideShowRadio' ).click( function () {
+ $( '.hideShowRadio' ).on( 'click', function () {
var $wrapper = $( '#' + $( this ).attr( 'rel' ) );
if ( $( this ).is( ':checked' ) ) {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-animate-toggle
$wrapper.hide( 'slow' );
} else {
+ // eslint-disable-next-line jquery/no-animate-toggle
$wrapper.show( 'slow' );
}
} );
}
// Enable/disable "other" textboxes
- $( '.enableForOther' ).click( function () {
+ $( '.enableForOther' ).on( 'click', function () {
var $textbox = $( document.getElementById( $( this ).attr( 'rel' ) ) );
// FIXME: Ugh, this is ugly
if ( $( this ).val() === 'other' ) {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-slide
$textbox.prop( 'readonly', false ).closest( '.config-block' ).slideDown( 'fast' );
} else {
+ // eslint-disable-next-line jquery/no-slide
$textbox.prop( 'readonly', true ).closest( '.config-block' ).slideUp( 'fast' );
}
} );
$( '#config_wgSitename' ).on( 'keyup change', syncText ).each( syncText );
// Show/Hide memcached servers when needed
- $( 'input[name$="config__MainCacheType"]' ).change( function () {
+ $( 'input[name$="config__MainCacheType"]' ).on( 'change', function () {
var $memc = $( '#config-memcachewrapper' );
if ( $( 'input[name$="config__MainCacheType"]:checked' ).val() === 'memcached' ) {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-animate-toggle
$memc.show( 'slow' );
} else {
+ // eslint-disable-next-line jquery/no-animate-toggle
$memc.hide( 'slow' );
}
} );
},
"devDependencies": {
"deepmerge": "1.3.2",
- "eslint-config-wikimedia": "0.9.0",
+ "eslint-config-wikimedia": "0.10.0",
"grunt": "1.0.3",
"grunt-banana-checker": "0.6.0",
"grunt-contrib-copy": "1.0.0",
}
// Cancel selection
- } ).mousedown( function () {
+ } ).on( 'mousedown', function () {
if ( config.cancelSelection ) {
this.onselectstart = function () {
return false;
var prevCheckbox = null,
$box = this;
// When our boxes are clicked..
- $box.click( function ( e ) {
+ $box.on( 'click', function ( e ) {
// And one has been clicked before...
if ( prevCheckbox !== null && e.shiftKey ) {
// Check or uncheck this one and all in-between checkboxes,
}
}
+ // eslint-disable-next-line jquery/no-animate-toggle
$containers.toggle( action === 'expand' );
hookCallback();
}
// Only fetch if the value in the textbox changed and is not empty, or if the results were hidden
// if the textbox is empty then clear the result div, but leave other settings intouched
if ( val.length === 0 ) {
+ // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
context.data.prevText = '';
} else if (
if ( context.data !== undefined ) {
if ( context.data.$textbox.val().length === 0 ) {
// Hide the div when no suggestion exist
+ // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
} else {
// Rebuild the suggestions list
.addClass( 'suggestions-result' )
.attr( 'rel', i )
.data( 'text', context.config.suggestions[ i ] )
- .mousemove( function () {
+ .on( 'mousemove', function () {
context.data.selectedWithMouse = true;
$.suggestions.highlight(
context,
break;
// Escape
case 27:
+ // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
$.suggestions.restore( context );
$.suggestions.cancel( context );
case 13:
preventDefault = wasVisible;
selected = context.data.$container.find( '.suggestions-result-current' );
+ // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
if ( selected.length === 0 || context.data.selectedWithMouse ) {
// If nothing is selected or if something was selected with the mouse
// Can't use click() because the container div is hidden when the
// textbox loses focus. Instead, listen for a mousedown followed
// by a mouseup on the same div.
- .mousedown( function ( e ) {
+ .on( 'mousedown', function ( e ) {
context.data.mouseDownOn = $( e.target ).closest( '.suggestions-results .suggestions-result' );
} )
- .mouseup( function ( e ) {
+ .on( 'mouseup', function ( e ) {
var $result = $( e.target ).closest( '.suggestions-results .suggestions-result' ),
$other = context.data.mouseDownOn;
// This will hide the link we're just clicking on, which causes problems
// when done synchronously in at least Firefox 3.6 (T64858).
setTimeout( function () {
+ // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
- }, 0 );
+ } );
}
// Always bring focus to the textbox, as that's probably where the user expects it
// if they were just typing.
// Can't use click() because the container div is hidden when the
// textbox loses focus. Instead, listen for a mousedown followed
// by a mouseup on the same div.
- .mousedown( function ( e ) {
+ .on( 'mousedown', function ( e ) {
context.data.mouseDownOn = $( e.target ).closest( '.suggestions-special' );
} )
- .mouseup( function ( e ) {
+ .on( 'mouseup', function ( e ) {
var $special = $( e.target ).closest( '.suggestions-special' ),
$other = context.data.mouseDownOn;
// This will hide the link we're just clicking on, which causes problems
// when done synchronously in at least Firefox 3.6 (T64858).
setTimeout( function () {
+ // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
- }, 0 );
+ } );
}
// Always bring focus to the textbox, as that's probably where the user expects it
// if they were just typing.
context.data.$textbox.focus();
} )
- .mousemove( function ( e ) {
+ .on( 'mousemove', function ( e ) {
context.data.selectedWithMouse = true;
$.suggestions.highlight(
context, $( e.target ).closest( '.suggestions-special' ), false
$( this )
// Stop browser autocomplete from interfering
.attr( 'autocomplete', 'off' )
- .keydown( function ( e ) {
+ .on( 'keydown', function ( e ) {
// Store key pressed to handle later
context.data.keypressed = e.which;
context.data.keypressedCount = 0;
} )
- .keypress( function ( e ) {
+ .on( 'keypress', function ( e ) {
context.data.keypressedCount++;
+ // eslint-disable-next-line jquery/no-event-shorthand
$.suggestions.keypress( e, context, context.data.keypressed );
} )
- .keyup( function ( e ) {
+ .on( 'keyup', function ( e ) {
// The keypress event is fired when a key is pressed down and that key normally
// produces a character value. We also want to handle some keys that don't
// produce a character value so we also attach to the keydown/keyup events.
e.which === context.data.keypressed &&
allowed.indexOf( e.which ) !== -1
) {
+ // eslint-disable-next-line jquery/no-event-shorthand
$.suggestions.keypress( e, context, context.data.keypressed );
}
} )
- .blur( function () {
+ .on( 'blur', function () {
// When losing focus because of a mousedown
// on a suggestion, don't hide the suggestions
if ( context.data.mouseDownOn.length > 0 ) {
return;
}
+ // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
$.suggestions.cancel( context );
} );
}
isSample = false;
- $( this ).focus();
+ $( this ).trigger( 'focus' );
if ( options.selectionStart !== undefined ) {
$( this ).textSelection( 'setSelection', { start: options.selectionStart, end: options.selectionEnd } );
}
} );
// Add form submission handler
- $( '#editform' ).submit( function () {
+ $( '#editform' ).on( 'submit', function () {
allowCloseWindow.release();
} );
} );
if ( scrollTop.value ) {
editBox.scrollTop = scrollTop.value;
}
- $editForm.submit( function () {
+ $editForm.on( 'submit', function () {
scrollTop.value = editBox.scrollTop;
} );
}
// Can't use fadeTo because it calls show(), and we might want to keep some elements hidden
// (e.g. empty #catlinks)
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-animate
$copyElements.animate( { opacity: 0.4 }, 'fast' );
api = new mw.Api();
.append( $( '<a>' )
.attr( {
href: mw.util.getUrl( template.title ),
- 'class': ( template.exists ? '' : 'new' )
+ class: ( template.exists ? '' : 'new' )
} )
.text( template.title )
);
mw.hook( 'wikipage.editform' ).fire( $editform );
} ).always( function () {
$spinner.hide();
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-animate
$copyElements.animate( {
opacity: 1
}, 'fast' );
if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) && mw.config.get( 'skin' ) === 'vector' ) {
$( '.portal:last' ).after(
$( '<div>' ).attr( {
- 'class': 'portal',
+ class: 'portal',
id: 'p-lang',
role: 'navigation',
'aria-labelledby': 'p-lang-label'
return true;
}
- $lis.find( 'input[name="diff"], input[name="oldid"]' ).click( updateDiffRadios );
+ $lis.find( 'input[name="diff"], input[name="oldid"]' ).on( 'click', updateDiffRadios );
// Set initial state
updateDiffRadios();
// Ideally we'd use e.target instead of $historySubmitter, but e.target points
// to the form element for submit actions, so.
- $historyCompareForm.find( '.historysubmit' ).click( function () {
+ $historyCompareForm.find( '.historysubmit' ).on( 'click', function () {
$historySubmitter = $( this );
} );
// Without the cloning we'd be changing the real form, which is slower, could make
// the page look broken for a second in slow browsers and might show the form broken
// again when coming back from a "next" page.
- $historyCompareForm.submit( function ( e ) {
+ $historyCompareForm.on( 'submit', function ( e ) {
var $copyForm, $copyRadios, $copyAction;
if ( $historySubmitter ) {
$copyForm.find( ':submit' ).remove();
}
- // IE7 doesn't do submission from an off-DOM clone, so insert hidden into document first
+ // Firefox requires the form to be attached, so insert hidden into document first
// Also remove potentially conflicting id attributes that we don't need anyway
$copyForm
.css( 'display', 'none' )
.find( '[id]' ).removeAttr( 'id' )
.end()
.insertAfter( $historyCompareForm )
- .submit();
+ .trigger( 'submit' );
e.preventDefault();
return false; // Because the submit is special, return false as well.
$a = $( '#ca-edit a' );
// Not every page has an edit link (T59713)
if ( $a.length ) {
+ // eslint-disable-next-line jquery/no-event-shorthand
$a.get( 0 ).click();
}
}
}
$popup = $( '<div>' ).addClass( 'postedit mw-notification' ).append( $content )
- .click( function () {
+ .on( 'click', function () {
clearTimeout( timeoutId );
fadeOutConfirmation();
} );
if ( e.target.nodeName.toLowerCase() !== 'a' ) {
// Trigger native HTMLElement click instead of opening URL (T45052)
e.preventDefault();
+ // eslint-disable-next-line jquery/no-event-shorthand
$edit.get( 0 ).click();
}
} );
}
} );
tokenPromise.done( function () {
- $form.submit();
+ $form.trigger( 'submit' );
} );
} );
$checkboxes.prop( 'checked', check );
}
- $( '.mw-checkbox-all' ).click( function () {
+ $( '.mw-checkbox-all' ).on( 'click', function () {
selectAll( true );
} );
- $( '.mw-checkbox-none' ).click( function () {
+ $( '.mw-checkbox-none' ).on( 'click', function () {
selectAll( false );
} );
- $( '.mw-checkbox-invert' ).click( function () {
+ $( '.mw-checkbox-invert' ).on( 'click', function () {
$checkboxes.prop( 'checked', function ( i, val ) {
return !val;
} );
hovzer.$.append( this.$container );
hovzer.update();
- $( '.mw-debug-panelink' ).click( this.switchPane );
+ $( '.mw-debug-panelink' ).on( 'click', this.switchPane );
},
/**
// Hide the current pane
if ( requestedPaneId === currentPaneId ) {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-slide
$currentPane.slideUp( updateHov );
debug.$container.data( 'currentPane', null );
return;
debug.$container.data( 'currentPane', requestedPaneId );
if ( currentPaneId === undefined || currentPaneId === null ) {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-slide
$requestedPane.slideDown( updateHov );
} else {
$currentPane.hide();
// Override toggle handler because we don't need it for this popup
// object at all. Sort of nasty, but it gets the job done.
- dialog.getPopup().toggle = $.noop;
+ dialog.getPopup().toggle = function () {};
}
}() );
$errorBox = this.$errorBox;
if ( errors.length === 0 ) {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-slide
$errorBox.slideUp( function () {
$errorBox
.removeAttr( 'class' )
.removeAttr( 'class' )
.detach();
}
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-slide
$errorBox
.attr( 'class', 'error' )
.empty()
.slideDown();
};
if ( $oldErrorBox !== $errorBox && $oldErrorBox.hasClass( 'error' ) ) {
+ // eslint-disable-next-line jquery/no-slide
$oldErrorBox.slideUp( showFunc );
} else {
showFunc();
deleteButton.$element.closest( 'li.mw-htmlform-cloner-li' ).remove();
} );
} else {
- $element.filter( ':input' ).click( function ( ev ) {
- ev.preventDefault();
+ $element.filter( ':input' ).on( 'click', function ( e ) {
+ e.preventDefault();
$( this ).closest( 'li.mw-htmlform-cloner-li' ).remove();
} );
}
appendToCloner( createButton.$element );
} );
} else {
- $createElement.filter( ':input' ).click( function ( ev ) {
- ev.preventDefault();
+ $createElement.filter( ':input' ).on( 'click', function ( e ) {
+ e.preventDefault();
appendToCloner( $( this ) );
} );
name: name,
multiple: 'multiple',
'data-placeholder': dataPlaceholder.plain(),
- 'class': 'htmlform-chzn-select mw-input ' + oldClass
+ class: 'htmlform-chzn-select mw-input ' + oldClass
} );
$oldContainer.find( 'input' ).each( function () {
var $oldInput = $( this ),
// cache the current selection to avoid expensive lookup
currentValReasonList = $reasonList.val();
- $reasonList.change( function () {
+ $reasonList.on( 'change', function () {
currentValReasonList = $reasonList.val();
} );
* @param {Array} nodes List of nodes
* @return {string} Other message
*/
- 'int': function ( nodes ) {
+ int: function ( nodes ) {
var msg = textify( nodes[ 0 ] );
return mw.jqueryMsg.getMessageFunction()( msg.charAt( 0 ).toLowerCase() + msg.slice( 1 ) );
},
}
if ( mw.config.get( 'wgCascadeableLevels' ) !== undefined ) {
- $( 'form#mw-Protect-Form' ).submit( this.toggleUnchainedInputs.bind( ProtectionForm, true ) );
+ $( 'form#mw-Protect-Form' ).on( 'submit', this.toggleUnchainedInputs.bind( ProtectionForm, true ) );
}
this.getExpirySelectors().each( function () {
- $( this ).change( ProtectionForm.updateExpiryList.bind( ProtectionForm, this ) );
+ $( this ).on( 'change', ProtectionForm.updateExpiryList.bind( ProtectionForm, this ) );
} );
this.getExpiryInputs().each( function () {
$( this ).on( 'keyup change', ProtectionForm.updateExpiry.bind( ProtectionForm, this ) );
} );
this.getLevelSelectors().each( function () {
- $( this ).change( ProtectionForm.updateLevels.bind( ProtectionForm, this ) );
+ $( this ).on( 'change', ProtectionForm.updateLevels.bind( ProtectionForm, this ) );
} );
$( '#mwProtectSet > tbody > tr:first' ).after( $row );
$cell.append(
$( '<input>' )
.attr( { id: 'mwProtectUnchained', type: 'checkbox' } )
- .click( this.onChainClick.bind( this ) )
+ .on( 'click', this.onChainClick.bind( this ) )
.prop( 'checked', !this.areAllTypesMatching() ),
document.createTextNode( ' ' ),
$( '<label>' )
* @property {Object}
*/
autoHideSeconds: {
- 'short': 5,
- 'long': 30
+ short: 5,
+ long: 30
},
/**
if ( !bound ) {
bound = true;
$( window )
- .resize( $.debounce( 300, true, handleResizeStart ) )
- .resize( $.debounce( 300, handleResizeEnd ) );
+ .on( 'resize', $.debounce( 300, true, handleResizeStart ) )
+ .on( 'resize', $.debounce( 300, handleResizeEnd ) );
}
} );
} );
mw.hook( 'wikipage.categories' ).fire( $nodes );
}
- $( '#t-print a' ).click( function ( e ) {
+ $( '#t-print a' ).on( 'click', function ( e ) {
window.print();
e.preventDefault();
} );
$links = $links.filter( ':not( #bodyContent *, #content * )' );
}
- $links.click( function ( e ) {
+ $links.on( 'click', function ( e ) {
var mwTitle, action, api, $link;
mwTitle = mw.Title.newFromText( title );
// Collect views
allViews = $.extend( true, {
- 'default': {
+ default: {
title: mw.msg( 'rcfilters-filterlist-title' ),
groups: filterGroups
}
id,
obj.label,
normalizedData,
- { 'default': isDefault }
+ { default: isDefault }
)
] );
randomID,
label,
normalizedData,
- { 'default': isDefault }
+ { default: isDefault }
)
] );
name: 'namespace', // parameter name is singular
type: 'string_options',
title: mw.msg( 'namespaces' ),
- labelPrefixKey: { 'default': 'rcfilters-tag-prefix-namespace', inverted: 'rcfilters-tag-prefix-namespace-inverted' },
+ labelPrefixKey: { default: 'rcfilters-tag-prefix-namespace', inverted: 'rcfilters-tag-prefix-namespace-inverted' },
separator: ';',
fullCoverage: true,
filters: items
hidden: true,
filters: [ {
name: 'invert',
- 'default': '0'
+ default: '0'
} ]
} ]
};
max: 1000
},
sortFunc: function ( a, b ) { return Number( a.name ) - Number( b.name ); },
- 'default': mw.user.options.get( this.limitPreferenceName, displayConfig.limitDefault ),
+ default: mw.user.options.get( this.limitPreferenceName, displayConfig.limitDefault ),
sticky: true,
filters: displayConfig.limitArray.map( function ( num ) {
return controller._createFilterDataFromNumber( num, num );
( Number( i ) * 24 ).toFixed( 2 ) :
Number( i );
},
- 'default': mw.user.options.get( this.daysPreferenceName, displayConfig.daysDefault ),
+ default: mw.user.options.get( this.daysPreferenceName, displayConfig.daysDefault ),
sticky: true,
filters: [
// Hours (1, 2, 6, 12)
filters: [
{
name: 'enhanced',
- 'default': String( mw.user.options.get( 'usenewrc', 0 ) )
+ default: String( mw.user.options.get( 'usenewrc', 0 ) )
}
]
}
filters: [
{
name: 'target',
- 'default': ''
+ default: ''
}
]
},
filters: [
{
name: 'showlinkedto',
- 'default': false
+ default: false
}
]
}
$firstNew.after( $indicator );
}
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-fade
$newChanges
.hide()
.fadeIn( 1000 );
this.queriesModel.connect( this, {
itemUpdate: 'onSavedQueriesItemUpdate',
initialize: 'onSavedQueriesInitialize',
- 'default': 'reevaluateResetRestoreState'
+ default: 'reevaluateResetRestoreState'
} );
}
)
)
) {
+ // eslint-disable-next-line jquery/no-animate
$( container ).animate( {
scrollTop: newScrollTop
} );
this.menu = new mw.rcfilters.ui.GroupWidget( {
events: {
click: 'menuItemClick',
- 'delete': 'menuItemDelete',
- 'default': 'menuItemDefault',
+ delete: 'menuItemDelete',
+ default: 'menuItemDefault',
edit: 'menuItemEdit'
},
classes: [ 'mw-rcfilters-ui-savedLinksListWidget-menu' ],
// OO.ui.ButtonWidget doesn't take focus itself (T128054)
$focus = $( '#mw-apisandbox-ui' ).find( document.activeElement );
if ( $focus.length ) {
+ // eslint-disable-next-line jquery/no-event-shorthand
$focus[ 0 ].blur();
}
// it makes it too hard to read and our "disabled"
// isn't really disabled.
widgetField.onFieldDisable( false );
- widgetField.onFieldDisable = $.noop;
+ widgetField.onFieldDisable = function () {};
widgetField.apiParamIndex = ppi.index;
widget = Util.createWidgetForParameter( {
name: name,
type: 'string',
- 'default': ''
+ default: ''
}, {
nooptional: true
} );
}
that.deprecatedItemsFieldset = new OO.ui.FieldsetLayout().addItems( deprecatedItems ).toggle( false );
+ // eslint-disable-next-line jquery/no-animate-toggle
tmp = $( '<fieldset>' )
.toggle( !that.deprecatedItemsFieldset.isEmpty() )
.append(
$( function () {
var $projectField = $( '#mw-import-table-interwiki #interwiki' );
if ( $projectField.length ) {
- $projectField.change( updateImportSubprojectList );
+ $projectField.on( 'change', updateImportSubprojectList );
updateImportSubprojectList();
}
} );
// Bind to change event, and trigger once to set the initial state of the checkboxes.
rc.updateCheckboxes();
- $select.change( rc.updateCheckboxes );
+ $select.on( 'change', rc.updateCheckboxes );
}
};
for ( i = 0; i < results.length; i++ ) {
result = results[ i ];
- imageCaption = mw.html.element( 'span', { 'class': 'iw-result__mini-gallery__caption' }, result.title );
+ imageCaption = mw.html.element( 'span', { class: 'iw-result__mini-gallery__caption' }, result.title );
imageThumbnailSrc = ( result.thumbnail ) ? result.thumbnail.source : '';
resultOutput += '<div class="iw-result__mini-gallery">' +
/* escaping response content */
mw.html.element( 'a', {
href: '/wiki/' + result.title,
- 'class': 'iw-result__mini-gallery__image',
+ class: 'iw-result__mini-gallery__image',
style: 'background-image: url(' + imageThumbnailSrc + ');'
}, new mw.html.Raw( imageCaption ) ) +
'</div>';
// Emulate HTML5 autofocus behavior in non HTML5 compliant browsers
if ( !( 'autofocus' in document.createElement( 'input' ) ) ) {
- $( 'input[autofocus]' ).eq( 0 ).focus();
+ $( 'input[autofocus]' ).eq( 0 ).trigger( 'focus' );
}
// Attach handler for check all/none buttons
$checkboxes = $( '#powersearch input[id^=mw-search-ns]' );
- $( '#mw-search-toggleall' ).click( function () {
+ $( '#mw-search-toggleall' ).on( 'click', function () {
$checkboxes.prop( 'checked', true );
} );
- $( '#mw-search-togglenone' ).click( function () {
+ $( '#mw-search-togglenone' ).on( 'click', function () {
$checkboxes.prop( 'checked', false );
} );
updateHeaderLinks( searchWidget.getValue() );
// When saving settings, use the proper request method (POST instead of GET).
- $( '#mw-search-powersearch-remember' ).change( function () {
+ $( '#mw-search-powersearch-remember' ).on( 'change', function () {
this.form.method = this.checked ? 'post' : 'get';
} ).trigger( 'change' );
summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ),
wpComment = OO.ui.infuse( $( '#wpComment' ).closest( '.oo-ui-widget' ) );
- $( '#mw-undelete-invert' ).click( function () {
+ $( '#mw-undelete-invert' ).on( 'click', function () {
$( '.mw-undelete-revlist input[type="checkbox"]' ).prop( 'checked', function ( i, val ) {
return !val;
} );
*/
( function () {
$( function () {
- $( 'a.mw-watch-link' ).click( function ( e ) {
+ $( 'a.mw-watch-link' ).on( 'click', function ( e ) {
var promise,
api = new mw.Api(),
$link = $( this ),
if ( ajaxUploadDestCheck ) {
// Insert an event handler that fetches upload warnings when wpDestFile
// has been changed
- $( '#wpDestFile' ).change( function () {
+ $( '#wpDestFile' ).on( 'change', function () {
uploadWarning.checkNow( $( this ).val() );
} );
// Insert a row where the warnings will be displayed just below the
if ( mw.config.get( 'wgAjaxLicensePreview' ) && $license.length ) {
// License selector check
- $license.change( function () {
+ $license.on( 'change', function () {
// We might show a preview
uploadTemplatePreview.getPreview( $license, $( '#mw-license-preview' ) );
} );
// fillDestFile setup
mw.config.get( 'wgUploadSourceIds' ).forEach( function ( sourceId ) {
- $( '#' + sourceId ).change( function () {
+ $( '#' + sourceId ).on( 'change', function () {
var path, slash, backslash, fname;
if ( !mw.config.get( 'wgUploadAutoFill' ) ) {
return;
/* Initialization */
if ( hasFileAPI() ) {
// Update thumbnail when the file selection control is updated.
- $( '#wpUploadFile' ).change( function () {
+ $( '#wpUploadFile' ).on( 'change', function () {
var file;
clearPreview();
if ( this.files && this.files.length ) {
namespace: 'uploadwarning'
} );
- $uploadForm.submit( function () {
+ $uploadForm.on( 'submit', function () {
allowCloseWindow.release();
} );
} );
// Change tabindex only when main div has focus
if ( $( this ).is( ':focus' ) ) {
- $( this ).find( 'a' ).first().focus();
+ $( this ).find( 'a' ).first().trigger( 'focus' );
setEditTabindex( '0' );
}
} );
// Dynamically show/hide the "other time" input under each dropdown
$( '.mw-userrights-nested select' ).on( 'change', function ( e ) {
+ // eslint-disable-next-line jquery/no-animate-toggle
$( e.target.parentNode ).find( 'input' ).toggle( $( e.target ).val() === 'other' );
} );
// If the user wants to reset their watchlist, use an API call to do so (no reload required)
// Adapted from a user script by User:NQ of English Wikipedia
// (User:NQ/WatchlistResetConfirm.js)
- $resetForm.submit( function ( event ) {
+ $resetForm.on( 'submit', function ( event ) {
var $button = $resetForm.find( 'input[name=mw-watchlist-reset-submit]' );
event.preventDefault();
} ).fail( function () {
// On error, fall back to server-side reset
// First remove this submit listener and then re-submit the form
- $resetForm.off( 'submit' ).submit();
+ $resetForm.off( 'submit' ).trigger( 'submit' );
} );
} );
// add a listener on all form elements in the header form
$( '#mw-watchlist-form input, #mw-watchlist-form select' ).on( 'change', function () {
// submit the form when one of the input fields is modified
- $( '#mw-watchlist-form' ).submit();
+ $( '#mw-watchlist-form' ).trigger( 'submit' );
} );
}
event.preventDefault();
event.stopPropagation();
- $unwatchLink.blur();
+ $unwatchLink.trigger( 'blur' );
} );
}
} );
// Hide/show the table of contents element
function toggleToc() {
if ( $tocList.is( ':hidden' ) ) {
+ // FIXME: Use CSS transitions
+ // eslint-disable-next-line jquery/no-slide
$tocList.slideDown( 'fast' );
$tocToggleLink.text( mw.msg( 'hidetoc' ) );
$this.removeClass( 'tochidden' );
mw.cookie.set( 'hidetoc', null );
} else {
+ // eslint-disable-next-line jquery/no-slide
$tocList.slideUp( 'fast' );
$tocToggleLink.text( mw.msg( 'showtoc' ) );
$this.addClass( 'tochidden' );
);
}
if ( $field.is( ':input' ) ) {
- $field.select();
+ $field.trigger( 'select' );
}
return false;
}
this.setValue( this.formatter.getDefaultDate() );
}
if ( $field.is( ':input' ) ) {
- $field.select();
+ $field.trigger( 'select' );
}
if ( this.calendar ) {
* are set up. Note: The promise must have an .abort() functionality.
*/
mw.widgets.APIResultsQueue.prototype.setup = function () {
- return $.Deferred().resolve().promise( { abort: $.noop } );
+ return $.Deferred().resolve().promise( { abort: function () {} } );
};
/**
provider = this;
if ( !this.isValid() ) {
- return $.Deferred().reject().promise( { abort: $.noop } );
+ return $.Deferred().reject().promise( { abort: function () {} } );
}
api = this.isLocal ? new mw.Api() : new mw.ForeignApi( this.getAPIurl(), { anonymous: true } );
if ( e.which === OO.ui.Keys.TAB ) {
if ( e.shiftKey ) {
// Tabbing backward from text input: normal browser behavior
- $.noop();
} else {
// Tabbing forward from text input: just focus the calendar
this.calendar.$element.focus();
self = this;
// reuse the searchSuggest function from mw.searchSuggest
- promise = mw.searchSuggest.request( api, this.getQueryValue(), $.noop, this.limit, this.getNamespace() );
+ promise = mw.searchSuggest.request( api, this.getQueryValue(), function () {}, this.limit, this.getNamespace() );
// tracking purposes
promise.done( function ( data, jqXHR ) {
<?php
+use MediaWiki\Block\Restriction\PageRestriction;
use MediaWiki\MediaWikiServices;
/**
'wgEmailAuthentication' => true,
] );
- $this->setUserPerm( [ "createpage", "move" ] );
+ $this->setUserPerm( [ 'createpage', 'edit', 'move', 'rollback', 'patrol', 'upload', 'purge' ] );
$this->setTitle( NS_HELP, "test page" );
# $wgEmailConfirmToEdit only applies to 'edit' action
'expiry' => 10,
'systemBlock' => 'test',
] );
- $this->assertEquals( [ [ 'systemblockedtext',
+
+ $errors = [ [ 'systemblockedtext',
'[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
'Useruser', 'test', '23:00, 31 December 1969', '127.0.8.1',
- $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ],
+ $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
+
+ $this->assertEquals( $errors,
+ $this->title->getUserPermissionsErrors( 'edit', $this->user ) );
+ $this->assertEquals( $errors,
$this->title->getUserPermissionsErrors( 'move-target', $this->user ) );
+ $this->assertEquals( $errors,
+ $this->title->getUserPermissionsErrors( 'rollback', $this->user ) );
+ $this->assertEquals( $errors,
+ $this->title->getUserPermissionsErrors( 'patrol', $this->user ) );
+ $this->assertEquals( $errors,
+ $this->title->getUserPermissionsErrors( 'upload', $this->user ) );
+ $this->assertEquals( [],
+ $this->title->getUserPermissionsErrors( 'purge', $this->user ) );
// partial block message test
$this->user->mBlockedby = $this->user->getName();
'expiry' => 10,
] );
- $this->assertEquals( [ [ 'blockedtext-partial',
+ $this->assertEquals( [],
+ $this->title->getUserPermissionsErrors( 'edit', $this->user ) );
+ $this->assertEquals( [],
+ $this->title->getUserPermissionsErrors( 'move-target', $this->user ) );
+ $this->assertEquals( [],
+ $this->title->getUserPermissionsErrors( 'rollback', $this->user ) );
+ $this->assertEquals( [],
+ $this->title->getUserPermissionsErrors( 'patrol', $this->user ) );
+ $this->assertEquals( [],
+ $this->title->getUserPermissionsErrors( 'upload', $this->user ) );
+ $this->assertEquals( [],
+ $this->title->getUserPermissionsErrors( 'purge', $this->user ) );
+
+ $this->user->mBlock->setRestrictions( [
+ ( new PageRestriction( 0, $this->title->getArticleID() ) )->setTitle( $this->title ),
+ ] );
+
+ $errors = [ [ 'blockedtext-partial',
'[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
'Useruser', null, '23:00, 31 December 1969', '127.0.8.1',
- $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ],
+ $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
+
+ $this->assertEquals( $errors,
+ $this->title->getUserPermissionsErrors( 'edit', $this->user ) );
+ $this->assertEquals( $errors,
$this->title->getUserPermissionsErrors( 'move-target', $this->user ) );
+ $this->assertEquals( $errors,
+ $this->title->getUserPermissionsErrors( 'rollback', $this->user ) );
+ $this->assertEquals( $errors,
+ $this->title->getUserPermissionsErrors( 'patrol', $this->user ) );
+ $this->assertEquals( [],
+ $this->title->getUserPermissionsErrors( 'upload', $this->user ) );
+ $this->assertEquals( [],
+ $this->title->getUserPermissionsErrors( 'purge', $this->user ) );
}
}
public function testCheckPasswordValidity() {
$uppCalled = 0;
- $uppStatus = \Status::newGood();
+ $uppStatus = \Status::newGood( [] );
$this->setMwGlobals( [
'wgPasswordPolicy' => [
'policies' => [
$this->assertNotNull( $ret );
$this->assertSame( 'resetpass-validity-soft', $ret->msg->getKey() );
$this->assertFalse( $ret->hard );
+
+ $this->manager->removeAuthenticationSessionData( null );
+ $row->user_password_expires = null;
+ $status = \Status::newGood( [ 'forceChange' => true ] );
+ $status->error( 'testing' );
+ $providerPriv->setPasswordResetFlag( $userName, $status, $row );
+ $ret = $this->manager->getAuthenticationSessionData( 'reset-pass' );
+ $this->assertNotNull( $ret );
+ $this->assertSame( 'resetpass-validity', $ret->msg->getKey() );
+ $this->assertTrue( $ret->hard );
}
public function testAuthentication() {
protected $policies = [
'checkuser' => [
- 'MinimalPasswordLength' => 10,
+ 'MinimalPasswordLength' => [ 'value' => 10, 'forceChange' => true ],
'MinimumPasswordLengthToLogin' => 6,
'PasswordCannotMatchUsername' => true,
],
'MinimumPasswordLengthToLogin' => 1,
'PasswordCannotMatchBlacklist' => true,
'MaximalPasswordLength' => 4096,
+ // test null handling
+ 'PasswordCannotMatchUsername' => null,
],
];
public function testGetPoliciesForUser() {
$upp = $this->getUserPasswordPolicy();
- $user = User::newFromName( 'TestUserPolicy' );
- $user->addToDatabase();
- $user->addGroup( 'sysop' );
-
+ $user = $this->getTestUser( [ 'sysop' ] )->getUser();
$this->assertArrayEquals(
[
'MinimalPasswordLength' => 8,
'MinimumPasswordLengthToLogin' => 1,
- 'PasswordCannotMatchUsername' => 1,
+ 'PasswordCannotMatchUsername' => true,
+ 'PasswordCannotMatchBlacklist' => true,
+ 'MaximalPasswordLength' => 4096,
+ ],
+ $upp->getPoliciesForUser( $user )
+ );
+
+ $user = $this->getTestUser( [ 'sysop', 'checkuser' ] )->getUser();
+ $this->assertArrayEquals(
+ [
+ 'MinimalPasswordLength' => [ 'value' => 10, 'forceChange' => true ],
+ 'MinimumPasswordLengthToLogin' => 6,
+ 'PasswordCannotMatchUsername' => true,
'PasswordCannotMatchBlacklist' => true,
'MaximalPasswordLength' => 4096,
],
$this->assertArrayEquals(
[
- 'MinimalPasswordLength' => 10,
+ 'MinimalPasswordLength' => [ 'value' => 10, 'forceChange' => true ],
'MinimumPasswordLengthToLogin' => 6,
'PasswordCannotMatchUsername' => true,
'PasswordCannotMatchBlacklist' => true,
/**
* @dataProvider provideCheckUserPassword
*/
- public function testCheckUserPassword( $username, $groups, $password, $valid, $ok, $msg ) {
+ public function testCheckUserPassword( $groups, $password, StatusValue $expectedStatus ) {
$upp = $this->getUserPasswordPolicy();
-
- $user = User::newFromName( $username );
- $user->addToDatabase();
- foreach ( $groups as $group ) {
- $user->addGroup( $group );
- }
+ $user = $this->getTestUser( $groups )->getUser();
$status = $upp->checkUserPassword( $user, $password );
- $this->assertSame( $valid, $status->isGood(), $msg . ' - password valid' );
- $this->assertSame( $ok, $status->isOK(), $msg . ' - can login' );
+ $this->assertSame( $expectedStatus->isGood(), $status->isGood(), 'password valid' );
+ $this->assertSame( $expectedStatus->isOK(), $status->isOK(), 'can login' );
+ $this->assertSame( $expectedStatus->getValue(), $status->getValue(), 'flags' );
}
public function provideCheckUserPassword() {
+ $success = Status::newGood( [] );
+ $warning = Status::newGood( [] );
+ $forceChange = Status::newGood( [ 'forceChange' => true ] );
+ $fatal = Status::newGood( [] );
+ // the message does not matter, we only test for state and value
+ $warning->warning( 'invalid-password' );
+ $forceChange->warning( 'invalid-password' );
+ $warning->warning( 'invalid-password' );
+ $fatal->fatal( 'invalid-password' );
return [
- [
- 'PassPolicyUser',
+ 'No groups, default policy, password too short to login' => [
[],
'',
- false,
- false,
- 'No groups, default policy, password too short to login'
+ $fatal,
],
- [
- 'PassPolicyUser',
+ 'Default policy, short password' => [
[ 'user' ],
'aaa',
- false,
- true,
- 'Default policy, short password'
+ $warning,
],
- [
- 'PassPolicyUser',
+ 'Sysop with good password' => [
[ 'sysop' ],
'abcdabcdabcd',
- true,
- true,
- 'Sysop with good password'
+ $success,
],
- [
- 'PassPolicyUser',
+ 'Sysop with short password' => [
[ 'sysop' ],
'abcd',
- false,
- true,
- 'Sysop with short password'
+ $warning,
],
- [
- 'PassPolicyUser',
+ 'Checkuser with short password' => [
[ 'sysop', 'checkuser' ],
'abcdabcd',
- false,
- true,
- 'Checkuser with short password'
+ $forceChange,
],
- [
- 'PassPolicyUser',
+ 'Checkuser with too short password to login' => [
[ 'sysop', 'checkuser' ],
'abcd',
- false,
- false,
- 'Checkuser with too short password to login'
- ],
- [
- 'Useruser',
- [ 'user' ],
- 'Passpass',
- false,
- true,
- 'Username & password on blacklist'
+ $fatal,
],
];
}
+ public function testCheckUserPassword_blacklist() {
+ $upp = $this->getUserPasswordPolicy();
+ $user = User::newFromName( 'Useruser' );
+ $user->addToDatabase();
+
+ $status = $upp->checkUserPassword( $user, 'Passpass' );
+ $this->assertFalse( $status->isGood(), 'password invalid' );
+ $this->assertTrue( $status->isOK(), 'can login' );
+ }
+
/**
* @dataProvider provideMaxOfPolicies
*/
- public function testMaxOfPolicies( $p1, $p2, $max, $msg ) {
+ public function testMaxOfPolicies( $p1, $p2, $max ) {
$this->assertArrayEquals(
$max,
- UserPasswordPolicy::maxOfPolicies( $p1, $p2 ),
- $msg
+ UserPasswordPolicy::maxOfPolicies( $p1, $p2 )
);
}
public function provideMaxOfPolicies() {
return [
- [
+ 'Basic max in p1' => [
[ 'MinimalPasswordLength' => 8 ], // p1
[ 'MinimalPasswordLength' => 2 ], // p2
[ 'MinimalPasswordLength' => 8 ], // max
- 'Basic max in p1'
],
- [
+ 'Basic max in p2' => [
[ 'MinimalPasswordLength' => 2 ], // p1
[ 'MinimalPasswordLength' => 8 ], // p2
[ 'MinimalPasswordLength' => 8 ], // max
- 'Basic max in p2'
],
- [
- [ 'MinimalPasswordLength' => 8 ], // p1
+ 'Missing items in p1' => [
+ [
+ 'MinimalPasswordLength' => 8,
+ ], // p1
[
'MinimalPasswordLength' => 2,
'PasswordCannotMatchUsername' => 1,
'MinimalPasswordLength' => 8,
'PasswordCannotMatchUsername' => 1,
], // max
- 'Missing items in p1'
],
- [
+ 'Missing items in p2' => [
[
'MinimalPasswordLength' => 8,
'PasswordCannotMatchUsername' => 1,
'MinimalPasswordLength' => 8,
'PasswordCannotMatchUsername' => 1,
], // max
- 'Missing items in p2'
+ ],
+ 'complex value in p1' => [
+ [
+ 'MinimalPasswordLength' => [
+ 'value' => 8,
+ 'foo' => 1,
+ ],
+ ], // p1
+ [
+ 'MinimalPasswordLength' => 2,
+ ], // p2
+ [
+ 'MinimalPasswordLength' => [
+ 'value' => 8,
+ 'foo' => 1,
+ ],
+ ], // max
+ ],
+ 'complex value in p2' => [
+ [
+ 'MinimalPasswordLength' => 8,
+ ], // p1
+ [
+ 'MinimalPasswordLength' => [
+ 'value' => 2,
+ 'foo' => 1,
+ ],
+ ], // p2
+ [
+ 'MinimalPasswordLength' => [
+ 'value' => 8,
+ 'foo' => 1,
+ ],
+ ], // max
+ ],
+ 'complex value in both p1 and p2' => [
+ [
+ 'MinimalPasswordLength' => [
+ 'value' => 8,
+ 'foo' => 1,
+ 'baz' => false,
+ ],
+ ], // p1
+ [
+ 'MinimalPasswordLength' => [
+ 'value' => 2,
+ 'bar' => 2,
+ 'baz' => true,
+ ],
+ ], // p2
+ [
+ 'MinimalPasswordLength' => [
+ 'value' => 8,
+ 'foo' => 1,
+ 'bar' => 2,
+ 'baz' => true,
+ ],
+ ], // max
],
];
}
// html5sec SVG vectors
[
'<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>',
- true,
- true,
+ true, /* SVG is well formed */
+ true, /* Evil SVG detected */
'Script tag in svg (http://html5sec.org/#47)'
],
[
true,
false,
'DTD with aliased entities apos (Should be allowed)'
- ]
+ ],
+ [
+ '<svg xmlns="http://www.w3.org/2000/svg"><g filter="url( \'#foo\' )"></g></svg>',
+ true,
+ false,
+ 'SVG with local filter (T69044)'
+ ],
+ [
+ '<svg xmlns="http://www.w3.org/2000/svg"><g filter="url( http://example.com/#foo )"></g></svg>',
+ true,
+ true,
+ 'SVG with non-local filter (T69044)'
+ ],
+
];
// phpcs:enable
}
"sinon": false
},
"rules": {
- "operator-linebreak": 0,
+ "operator-linebreak": "off",
"quote-props": [ "error", "as-needed" ],
- "valid-jsdoc": 0,
- "qunit/require-expect": 0,
- "qunit/resolve-async": 0
+ "valid-jsdoc": "off",
+ "qunit/require-expect": "off",
+ "qunit/resolve-async": "off",
+ "jquery/no-parse-html-literal": "off"
}
}
if ( warn === undefined ) {
warn = mw.log.warn;
error = mw.log.error;
- mw.log.warn = mw.log.error = $.noop;
+ mw.log.warn = mw.log.error = function () {};
}
}
var done = assert.async(),
$canvas = $( '<div>' ).css( 'background-color', '#fff' ).appendTo( '#qunit-fixture' );
+ // eslint-disable-next-line jquery/no-animate
$canvas.animate( { 'background-color': '#000' }, 3 ).promise()
.done( function () {
var endColors = $.colorUtil.getRGB( $canvas.css( 'background-color' ) );
callback( $table );
} else {
$table.tablesorter();
- $table.find( '#sortme' ).click();
+ $table.find( '#sortme' ).trigger( 'click' );
}
// Table sorting is done synchronously; if it ever needs to change back
planetsAscName,
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
tableTest(
planetsAscName,
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
tableTest(
planetsAscName,
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
- $table.find( '.headerSort:eq(1)' ).click();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
+ $table.find( '.headerSort:eq(1)' ).trigger( 'click' );
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
tableTest(
reversed( planetsAscName ),
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click().click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' ).trigger( 'click' );
}
);
tableTest(
planetsAscRadius,
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(1)' ).click();
+ $table.find( '.headerSort:eq(1)' ).trigger( 'click' );
}
);
tableTest(
reversed( planetsAscRadius ),
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(1)' ).click().click();
+ $table.find( '.headerSort:eq(1)' ).trigger( 'click' ).trigger( 'click' );
}
);
tableTest(
$table.tablesorter(
{ sortList: [ { 0: 'asc' }, { 1: 'asc' } ] }
);
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
tableTest(
$table.tablesorter(
{ sortList: [ { 0: 'desc' }, { 1: 'desc' } ] }
);
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
// Pretend to click while pressing the multi-sort key
event = $.Event( 'click' );
$table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
tableTest( 'Sorting with colspanned headers: sort spanned column twice',
$table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
tableTest( 'Sorting with colspanned headers: subsequent column',
$table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
$table.tablesorter();
- $table.find( '.headerSort:eq(1)' ).click();
+ $table.find( '.headerSort:eq(1)' ).trigger( 'click' );
}
);
tableTest( 'Sorting with colspanned headers: sort subsequent column twice',
$table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
$table.tablesorter();
- $table.find( '.headerSort:eq(1)' ).click();
- $table.find( '.headerSort:eq(1)' ).click();
+ $table.find( '.headerSort:eq(1)' ).trigger( 'click' );
+ $table.find( '.headerSort:eq(1)' ).trigger( 'click' );
}
);
$table.find( 'tr:eq(0) > th:eq(0)' ).addClass( 'unsortable' );
$table.tablesorter();
- $table.find( 'tr:eq(0) > th:eq(0)' ).click();
+ $table.find( 'tr:eq(0) > th:eq(0)' ).trigger( 'click' );
assert.deepEqual(
tableExtract( $table ),
);
$cell = $table.find( 'tr:eq(0) > th:eq(0)' );
- $table.find( 'tr:eq(0) > th:eq(1)' ).click();
+ $table.find( 'tr:eq(0) > th:eq(1)' ).trigger( 'click' );
assert.strictEqual(
$cell.hasClass( 'headerSortUp' ) || $cell.hasClass( 'headerSortDown' ),
mw.config.set( 'wgPageContentLanguage', 'de' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
mw.config.set( 'wgDefaultDateFormat', 'mdy' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
ipv4Sorted,
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
tableTest(
reversed( ipv4Sorted ),
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click().click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' ).trigger( 'click' );
}
);
} );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
} );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
$table.find( 'tr:eq(2) td:eq(1)' ).attr( 'rowspan', '3' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
tableTest(
$table.find( 'tr:eq(2) td:eq(0)' ).attr( 'rowspan', '3' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
mw.config.set( 'wgDefaultDateFormat', 'mdy' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
currencySorted,
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
function ( $table ) {
$table.find( 'tr:last' ).addClass( 'sortbottom' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
'</table>'
);
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
assert.strictEqual(
$table.data( 'tablesorter' ).config.parsers[ 0 ].id,
'<tr><td data-sort-value="Cherry">Dolphin</td></tr>' +
'</tbody></table>'
);
- $table.tablesorter().find( '.headerSort:eq(0)' ).click();
+ $table.tablesorter().find( '.headerSort:eq(0)' ).trigger( 'click' );
data = [];
$table.find( 'tbody > tr' ).each( function ( i, tr ) {
'<tr><td><span data-sort-value="D">H</span></td></tr>' +
'</tbody></table>'
);
- $table.tablesorter().find( '.headerSort:eq(0)' ).click();
+ $table.tablesorter().find( '.headerSort:eq(0)' ).trigger( 'click' );
data = [];
$table.find( 'tbody > tr' ).each( function ( i, tr ) {
// initialize table sorter and sort once
$table
.tablesorter()
- .find( '.headerSort:eq(0)' ).click();
+ .find( '.headerSort:eq(0)' ).trigger( 'click' );
// Change the sortValue data properties (T40152)
// - change data
$table.find( 'td:contains(G)' ).removeData( 'sortValue' );
// Now sort again (twice, so it is back at Ascending)
- $table.find( '.headerSort:eq(0)' ).click();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
data = [];
$table.find( 'tbody > tr' ).each( function ( i, tr ) {
[ 'Numbers' ], numbers, numbersAsc,
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
[ 'Numbers' ], numbers, reversed( numbersAsc ),
function ( $table ) {
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click().click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' ).trigger( 'click' );
}
);
// TODO add numbers sorting tests for T10115 with a different language
mw.config.set( 'wgDefaultDateFormat', 'mdy' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
mw.config.set( 'wgDefaultDateFormat', 'dmy' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
mw.config.set( 'wgDefaultDateFormat', 'dmy' );
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
}
);
'<tr><td>1</td></tr>' +
'</table>'
);
- $table.tablesorter().find( '.headerSort:eq(0)' ).click();
+ $table.tablesorter().find( '.headerSort:eq(0)' ).trigger( 'click' );
assert.strictEqual(
$table.find( 'td' ).first().text(),
'<tr><td><img alt="A" />C</tr>' +
'</table>'
);
- $table.tablesorter().find( '.headerSort:eq(0)' ).click();
+ $table.tablesorter().find( '.headerSort:eq(0)' ).trigger( 'click' );
assert.strictEqual(
$table.find( 'td' ).text(),
'<tr><td>4</td></tr>' +
'</table>'
);
- $table.tablesorter().find( '.headerSort:eq(0)' ).click();
+ $table.tablesorter().find( '.headerSort:eq(0)' ).trigger( 'click' );
assert.strictEqual(
$table.find( 'td' ).text(),
'</table>'
);
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
// now the first row have 2 columns
- $table.find( '.headerSort:eq(1)' ).click();
+ $table.find( '.headerSort:eq(1)' ).trigger( 'click' );
parsers = $table.data( 'tablesorter' ).config.parsers;
'</table>'
);
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
assert.deepEqual(
tableExtract( $table ),
'</table>'
);
$table.tablesorter();
- $table.find( '.headerSort:eq(0)' ).click();
+ $table.find( '.headerSort:eq(0)' ).trigger( 'click' );
assert.deepEqual(
tableExtract( $table ),
$options = $( '#namespace' ).find( 'option' );
$options.eq( 0 ).removeProp( 'selected' );
$options.eq( 1 ).prop( 'selected', true );
- $( '#namespace' ).change();
+ $( '#namespace' ).trigger( 'change' );
// ... and checkboxes should be enabled again
assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), false );
// select first option ( 'all' namespace)...
$options.eq( 1 ).removeProp( 'selected' );
$options.eq( 0 ).prop( 'selected', true );
- $( '#namespace' ).change();
+ $( '#namespace' ).trigger( 'change' );
// ... and checkboxes should now be disabled
assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), true );
assert.strictEqual( $tocList.is( ':hidden' ), false, 'The table of contents is now visible' );
- $toggleLink.click();
+ $toggleLink.trigger( 'click' );
return $tocList.promise().then( function () {
assert.strictEqual( $tocList.is( ':hidden' ), true, 'The table of contents is now hidden' );
- $toggleLink.click();
+ $toggleLink.trigger( 'click' );
return $tocList.promise();
} );
} );