Merge "Make generic placeholder pseudo-class browser-prefix mixin"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 23 Feb 2017 16:20:38 +0000 (16:20 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 23 Feb 2017 16:20:38 +0000 (16:20 +0000)
74 files changed:
.eslintrc.json
.stylelintrc
.travis.yml
Gruntfile.js
RELEASE-NOTES-1.29
includes/EditPage.php
includes/actions/RollbackAction.php
includes/api/i18n/gl.json
includes/api/i18n/he.json
includes/api/i18n/qqq.json
includes/collation/Collation.php
includes/installer/i18n/bg.json
includes/installer/i18n/mk.json
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/encasing/Blob.php
includes/libs/rdbms/field/Field.php
includes/resourceloader/ResourceLoaderModule.php
includes/resourceloader/ResourceLoaderWikiModule.php
includes/utils/AutoloadGenerator.php
languages/i18n/be-tarask.json
languages/i18n/be.json
languages/i18n/bg.json
languages/i18n/de.json
languages/i18n/diq.json
languages/i18n/el.json
languages/i18n/en.json
languages/i18n/et.json
languages/i18n/gl.json
languages/i18n/mg.json
languages/i18n/oc.json
languages/i18n/qqq.json
languages/i18n/ta.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
resources/src/jquery/jquery.qunit.completenessTest.js
resources/src/mediawiki.skinning/content.parsoid.less
resources/src/mediawiki.special/mediawiki.special.search.interwikiwidget.styles.less
resources/src/mediawiki.ui/components/inputs.less
resources/src/mediawiki.widgets/mw.widgets.StashedFileWidget.less
resources/src/mediawiki/api.js
resources/src/mediawiki/htmlform/styles.css
resources/src/mediawiki/page/gallery-slideshow.js
tests/parser/parserTests.txt
tests/phpunit/includes/utils/ClassCollectorTest.php [new file with mode: 0644]
tests/phpunit/structure/AutoLoaderTest.php
tests/qunit/.eslintrc.json [new file with mode: 0644]
tests/qunit/data/generateJqueryMsgData.php
tests/qunit/data/mediawiki.jqueryMsg.data.js
tests/qunit/data/testrunner.js
tests/qunit/suites/resources/jquery/jquery.accessKeyLabel.test.js
tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js
tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js
tests/qunit/suites/resources/jquery/jquery.hidpi.test.js
tests/qunit/suites/resources/jquery/jquery.highlightText.test.js
tests/qunit/suites/resources/jquery/jquery.localize.test.js
tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js
tests/qunit/suites/resources/jquery/jquery.placeholder.test.js
tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js
tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js
tests/qunit/suites/resources/jquery/jquery.textSelection.test.js
tests/qunit/suites/resources/mediawiki.api/mediawiki.api.edit.test.js
tests/qunit/suites/resources/mediawiki.api/mediawiki.api.options.test.js
tests/qunit/suites/resources/mediawiki.api/mediawiki.api.parse.test.js
tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js
tests/qunit/suites/resources/mediawiki.rcfilters/dm.FiltersViewModel.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.cldr.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.errorLogger.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.loader.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js
tests/qunit/suites/resources/startup.test.js

index 98d0f10..64b5ea7 100644 (file)
@@ -2,8 +2,7 @@
        "extends": "wikimedia",
        "env": {
                "browser": true,
-               "jquery": true,
-               "qunit": true
+               "jquery": true
        },
        "globals": {
                "require": false,
index 41702aa..6325182 100644 (file)
@@ -3,8 +3,6 @@
        "rules": {
                "declaration-no-important": null,
 
-               "indentation": null,
-
                "no-descending-specificity": null,
 
                "selector-list-comma-newline-after": null,
index 9738605..ec7bac3 100644 (file)
@@ -7,6 +7,12 @@
 # complement that setup by testing MediaWiki on travis
 #
 language: php
+# Using HHVM-3.6+ requires Trusty (Travis default: precise)
+# https://docs.travis-ci.com/user/languages/php#HHVM-versions
+# https://github.com/travis-ci/travis-ci/issues/7368
+sudo: required
+group: edge
+dist: trusty
 
 matrix:
   fast_finish: true
@@ -16,7 +22,7 @@ matrix:
     - env: dbtype=postgres
       php: 5.5
     - env: dbtype=mysql
-      php: hhvm
+      php: hhvm-3.12
     - env: dbtype=mysql
       php: 7
 
@@ -44,7 +50,7 @@ before_script:
       --pass travis
       --dbtype "$dbtype"
       --dbname traviswiki
-      --dbuser travis
+      --dbuser root
       --dbpass ""
       --scriptpath "/w"
 
index 191286a..0e1c8cb 100644 (file)
@@ -24,12 +24,13 @@ module.exports = function ( grunt ) {
                        all: [
                                '**/*.js',
                                '!docs/**',
-                               '!tests/**',
                                '!node_modules/**',
                                '!resources/lib/**',
                                '!resources/src/jquery.tipsy/**',
                                '!resources/src/jquery/jquery.farbtastic.js',
                                '!resources/src/mediawiki.libs/**',
+                               // Third-party code of PHPUnit coverage report
+                               '!tests/coverage/**',
                                '!vendor/**',
                                // Explicitly say "**/*.js" here in case of symlinks
                                '!extensions/**/*.js',
index a739821..a1ce9d9 100644 (file)
@@ -61,6 +61,7 @@ production.
 * Updated QUnit from v1.22.0 to v1.23.1.
 * Updated cssjanus from v1.1.2 to 1.1.3.
 * Updated psr/log from v1.0.0 to v1.0.2.
+* Update Moment.js from v2.8.4 to v2.15.0.
 
 ==== New external libraries ====
 
index 34062c0..a45c889 100644 (file)
@@ -1256,7 +1256,7 @@ class EditPage {
                $revision = $this->mArticle->getRevisionFetched();
                if ( $revision === null ) {
                        if ( !$this->contentModel ) {
-                               $this->contentModel = $this->getTitle()->getContentModel();
+                               throw new RuntimeException( 'EditPage contentModel was false' );
                        }
                        $handler = ContentHandler::getForModelID( $this->contentModel );
 
@@ -1300,7 +1300,7 @@ class EditPage {
 
                if ( $content === false || $content === null ) {
                        if ( !$this->contentModel ) {
-                               $this->contentModel = $this->getTitle()->getContentModel();
+                               throw new RuntimeException( 'EditPage contentModel was false' );
                        }
                        $handler = ContentHandler::getForModelID( $this->contentModel );
 
index aa2858d..9d336e4 100644 (file)
@@ -41,6 +41,7 @@ class RollbackAction extends FormlessAction {
         * - confirm-rollback-button
         * - rollbackfailed
         * - rollback-missingparam
+        * - rollback-success-notify
         */
 
        /**
@@ -123,8 +124,13 @@ class RollbackAction extends FormlessAction {
 
                $old = Linker::revUserTools( $current );
                $new = Linker::revUserTools( $target );
-               $this->getOutput()->addHTML( $this->msg( 'rollback-success' )->rawParams( $old, $new )
-                       ->parseAsBlock() );
+               $this->getOutput()->addHTML(
+                       $this->msg( 'rollback-success' )
+                               ->rawParams( $old, $new )
+                               ->params( $current->getUserText( Revision::FOR_THIS_USER, $user ) )
+                               ->params( $target->getUserText( Revision::FOR_THIS_USER, $user ) )
+                               ->parseAsBlock()
+               );
 
                if ( $user->getBoolOption( 'watchrollback' ) ) {
                        $user->addWatch( $this->page->getTitle(), User::IGNORE_USER_RIGHTS );
index 0865424..f8e3f05 100644 (file)
        "apierror-reauthenticate": "Non se autentificou recentemente nesta sesión. Por favor, volva a autentificarse.",
        "apierror-revwrongpage": "r$1 non é unha revisión de $2.",
        "apierror-searchdisabled": "A busca <var>$1</var> está desactivada.",
+       "apierror-sectionreplacefailed": "Non se puido combinar a sección actualizada.",
+       "apierror-sectionsnotsupported": "As seccións non son compatibles co modelo de contido $1.",
        "apierror-sectionsnotsupported-what": "As seccións non son compatibles con $1.",
        "apierror-show": "Parámetro incorrecto - non se poden proporcionar valores mutuamente excluíntes.",
+       "apierror-siteinfo-includealldenied": "Non se pode ver a información de tódolos servidores a menos que <var>$wgShowHostNames</var> teña valor verdadeiro.",
        "apierror-sizediffdisabled": "A diferenza de tamaño está deshabilitada no modo Miser.",
        "apierror-spamdetected": "A súa edición foi rexeitada por conter un fragmento de publicidade: <code>$1</code>.",
        "apierror-specialpage-cantexecute": "Non ten permiso para ver os resultados desta páxina especial.",
        "apierror-unknownformat": "Formato descoñecido \"$1\".",
        "apierror-unrecognizedparams": "{{PLURAL:$2|Parámetro non recoñecido|Parámetros non recoñecidos}}: $1.",
        "apierror-unrecognizedvalue": "Valor non recoñecido para o parámetro <var>$1</var>: $2.",
+       "apierror-urlparamnormal": "Non se puideron normalizar os parámetros de imaxe de $1.",
+       "apierror-writeapidenied": "Non ten permiso para editar este wiki a través da API.",
+       "apiwarn-alldeletedrevisions-performance": "Para ter un mellor rendemento á hora de xerar títulos, estableza <kbd>$1dir=newer</kbd>.",
+       "apiwarn-badurlparam": "Non se puido analizar <var>$1urlparam</var> para $2. Só se usará a anchura e a altura.",
        "apiwarn-deprecation-httpsexpected": "Utilizouse HTTP cando esperábase HTTPS.",
        "apiwarn-deprecation-parameter": "O parámetro <var>$1</var> está obsoleto.",
        "apiwarn-invalidcategory": "\"$1\" non é unha categoría.",
index 30afb47..682f9fc 100644 (file)
        "apierror-upload-filekeyneeded": "חובה לספק <var>filekey</var> כאשר <var>offset</var> אינו אפס.",
        "apierror-upload-filekeynotallowed": "לא ניתן לספק <var>filekey</var> כאשר <var>offset</var> הוא 0.",
        "apierror-upload-missingresult": "אין תוצאות בנתוני מצב.",
+       "apierror-writeapidenied": "אין לך הרשאה לערוך את הוויקי הזה דרך ה־API.",
+       "apiwarn-alldeletedrevisions-performance": "לביצועים טובים יותר בעת יצירת כותרת, יש להשתמש ב־<kbd>$1dir=newer</kbd>.",
+       "apiwarn-badurlparam": "לא היה אפשר לפענח את <var>$1urlparam</var> עבור $2. משתמשים רק ב־width ו־height.",
+       "apiwarn-badutf8": "הערך הערך שהועבר ל־<var>$1</var> מכיל נתונים בלתי־תקינים או בלתי־מנורמלים. נתונים טקסט אמורים להיות תקינים, מנורמלי NFC ללא תווי בקרה C0 למעט HT (\\t)‏, LF (\\n), ו־CR (\\r).",
+       "apiwarn-checktoken-percentencoding": "נא לבדוק שסימנים כמו \"+\" באסימון מקודדים עם אחוזים בצורה נכונה ב־URL.",
+       "apiwarn-deprecation-deletedrevs": "<kbd>list=deletedrevs</kbd> הוצהר בתור מיושן. נא להשתמש ב־ <kbd>prop=deletedrevisions</kbd> או ב־<kbd>list=alldeletedrevisions</kbd> במקום זה.",
+       "apiwarn-deprecation-expandtemplates-prop": "מכיוון שלא ניתנו ערכים לפרמטר <var>prop</var>, תסדיר מיושן ישמש לפלט. התסדיר הזה מיושן, ובעתיד יינתן ערך בררת מחדל לפרמטר <var>prop</var>, כך שתמיד ישמש התסדיר החדש.",
+       "apiwarn-deprecation-httpsexpected": "משמש HTTP כשהיה צפוי HTTPS.",
+       "apiwarn-deprecation-login-botpw": "כניסה לחשבון עיקרי (main-account) דרך <kbd>action=login</kbd> מיושנת ועלולה להפסיק לעבוד ללא אזהרה נוספת. כדי להמשיך להיכנס עם <kbd>action=login</kbd>, ר' [[Special:BotPasswords]]. כדי להמשיך באופן מאובטח באמצעות חשבון עיקרי, ר' <kbd>action=clientlogin</kbd>.",
+       "apiwarn-deprecation-login-token": "אחזור אסימון דרך <kbd>action=login</kbd> מיושן. נא להשתמש ב־<kbd>action=query&meta=tokens&type=login</kbd> במקום זה.",
+       "apiwarn-deprecation-parameter": "הפרמטר <var>$1</var> מיושן.",
+       "apiwarn-deprecation-parse-headitems": "<kbd>prop=headitems</kbd> מיושן מאז מדיה־ויקי 1.28. יש להשתמש ב־<kbd>prop=headhtml</kbd> בעת יצירת מסמכי HTML חדשים, או ב־<kbd>prop=modules|jsconfigvars</kbd> בעת עדכון מסמך בצד הלקוח.",
+       "apiwarn-deprecation-purge-get": "שימוש ב־<kbd>action=purge</kbd> דרך GET מיושן. יש להשתמש ב־POST במקום זה.",
+       "apiwarn-deprecation-withreplacement": "<kbd>$1</kbd> מיושן. יש להשתמש ב־<kbd>$2</kbd> במקום זה.",
+       "apiwarn-difftohidden": "לא היה אפשר לעשות השוואה עם גרסה $1: התוכן מוסתר.",
+       "apiwarn-errorprinterfailed": "מדפיס השגיאות לא עבד. ינסה שוב ללא פרמטרים.",
+       "apiwarn-errorprinterfailed-ex": "מדפיס השגיאות לא עבד (ינסה שוב ללא פרמטרים): $1",
        "apiwarn-invalidcategory": "\"$1\" אינה קטגוריה.",
        "apiwarn-invalidtitle": "\"$1\" אינה כותרת תקינה.",
+       "apiwarn-invalidxmlstylesheetext": "לגיליון הסגנונות אמור להיות הסיומת <code dir=\"ltr\">.xsl</code>.",
+       "apiwarn-invalidxmlstylesheet": "ניתן גיליון סגנונות שאינו תקין או אינו קיים.",
+       "apiwarn-invalidxmlstylesheetns": "גיליון הסגנונות אמור להיות במרחב השם {{ns:MediaWiki}}.",
+       "apiwarn-moduleswithoutvars": "המאפיין <kbd>modules</kbd> לא הוגדר, אבל לא <kbd>jsconfigvars</kbd> או <kbd>encodedjsconfigvars</kbd>. משתני הגדרות נחוצים בשביל שימוש נכון במודולים.",
        "apiwarn-notfile": "\"$1\" אינו קובץ.",
+       "apiwarn-nothumb-noimagehandler": "לא היה אפשר ליצור תמונה ממוזערת כי לקובץ $1 לא משויך מטפל תמונה.",
+       "apiwarn-parse-nocontentmodel": "לא ניתן <var>title</var> או <var>contentmodel</var>, נניח שזה $1.",
+       "apiwarn-parse-titlewithouttext": "<var>title</var> שימש ללא <var>text</var>, והתבקשו מאפייני דף מפוענח. האם התכוונת להשתמש ב־<var>page</var> במקום <var>title</var>?",
+       "apiwarn-redirectsandrevids": "פתרון הפניות לא יכול לשמש יחד עם הפרמטר <var>revids</var>. הפניות ש־<var>revids</var> מצביע אליהן לא נפתרו.",
        "apiwarn-tokennotallowed": "הפעולה \"$1\" אינה מותרת למשתמש הנוכחי.",
        "apiwarn-tokens-origin": "לא ניתן לקבל אסימונים כשמדיניות המקור הזהה אינה חלה.",
        "apiwarn-toomanyvalues": "יותר מדי ערכים סופקו לפרמטר <var>$1</var>: המגבלה היא $2.",
index 297f7ed..c3ccad6 100644 (file)
        "apiwarn-deprecation-parse-headitems": "{{doc-apierror}}",
        "apiwarn-deprecation-purge-get": "{{doc-apierror}}",
        "apiwarn-deprecation-withreplacement": "{{doc-apierror}}\n\nParameters:\n* $1 - Query string fragment that is deprecated, e.g. \"action=tokens\".\n* $2 - Query string fragment to use instead, e.g. \"action=tokens\".",
-       "apiwarn-difftohidden": "{{doc-apierror}}\n\nParameters:\n* $1 - Revision ID number.",
+       "apiwarn-difftohidden": "{{doc-apierror}}\n\nParameters:\n* $1 - Revision ID number.\n\n\"r\" is short for \"revision\". You may translate it.",
        "apiwarn-errorprinterfailed": "{{doc-apierror}}",
        "apiwarn-errorprinterfailed-ex": "{{doc-apierror}}\n\nParameters:\n* $1 - Exception message, which may already end in punctuation. Probably in English.",
        "apiwarn-invalidcategory": "{{doc-apierror}}\n\nParameters:\n* $1 - Supplied category name.",
index 7659d6c..d67bc7e 100644 (file)
@@ -67,7 +67,7 @@ abstract class Collation {
                                return new CollationFa;
                        default:
                                $match = [];
-                               if ( preg_match( '/^uca-([a-z@=-]+)$/', $collationName, $match ) ) {
+                               if ( preg_match( '/^uca-([A-Za-z@=-]+)$/', $collationName, $match ) ) {
                                        return new IcuCollation( $match[1] );
                                }
 
index 5c2b320..b950420 100644 (file)
@@ -65,6 +65,7 @@
        "config-apc": "[http://www.php.net/apc APC] е инсталиран",
        "config-apcu": "[http://www.php.net/apc APC] е инсталиран",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] е инсталиран",
+       "config-no-cache-apcu": "<strong>Внимание:</strong> [http://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] и [http://www.iis.net/download/WinCacheForPhp WinCache] не могат да бъдат открити.\nКеширането на обекти не е активирано.",
        "config-mod-security": "<strong>Предупреждение:</strong> [http://modsecurity.org/ mod_security]/mod_security2 е включено на вашия уеб сървър. Много от обичайните му конфигурации пораждат проблеми с МедияУики и друг софтуер, който позволява публикуване на произволно съдържание.\nАко е възможно, моля изключете го. В противен случай се обърнете към [http://modsecurity.org/documentation/ документацията на mod_security] или се свържете с поддръжката на хостинга си, ако се сблъскате със случайни грешки.",
        "config-diff3-bad": "GNU diff3 не беше намерен.",
        "config-git": "Налична е системата за контрол на версиите Git: <code>$1</code>.",
@@ -84,6 +85,7 @@
        "config-db-host": "Хост на базата от данни:",
        "config-db-host-help": "Ако базата от данни е на друг сървър, в кутията се въвежда името на хоста или IP адреса.\n\nАко се използва споделен уеб хостинг, доставчикът на услугата би трябвало да е предоставил в документацията си коректния хост.\n\nАко инсталацията протича на Windows-сървър и се използва MySQL, използването на \"localhost\" може да е неприемливо. В такива случаи се използва \"127.0.0.1\" за локален IP адрес.\n\nПри използване на PostgreSQL, това поле се оставя празно, за свързване чрез Unix socket.",
        "config-db-host-oracle": "TNS на базата данни:",
+       "config-db-host-oracle-help": "Въведете валидно [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm Local Connect Name]; файлът tnsnames.ora трябва да бъде видим за инсталацията.<br />Ако използвате клиентска библиотека версия 10g или по-нова можете да използвате метода [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect].",
        "config-db-wiki-settings": "Идентифициране на това уики",
        "config-db-name": "Име на базата от данни:",
        "config-db-name-help": "Избира се име, което да идентифицира уикито.\nТо не трябва да съдържа интервали.\n\nАко се използва споделен хостинг, доставчикът на услугата би трябвало да е предоставил или име на базата от данни, която да бъде използвана, или да позволява създаването на бази от данни чрез контролния панел.",
        "config-mysql-innodb": "InnoDB",
        "config-mysql-myisam": "MyISAM",
        "config-mysql-myisam-dep": "'''Предупреждение''': Избрана е MyISAM като система за складиране в MySQL, която не се препоръчва за използване с МедияУики, защото:\n* почти не поддържа паралелност заради заключване на таблиците\n* е по-податлива на повреди в сравнение с други системи\n* кодът на МедияУики не винаги поддържа MyISAM коректно\n\nАко инсталацията на MySQL поддържа InnoDB, силно е препоръчително да се използва тя.\nАко инсталацията на MySQL не поддържа InnoDB, вероятно е време за обновяване.",
+       "config-mysql-only-myisam-dep": "<strong>Внимание:</strong> MyISAM e единственият наличен на тази машина тип на таблиците за MySQL и не е препоръчителен за употреба при МедияУики защото:\n* има слаба поддръжка на конкурентност на заявките, поради закючването на таблиците\n* е много по-податлив на грешки в базите от данни от другите типове таблици\n* кодът на МедияУики не винаги работи с MyISAM както трябва\n\nВашият MySQL не поддържа InnoDB, така че може би е дошло време за актуализиране.",
        "config-mysql-engine-help": "'''InnoDB''' почти винаги е най-добрата възможност заради навременната си поддръжка.\n\n'''MyISAM''' може да е по-бърза при инсталации с един потребител или само за четене.\nБазите от данни MyISAM се повреждат по-често от InnoDB.",
        "config-mysql-charset": "Набор от символи в базата от данни:",
        "config-mysql-binary": "Бинарен",
        "config-mysql-utf8": "UTF-8",
        "config-mysql-charset-help": "В '''бинарен режим''' МедияУики съхранява текстовете в UTF-8 в бинарни полета в базата от данни.\nТова е по-ефективно от UTF-8 режима на MySQL и позволява използването на пълния набор от символи в Уникод.\n\nВ '''UTF-8 режим''' MySQL ще знае в кой набор от символи са данните от уикито и ще може да ги показва и променя по подходящ начин, но няма да позволява складиране на символи извън [https://en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Основния многоезичен набор].",
        "config-mssql-auth": "Тип на удостоверяването:",
+       "config-mssql-install-auth": "Изберете начин за удостоверяване, който ще бъде използван за връзка с базата от данни по време на инсталацията.\nАко изберете \"{{int:config-mssql-windowsauth}}\", ще се използват идентификационните данни на потребителя под който работи уеб сървъра.",
+       "config-mssql-web-auth": "Изберете начина за удостоверяване, който ще се използва от уеб сървъра за връзка със сървъра за бази от данни по време на нормалните операции на уикито.\nАко изберете \"{{int:config-mssql-windowsauth}}\", ще се използват идентификационните данни на потребителя под който работи уеб сървъра.",
        "config-mssql-sqlauth": "Удостоверяване чрез SQL Server",
        "config-mssql-windowsauth": "Удостоверяване чрез Windows",
        "config-site-name": "Име на уикито:",
index f34849b..70ef27a 100644 (file)
        "config-profile-help": "Викијата функционираат најдобро кога имаат што повеќе уредници.\nВо МедијаВики лесно се проверуваат скорешните промени, и лесно се исправа (технички: „враќа“) штетата направена од неупатени или злонамерни корисници.\n\nМногумина имаат најдено најразлични полезни примени за МедијаВики, но понекогаш не е лесно да убедите некого во предностите на вики-концептот.\nЗначи имате избор.\n\n'''{{int:config-profile-wiki}}''' — модел според кој секој може да уредува, дури и без најавување.\nАко имате вики со '''задолжително отворање на сметка''', тогаш добивате повеќе контрола, но ова може даги одврати спонтаните учесници.\n\n'''{{int:config-profile-fishbowl}}''' — може да уредуваат само уредници што имаат добиено дозвола за тоа, но јавноста може да ги гледа страниците, вклучувајќи ја нивната историја.\n'''{{int:config-profile-private}}''' — страниците се видливи и уредливи само за овластени корисници.\n\nПо воспоставката имате на избор и посложени кориснички права и поставки. Погледајте во [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights прирачникот].",
        "config-license": "Авторски права и лиценца:",
        "config-license-none": "Без подножје за лиценца",
-       "config-license-cc-by-sa": "Криејтив комонс НаведиИзвор СподелиПодИстиУслови",
-       "config-license-cc-by": "Криејтив комонс НаведиИзвор",
-       "config-license-cc-by-nc-sa": "Криејтив комонс НаведиИзвор-Некомерцијално-СподелиПодИстиУслови",
+       "config-license-cc-by-sa": "Криејтив комонс Наведи извор-Сподели под исти услови",
+       "config-license-cc-by": "Криејтив комонс Наведи извор",
+       "config-license-cc-by-nc-sa": "Криејтив комонс Наведи извор-Сподели под исти услови",
        "config-license-cc-0": "Криејтив комонс Нула (јавна сопственост)",
        "config-license-gfdl": "ГНУ-ова лиценца за слободна документација 1.3 или понова",
        "config-license-pd": "Јавна сопственост",
index 9d800a2..1c5c77e 100644 (file)
@@ -3467,4 +3467,4 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 }
 
-class_alias( 'Database', 'DatabaseBase' );
+class_alias( Database::class, 'DatabaseBase' );
index d394692..db5b7e5 100644 (file)
@@ -18,4 +18,4 @@ class Blob implements IBlob {
        }
 }
 
-class_alias( 'Wikimedia\Rdbms\Blob', 'Blob' );
+class_alias( Blob::class, 'Blob' );
index 7a25f03..7918f36 100644 (file)
@@ -32,4 +32,4 @@ interface Field {
        function isNullable();
 }
 
-class_alias( 'Wikimedia\Rdbms\Field', 'Field' );
+class_alias( Field::class, 'Field' );
index 71e5939..6d2bc0d 100644 (file)
@@ -461,13 +461,28 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
         * @param array $localFileRefs List of files
         */
        protected function saveFileDependencies( ResourceLoaderContext $context, $localFileRefs ) {
-               // Normalise array
-               $localFileRefs = array_values( array_unique( $localFileRefs ) );
-               sort( $localFileRefs );
 
                try {
+                       // Related bugs and performance considerations:
+                       // 1. Don't needlessly change the database value with the same list in a
+                       //    different order or with duplicates.
+                       // 2. Use relative paths to avoid ghost entries when $IP changes. (T111481)
+                       // 3. Don't needlessly replace the database with the same value
+                       //    just because $IP changed (e.g. when upgrading a wiki).
+                       // 4. Don't create an endless replace loop on every request for this
+                       //    module when '../' is used anywhere. Even though both are expanded
+                       //    (one expanded by getFileDependencies from the DB, the other is
+                       //    still raw as originally read by RL), the latter has not
+                       //    been normalized yet.
+
+                       // Normalise
+                       $localFileRefs = array_values( array_unique( $localFileRefs ) );
+                       sort( $localFileRefs );
+                       $localPaths = self::getRelativePaths( $localFileRefs );
+
+                       $storedPaths = self::getRelativePaths( $this->getFileDependencies( $context ) );
                        // If the list has been modified since last time we cached it, update the cache
-                       if ( $localFileRefs !== $this->getFileDependencies( $context ) ) {
+                       if ( $localPaths !== $storedPaths ) {
                                $vary = $context->getSkin() . '|' . $context->getLanguage();
                                $cache = ObjectCache::getLocalClusterInstance();
                                $key = $cache->makeKey( __METHOD__, $this->getName(), $vary );
@@ -476,8 +491,7 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
                                        return; // T124649; avoid write slams
                                }
 
-                               // Use relative paths to avoid ghost entries when $IP changes (T111481)
-                               $deps = FormatJson::encode( self::getRelativePaths( $localFileRefs ) );
+                               $deps = FormatJson::encode( $localPaths );
                                $dbw = wfGetDB( DB_MASTER );
                                $dbw->upsert( 'module_deps',
                                        [
index 14d6e05..e8574f4 100644 (file)
@@ -357,6 +357,11 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
                        }
                }
 
+               if ( !$wikiModules ) {
+                       // Nothing to preload
+                       return;
+               }
+
                $pageNames = array_keys( $allPages );
                sort( $pageNames );
                $hash = sha1( implode( '|', $pageNames ) );
index 0bfd4a2..55e228a 100644 (file)
@@ -291,15 +291,6 @@ EOD;
                foreach ( glob( $this->basepath . '/*.php' ) as $file ) {
                        $this->readFile( $file );
                }
-
-               // Legacy aliases (1.28)
-               $this->forceClassPath( 'DatabaseBase',
-                       $this->basepath . '/includes/libs/rdbms/database/Database.php' );
-               // Legacy aliases (1.29)
-               $this->forceClassPath( 'Blob',
-                       $this->basepath . '/includes/libs/rdbms/encasing/Blob.php' );
-               $this->forceClassPath( 'Field',
-                       $this->basepath . '/includes/libs/rdbms/field/Field.php' );
        }
 }
 
@@ -328,6 +319,11 @@ class ClassCollector {
         */
        protected $tokens;
 
+       /**
+        * @var array Class alias with target/name fields
+        */
+       protected $alias;
+
        /**
         * @var string $code PHP code (including <?php) to detect class names from
         * @return array List of FQCN detected within the tokens
@@ -336,6 +332,7 @@ class ClassCollector {
                $this->namespace = '';
                $this->classes = [];
                $this->startToken = null;
+               $this->alias = null;
                $this->tokens = [];
 
                foreach ( token_get_all( $code ) as $token ) {
@@ -358,6 +355,8 @@ class ClassCollector {
                if ( is_string( $token ) ) {
                        return;
                }
+               // Note: When changing class name discovery logic,
+               // AutoLoaderTest.php may also need to be updated.
                switch ( $token[0] ) {
                case T_NAMESPACE:
                case T_CLASS:
@@ -365,6 +364,12 @@ class ClassCollector {
                case T_TRAIT:
                case T_DOUBLE_COLON:
                        $this->startToken = $token;
+                       break;
+               case T_STRING:
+                       if ( $token[1] === 'class_alias' ) {
+                               $this->startToken = $token;
+                               $this->alias = [];
+                       }
                }
        }
 
@@ -388,6 +393,49 @@ class ClassCollector {
                        }
                        break;
 
+               case T_STRING:
+                       if ( $this->alias !== null ) {
+                               // Flow 1 - Two string literals:
+                               // - T_STRING  class_alias
+                               // - '('
+                               // - T_CONSTANT_ENCAPSED_STRING 'TargetClass'
+                               // - ','
+                               // - T_WHITESPACE
+                               // - T_CONSTANT_ENCAPSED_STRING 'AliasName'
+                               // - ')'
+                               // Flow 2 - Use of ::class syntax for first parameter
+                               // - T_STRING  class_alias
+                               // - '('
+                               // - T_STRING TargetClass
+                               // - T_DOUBLE_COLON ::
+                               // - T_CLASS class
+                               // - ','
+                               // - T_WHITESPACE
+                               // - T_CONSTANT_ENCAPSED_STRING 'AliasName'
+                               // - ')'
+                               if ( $token === '(' ) {
+                                       // Start of a function call to class_alias()
+                                       $this->alias = [ 'target' => false, 'name' => false ];
+                               } elseif ( $token === ',' ) {
+                                       // Record that we're past the first parameter
+                                       if ( $this->alias['target'] === false ) {
+                                               $this->alias['target'] = true;
+                                       }
+                               } elseif ( is_array( $token ) && $token[0] === T_CONSTANT_ENCAPSED_STRING ) {
+                                       if ( $this->alias['target'] === true ) {
+                                               // We already saw a first argument, this must be the second.
+                                               // Strip quotes from the string literal.
+                                               $this->alias['name'] = substr( $token[1], 1, -1 );
+                                       }
+                               } elseif ( $token === ')' ) {
+                                       // End of function call
+                                       $this->classes[] = $this->alias['name'];
+                                       $this->alias = null;
+                                       $this->startToken = null;
+                               }
+                       }
+                       break;
+
                case T_CLASS:
                case T_INTERFACE:
                case T_TRAIT:
index 2e71999..996af71 100644 (file)
        "rev-deleted-text-unhide": "Гэтая вэрсія старонкі была <strong>выдаленая</strong>.\nПадрабязнасьці могуць быць знойдзеныя ў [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале выдаленьняў].\nВы можаце [$1 праглядзець гэтую вэрсію], калі жадаеце.",
        "rev-suppressed-text-unhide": "Гэтая вэрсія старонкі была <strong>схаваная</strong>.\nПадрабязнасьці могуць быць знойдзеныя ў [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} журнале хаваньняў].\nВы можаце [$1 праглядзець гэтую вэрсію], калі жадаеце.",
        "rev-deleted-text-view": "Гэтая вэрсія старонкі была <strong>выдаленая</strong>.\nВы можаце праглядзець яе; падрабязнасьці могуць быць знойдзеныя ў [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале выдаленьняў].",
-       "rev-suppressed-text-view": "Гэтая вэрсія старонкі была '''схаваная'''.\nВы можаце яе праглядзець; падрабязнасьці могуць быць знойдзеныя ў  [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} журнале хаваньняў].",
+       "rev-suppressed-text-view": "Гэтая вэрсія старонкі была <strong>схаваная</strong>.\nВы можаце яе праглядзець; падрабязнасьці могуць быць знойдзеныя ў [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} журнале хаваньняў].",
        "rev-deleted-no-diff": "Вы ня можаце праглядаць гэтую розьніцу паміж вэрсіямі, таму што адна з вэрсіяў была '''выдаленая'''.\nМагчыма, падрабязнасьці могуць быць знойдзеныя ў [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале выдаленьняў].",
        "rev-suppressed-no-diff": "Вы ня можаце праглядзець гэтую розьніцу, таму што адна з вэрсіяў была '''выдаленая'''.",
        "rev-deleted-unhide-diff": "Адна з вэрсіяў гэтай старонкі была '''выдаленая'''.\nПадрабязнасьці могуць быць знойдзеныя ў [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале выдаленьняў].\nВы можаце праглядзець [$1 розьніцу паміж вэрсіямі], калі жадаеце.",
        "authmanager-authn-no-local-user": "Пададзеныя ўліковыя зьвесткі не зьвязаныя зь ніводным удзельнікам гэтай вікі.",
        "authmanager-authn-autocreate-failed": "Аўтаматычнае стварэньне лякальнага рахунку не атрымалася: $1",
        "authmanager-change-not-supported": "Пададзеныя ўліковыя зьвесткі ня могуць быць зьмененыя, бо яны ня будуць выкарыстаныя.",
+       "authmanager-create-disabled": "Стварэньне рахункаў адключанае.",
        "authmanager-realname-label": "Сапраўднае імя",
        "authmanager-provider-temporarypassword": "Часовы пароль",
        "changecredentials": "Зьмена ўліковых зьвестак",
index c378228..5abee6a 100644 (file)
        "activeusers-intro": "Гэта пералік удзельнікаў, якія нешта рабілі за апошнія $1 {{PLURAL:$1|дзень|дзён}}.",
        "activeusers-count": "$1 {{PLURAL:$1|дзеянне|дзеянні|дзеянняў}} за апошні{{PLURAL:$3| дзень|я $3 дні|я $3 дзён}}",
        "activeusers-from": "Паказ, пачынаючы з:",
-       "activeusers-groups": "Паказаць удзельнікаў, якія належаць да групаў:",
+       "activeusers-groups": "Паказаць удзельнікаў, якія належаць да груп:",
        "activeusers-noresult": "Няма такіх удзельнікаў.",
        "activeusers-submit": "Паказаць актыўных удзельнікаў",
        "listgrouprights": "Дазволы для груп удзельнікаў",
index dafddd5..0f96934 100644 (file)
        "continue-editing": "Продължаване към полето за редактиране",
        "previewconflict": "Този предварителен преглед отразява текста в горната текстова кутия така, както би се показал, ако съхраните.",
        "session_fail_preview": "За съжаление редакцията ви не успя да бъде обработена поради загуба на данните за текущата сесия.\n\nМоже би сте излезли от системата. <strong>Моля, уверете се, че сте влезли в профила си и опитайте отново.</strong>\nАко все още не работи, опитайте да [[Special:UserLogout|излезете]] и да влезете отново, също така проверете дали браузърът ви позволява бисквитки от този сайт.",
-       "session_fail_preview_html": "'''За съжаление редакцията ви не беше записана поради изтичането на сесията ви.'''\n\n''Тъй като {{SITENAME}} приема обикновен HTML, предварителният преглед е скрит като предпазна мярка срещу атаки чрез Джаваскрипт.''\n\n'''Опитайте отново. Ако все още не сработва, пробвайте да [[Special:UserLogout|излезете]] и влезете отново.'''",
+       "session_fail_preview_html": "За съжаление редакцията ви не беше записана поради изтичането на сесията ви.\n\n<em>Тъй като {{SITENAME}} приема обикновен HTML, предварителният преглед е скрит като предпазна мярка срещу атаки чрез JavaScript.</em>\n\n<strong>Ако това е обикновен опит за редактиране, моля опитайте отново.</strong>\nАко все още не сработва, пробвайте да [[Special:UserLogout|излезете]] и влезете отново, и се уверете, че браузъра ви приема бисквитки от този сайт.",
        "token_suffix_mismatch": "'''Редакцията ви беше отхвърлена, защото браузърът ви е развалил пунктуационните знаци в редакционната отметка. Евентуалното съхранение би унищожило съдържанието на страницата. Понякога това се случва при използването на грешно работещи анонимни междинни сървъри.'''",
        "edit_form_incomplete": "'''Някои части от формуляра за редактиране не достигнаха до сървъра; проверете дали редакциите ви са непокътнати и опитайте отново.'''",
        "editing": "Редактиране на „$1“",
index b96f8be..ea83241 100644 (file)
        "permissionserrorstext-withaction": "Du bist aus {{PLURAL:$1|dem folgenden Grund|den folgenden Gründen}} nicht berechtigt, $2:",
        "contentmodelediterror": "Du kannst diese Version nicht bearbeiten, da das Inhaltsmodell <code>$1</code> vom aktuellen Inhaltsmodell der Seite <code>$2</code> abweicht.",
        "recreate-moveddeleted-warn": "<strong>Achtung: Du erstellst eine Seite, die bereits früher gelöscht wurde.</strong>\n\nBitte prüfe sorgfältig, ob die erneute Seitenerstellung den Richtlinien entspricht.\nZu deiner Information folgt das Lösch- und Verschiebungs-Logbuch mit der Begründung für die vorhergehende Löschung:",
-       "moveddeleted-notice": "Diese Seite wurde gelöscht. Zur Information folgt das Lösch- und Verschiebungs-Logbuch dieser Seite.",
-       "moveddeleted-notice-recent": "Leider wurde diese Seite kürzlich gelöscht (innerhalb der letzten 24 Stunden).\nZur Information wird das Lösch- und Verschiebungs-Logbuch für die Seite unten angezeigt.",
+       "moveddeleted-notice": "Diese Seite wurde gelöscht.\nZur Information folgt das Lösch- und Verschiebungs-Logbuch dieser Seite.",
+       "moveddeleted-notice-recent": "Diese Seite wurde kürzlich gelöscht (innerhalb der letzten 24 Stunden).\nZur Information folgt das Lösch- und Verschiebungs-Logbuch dieser Seite.",
        "log-fulllog": "Alle Logbucheinträge ansehen",
        "edit-hook-aborted": "Die Bearbeitung wurde ohne Erklärung durch eine Schnittstelle abgebrochen.",
        "edit-gone-missing": "Die Seite konnte nicht aktualisiert werden.\nSie wurde anscheinend gelöscht.",
index 2b6ff4c..733f3f7 100644 (file)
        "missingsummary": "'''DİQET:''' Şıma jû xulasa nênuşte.\nEke şıma \"{{int:savearticle}}\" reyna bıtıknê, vırnayışê şıma bê xulasa qeyd beno.",
        "missingcommenttext": "Cêr de jû fıkır bınusên, şıma rê zehmet.",
        "missingcommentheader": "'''Diqet:''' Şıma seba nê fıkrvaci yew mewzu/sernuşte nênuşt.\nEke şıma reyna \"{{int:savearticle}}\" bıtıknê, vırnayışê şıa bê mewzu/sernuşte do qeyd bo.",
-       "summary-preview": "Verqaytê xulasa:",
+       "summary-preview": "Verasayışê xulasa:",
        "subject-preview": "Verqaytê mewzu:",
        "previewerrortext": "Verasayışê vırnayışê şıma de yew xeta veciya miyan.",
        "blockedtitle": "Karber blokekerdeo",
index 3d6e462..4632b32 100644 (file)
        "deleting-backlinks-warning": "<strong>Προσοχή:</strong>  [[Special:WhatLinksHere/{{FULLPAGENAME}}|Άλλες σελίδες]] συνδέουν ή ενσωματώνουν τη σελίδα που πρόκειται να διαγράψετε.",
        "rollback": "Επαναφορά επεξεργασιών",
        "rollbacklink": "αναστροφή",
-       "rollbacklinkcount": "Î\95Ï\80αναÏ\86οÏ\81ά $1 {{PLURAL:$1|επεξεργασίας|επεξεργασιών}}",
-       "rollbacklinkcount-morethan": "εÏ\80αναÏ\86οÏ\81ά περισσότερων από $1 {{PLURAL:$1|επεξεργασία|επεξεργασίες}}",
+       "rollbacklinkcount": "Î\91ναÏ\83Ï\84Ï\81οÏ\86ή $1 {{PLURAL:$1|επεξεργασίας|επεξεργασιών}}",
+       "rollbacklinkcount-morethan": "αναÏ\83Ï\84Ï\81οÏ\86ή περισσότερων από $1 {{PLURAL:$1|επεξεργασία|επεξεργασίες}}",
        "rollbackfailed": "Η επαναφορά απέτυχε.",
        "cantrollback": "Δεν είναι δυνατή η αναίρεση αυτής της αλλαγής, πρόκειται για την αρχική ενέργεια δημιουργίας της σελίδας.",
        "alreadyrolled": "Αδύνατον να αναιρεθεί η τελευταία αλλαγή της σελίδας [[:$1]] από το χρήστη ([[User:$2|$2]] ([[User talk:$2|Συζήτηση]]){{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]), διότι κάποιος έχει ήδη αναιρέσει την αλλαγή ή έχει αλλάξει εκ νέου τη σελίδα.\n\nΤελευταία αλλαγή από το χρήστη ([[User:$3|$3]] ([[User talk:$3|Συζήτηση]]){{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
index 53eceed..8de97e9 100644 (file)
        "editcomment": "The edit summary was: <em>$1</em>.",
        "revertpage": "Reverted edits by [[Special:Contributions/$2|$2]] ([[User talk:$2|talk]]) to last revision by [[User:$1|$1]]",
        "revertpage-nouser": "Reverted edits by a hidden user to last revision by {{GENDER:$1|[[User:$1|$1]]}}",
-       "rollback-success": "Reverted edits by $1;\nchanged back to last revision by $2.",
+       "rollback-success": "Reverted edits by {{GENDER:$3|$1}};\nchanged back to last revision by {{GENDER:$4|$2}}.",
        "rollback-success-notify": "Reverted edits by $1;\nchanged back to last revision by $2. [$3 Show changes]",
        "sessionfailure-title": "Session failure",
        "sessionfailure": "There seems to be a problem with your login session;\nthis action has been canceled as a precaution against session hijacking.\nGo back to the previous page, reload that page and then try again.",
index 824ec6f..eb89f59 100644 (file)
        "createacct-email-ph": "Sisesta e-posti aadress",
        "createacct-another-email-ph": "Sisesta e-posti aadress",
        "createaccountmail": "Kasuta juhuslikku parooli ja saada see määratud e-posti aadressile",
+       "createaccountmail-help": "Saab kasutada konto loomiseks teisele kasutajale ilma parooli teada saamata.",
        "createacct-realname": "Pärisnimi (valikuline)",
        "createaccountreason": "Põhjus:",
        "createacct-reason": "Põhjus",
        "createacct-reason-ph": "Miks lood teist kontot?",
+       "createacct-reason-help": "Sõnum, mida näidatakse konto loomise logis",
        "createacct-submit": "Loo konto",
        "createacct-another-submit": "Loo konto",
+       "createacct-continue-submit": "Jätka konto loomist",
+       "createacct-another-continue-submit": "Jätka konto loomist",
        "createacct-benefit-heading": "{{SITENAME}} on sinusuguste inimeste tehtud.",
        "createacct-benefit-body1": "{{PLURAL:$1|muudatus|muudatust}}",
        "createacct-benefit-body2": "{{PLURAL:$1|lehekülg|lehekülge}}",
        "nocookiesnew": "Kasutajakonto loodi, aga sa ei ole sisse logitud, sest {{SITENAME}} kasutab kasutajate tuvastamisel küpsiseid. Sinu brauseris on küpsised keelatud. Palun sea küpsised lubatuks ja logi siis oma vastse kasutajanime ning parooliga sisse.",
        "nocookieslogin": "{{SITENAME}} kasutab kasutajate tuvastamisel küpsiseid. Sinu brauseris on küpsised keelatud. Palun sea küpsised lubatuks ja proovi siis uuesti.",
        "nocookiesfornew": "Kasutajakonto jäi loomata, kuna me ei saanud selle allikat kindlaks teha.\nVeendu, et sul on küpsised lubatud, taaslaadi see lehekülg ja proovi uuesti.",
+       "createacct-loginerror": "Konto on edukalt loodud, aga automaatselt ei õnnestunud sisse logida. Et jätkata, [[Special:UserLogin|logi palun sisse käsitsi]].",
        "noname": "Sa ei sisestanud kasutajanime lubataval kujul.",
        "loginsuccesstitle": "Sisse logitud",
        "loginsuccess": "Oled sisse loginud. Sinu kasutajanimi on \"$1\".",
        "missingcommenttext": "Palun sisesta siit allapoole kommentaar.",
        "missingcommentheader": "<strong>Meeldetuletus:</strong> Sa pole kirjutanud kommentaarile teemat.\nKui klõpsad uuesti \"{{int:savearticle}}\", salvestatakse su kommentaar ilma teemata.",
        "summary-preview": "Resümee eelvaade:",
-       "subject-preview": "Alaosa pealkirja eelvaade:",
+       "subject-preview": "Resümee eelvaade:",
        "previewerrortext": "Sinu muudatuste eelvaatluse juures esines tõrge.",
        "blockedtitle": "Kasutaja on blokeeritud",
        "blockedtext": "'''Sinu kasutajanimi või IP-aadress on blokeeritud.'''\n\nBlokeeris $1.\nTema põhjendus on järgmine: ''$2''.\n\n* Blokeeringu algus: $8\n* Blokeeringu lõpp: $6\n* Sooviti blokeerida: $7\n\nKüsimuse arutamiseks võid pöörduda kasutaja $1 või mõne teise [[{{MediaWiki:Grouppage-sysop}}|administraatori]] poole.\n\nPane tähele, et sa ei saa kasutajale teadet saata, kui sa pole kinnitanud oma [[Special:Preferences|eelistuste lehel]] kehtivat e-posti aadressi.\n\nSinu praegune IP-aadress on $3 ning blokeeringu number on #$5. Lisa need andmed kõigile järelepärimistele, mida kavatsed teha.",
index 6b10aa7..cd7d2cc 100644 (file)
        "selfredirect": "<strong>Atención:</strong> Está redirixindo esta páxina a si mesma.\nQuizais especificou incorrectamente a páxina de destino ou poida que estea a editar unha páxina errónea.\nSe preme en \"{{int:savearticle}}\" de novo, crearase a redireción de calquera xeito.",
        "missingcommenttext": "Por favor, escriba un comentario a continuación.",
        "missingcommentheader": "<strong>Aviso:</strong> Non escribiu ningún texto no asunto deste comentario.\nSe preme en \"{{int:savearticle}}\" de novo, a súa edición gardarase sen el.",
-       "summary-preview": "Vista previa do resumo:",
+       "summary-preview": "Vista previa do resumo de edición:",
        "subject-preview": "Vista previa do asunto:",
        "previewerrortext": "Produciuse un erro ao intentar previsualizar os cambios.",
        "blockedtitle": "O usuario está bloqueado",
        "saveusergroups": "Gardar os grupos {{GENDER:$1|do usuario|da usuaria}}",
        "userrights-groupsmember": "Membro de:",
        "userrights-groupsmember-auto": "Membro implícito de:",
-       "userrights-groups-help": "Pode cambiar os grupos aos que {{GENDER:$1|o usuario|a usuaria}} pertence:\n* Se a caixa ten un sinal (✓) significa que {{GENDER:$1|o usuario|a usuaria}} pertence a ese grupo.\n* Se, pola contra, non o ten, significa que non pertence.\n* Un asterisco (*) indica que non pode eliminar o grupo unha vez que o engadiu, e viceversa.",
+       "userrights-groups-help": "Pode cambiar os grupos aos que {{GENDER:$1|o usuario|a usuaria}} pertence:\n* Se a caixa ten un sinal (✓) significa que {{GENDER:$1|o usuario|a usuaria}} pertence a ese grupo.\n* Se, pola contra, non o ten, significa que non pertence.\n* Un asterisco (*) indica que non pode eliminar o grupo unha vez que o engadiu, e viceversa.\n* Un # indica que só se pode atrasar a data de caducidade deste grupo; non se pode adiantar.",
        "userrights-reason": "Motivo:",
        "userrights-no-interwiki": "Non ten os permisos necesarios para editar os dereitos de usuario noutros wikis.",
        "userrights-nodatabase": "A base de datos \"$1\" non existe ou non é local.",
        "userrights-expiry-options": "1 día:1 día,1 semana:1 semana,1 mes:1 mes,3 meses:3 meses,6 meses:6 meses,1 ano:1 ano",
        "userrights-invalid-expiry": "O tempo de caducidade para o grupo \"$1\" non é válido.",
        "userrights-expiry-in-past": "O tempo de caducidade para o grupo \"$1\" está no pasado.",
+       "userrights-cannot-shorten-expiry": "Non pode adiantar a data de caducidade do grupo \"$1\". Só os usuarios con permisos para engadir e eliminar este grupo poden adiantar datas de caducidade.",
        "userrights-conflict": "Hai un conflito na modificación dos dereitos de usuario! Por favor, revíseo e confirme os seus cambios.",
        "group": "Grupo:",
        "group-user": "Usuarios",
index e075af2..c85e767 100644 (file)
@@ -26,6 +26,7 @@
        "tog-watchdefault": "Hanaraka ny pejy ary ny rakitra ovaiko",
        "tog-watchmoves": "Hanaraka ny pejy ary ny rakitra ovaiko anarana",
        "tog-watchdeletion": "Hanaraka ny pejy ary ny rakitra voafafako",
+       "tog-watchuploads": "Ampiana amin'ny pejy arahako ireo rakitra vaovao nalefako",
        "tog-watchrollback": "Hanaraka pejy nanaovako famoana",
        "tog-minordefault": "Mariho ho madinika foana aloha ny fanovana rehetra",
        "tog-previewontop": "Asehoy alohan'ny boaty fanovana ny tsipalotra",
        "tagline": "Avy amin'i {{SITENAME}}",
        "help": "Fanoroana",
        "search": "Tadiavo",
+       "search-ignored-headings": "#<!-- Avelao ho toa izao ity andalana ity --> <pre>\n# Ny lohatenim-pizarana dia tsy horaharahiana amin'ny karoka.\n# Ny fiovana atao eto dia hihatra rehefa voasoratra ao amin'ny tondro ilay pejy miaraka amin'ilay lohateny.\n# Azonao atao ny famerenana an-tondro an'ilay pejy amin'ny alalan'ny fanovana tsy misy inona inona.\n# Ny rariteny dia ireo manaraka:\n# *Izay andalana rehetra manomboka amin'ny \"#\" dia resaka\n# *Izay andalana tsy fotsy dia lohateny tsy horaharahiana, iaraka amin'ny haben-tsoratra\nTsiahy\nRohy ivelany\nJereo koa\n#</pre> <!-- Avelao ho toa izao ity andalana ity -->",
        "searchbutton": "Tadiavo",
        "go": "Ndao",
        "searcharticle": "Tsidiho",
        "passwordreset-emailtext-user": "Nisy mpikambana mitondra anarana $1 eo amin'i {{SITENAME}} nangataka fampatsiahivana mikasika ny kaontinao eo amin'i {{SITENAME}} ($4). Manana io adiresy imailaka {{PLURAL:$3|io kaontim-pikambana io|ireo kaontim-pikambana ireo}} :\n\n$2\n\nHitsahatra afaka {{PLURAL:$5|iray|$5}} andro {{PLURAL:$3|io|ireo}} tenimiafina {{PLURAL:$3|io|ireo}}. Mila miditra dien'izao ianao izao ary mifidy tenimiafina vaovao. Raha tsy avy aminao ity hataka ity na efa nahatadidy ny tenimiafinao taloha ianao, ary raha tsy tianao hovaina intsony ilay tenimiafinao, dia azonao tsy raharahiana ity hafatra ity ary mampiasa ny tenimiafinao taloha.",
        "passwordreset-emailelement": "Anaram-pikambana : \n$1\n\nTenimiafina miserana : \n$2",
        "passwordreset-emailsentemail": "Lasa ny mailaka famerenana tenimiafina.",
+       "passwordreset-nocaller": "Mila manitsy mpiantso",
+       "passwordreset-nosuchcaller": "Tsy misy ilay mpiantso: $1",
        "changeemail": "Hanova ny adiresy imailaka",
        "changeemail-header": "Hanova ny adiresy imailak'ilay kaonty",
        "changeemail-no-info": "Mila tafiditra ianao vao avaka mijery ity pejy ity.",
        "yourdiff": "Fampitahana",
        "copyrightwarning": "Ny zavatra rehetra apetraka amin'ny {{SITENAME}} dia raisina ho azo adika malalaka araka ny fahazoan-dalana $2 (Jereo $1 ny fanazavana fanampiny). Raha toa ka tianao ho anao manokana ny tahirin-kevitra dia aleo tsy apetraka ato.\n\n<b>AZA MAMPIASA TAHIRINKEVITRA TSY NAHAZOAN-DALANA</b>",
        "copyrightwarning2": "Ny fandraisana anjara ao amin'i {{SITENAME}} dia azo ovaina ary fafan'ny mpikambana hafa. Raha tsy tianao ho ampiasainan, ovaina na zarazaraina ny soratrao, dia aza alefa eto ilay vokatr'asanao<br />\nNy zava-tsoratanao eto dia vokatr'asa naverinao soratana na nodikainao tany amina loharano ao amin'ny vala sarababem-bahoaka na loharano malalaka hafa (Jereo $1 ho an'ny antsipirihany).\n\n'''Aza mampiasa tahirin-kevitra tsy nahazoan-dalana!'''",
+       "editpage-cannot-use-custom-model": "Tsy mety ovaina ny modelim-botoatin'ity pejy ity.",
        "longpageerror": "'''Hadisoana : Ny tahirin-tsoratra nalefanao dia manana halava {{PLURAL:$1|iray|$1}} kilooktety, izay lava kokoa nohon'ny fetra avo indridra izay natao ho {{PLURAL:$2|iray|$2}} kilooktety.'''\nTsy afaka tahirizina ilay tahirin-tsoratra.",
        "readonlywarning": "'''FAMPITANDREMANA: Nohidiana noho ny antony fikolokoloana aloha ny banky angona,\nkoa tsy afaka mitahiry ny fanovana nataonao aloha ianao izao. Angamba tokony hanao Couper coller aloha\nianao dia tehirizo anaty rakitra ny fanovanao mandra-paha.'''\n\nNy mpandrindra nanidy ny banky angona dia nanome ny antony : <br />$1",
        "protectedpagewarning": "'''FAMPITANDREMANA:  Voaaro ity pejy ity ka ny mpikambana manana ny fahazoan-dàlana sysop ihany no afaka manova azy.'''",
        "invalid-content-data": "Data anaty votoatiny tsy miady amin'ny fepetra",
        "content-not-allowed-here": "Votoatiny ''$1'' voarara eo amin'ny pejy [[$2]]",
        "editwarning-warning": "Mety hahavery ny fanovana nataonao ny fialanao amin'ity pejy ity.\nRaha tafiditra ianao dia azonao esorina ity fampitandremana ity ao amin'ny fizarana \"{{int:prefs-editing}}\" ao amin'ny safidinao.",
+       "editpage-invalidcontentmodel-title": "Andrefim-botoatiny tsy zaka",
+       "editpage-invalidcontentmodel-text": "Andrefim-botoatiny \"$1\" tsy zaka.",
        "editpage-notsupportedcontentformat-title": "Tsy zaka io andrefim-botoatiny io",
        "editpage-notsupportedcontentformat-text": "Tsy zakan'ny maodelim-botoatiny $1 ny firafi-botoatiny $1",
        "content-model-wikitext": "wiki-soratra",
        "content-model-css": "CSS",
        "content-json-empty-object": "Zavatra foana",
        "content-json-empty-array": "Tabilao foana",
+       "deprecated-self-close-category": "Pejy mampiasa balizy HTML mihidy ho azy izay tsy azo raisina",
        "duplicate-args-category": "Pejy mampiasa dika mitovy hevitra amin'ny fiantsoana endrika",
        "expensive-parserfunction-warning": "Tandremo : Betsaka loatra ny fanantsoana ny tao parser.\n\nTsy maintsy latsaky ny $2 ny tao, kanefa misy $1. {{PLURAL:$2||}}",
        "expensive-parserfunction-category": "Pejy mampiasa be loatra ny tao parser",
        "search-interwiki-caption": "zandri-tetikasa",
        "search-interwiki-default": "Valiny amin'ny $1 :",
        "search-interwiki-more": "(be kokoa)",
+       "search-interwiki-more-results": "Valiny be kokoa",
        "search-relatedarticle": "voadinika",
        "searchrelated": "voadinika",
        "searchall": "rehetra",
        "youremail": "Imailaka:",
        "username": "{{GENDER:$1}}Anaram-pikambana :",
        "prefs-memberingroups": "Mpikambana{{GENDER:$2}} ao amin'ny vondrona{{PLURAL:$1}}:",
+       "group-membership-link-with-expiry": "$1 (hatramin'i $2)",
        "prefs-registration": "Daty fidirana :",
        "yourrealname": "Tena anarana marina:",
        "yourlanguage": "Tenim-pirenena:",
        "prefswarning-warning": "Efa nanova tamin'ny safidinao tsy mbola voatahiry ianao. Raha miala amin'ity pejy ity amin'ny alalan'ny fanindriana an'i \"$1\" ianao dia tsy ho voavao ny safidinao.",
        "prefs-tabs-navigation-hint": "Torohevitra: afaka mampiasa ny zana-tsipika havia ary havanana ianao ho an'ny fitetezana ny vakizoro ao amin'ny lisi-bakizoro",
        "userrights": "Fandrindràna ny fahefahan'ny mpikambana",
-       "userrights-lookup-user": "Handrindra vondrom-pikambana",
+       "userrights-lookup-user": "Hisafidy mpikambana",
        "userrights-user-editname": "Manomeza solonanarana:",
-       "editusergroup": "Hanova satan'ny {{GENDER:$1|}}mpikambana",
+       "editusergroup": "Hampiditra vondrom-pikambana",
        "editinguser": "Fanovana ny zon'ny mpikambana <strong>{{GENDER:$1|}}[[User:$1|$1]]</strong> $2",
        "userrights-editusergroup": "Hanova vondrom-pikambana",
        "saveusergroups": "{{GENDER:$1|}}Tehirizo ny vondrom-pikambana",
        "userrights-changeable-col": "Ny gropy azonao ovaina",
        "userrights-unchangeable-col": "Ny gropy tsy azonao ovaina",
        "userrights-expiry-current": "Mitsahatra ny $1",
+       "userrights-expiry-none": "Tsy mitsahatra",
        "userrights-expiry": "Fitsaharana:",
+       "userrights-expiry-existing": "Fotoam-pitsaharana ankehitriny: $3, $2",
+       "userrights-expiry-othertime": "Fotoana hafa:",
+       "userrights-expiry-options": "1 andro:1 day,herinandro:1 week,1 volana:1 month,3 volana:3 months,6 volana:6 months,herintaona:1 year",
+       "userrights-invalid-expiry": "Tsy azo raisina ny fotoam-pitsaharana ho an'ny vondrona \"$1\".",
        "userrights-conflict": "Fifandonana fanovana zom-pikambana! Avereno vakiana ary marino ny fanovanao.",
        "group": "Gropy :",
        "group-user": "Mpikambana",
index d3ed9a8..3cfbe34 100644 (file)
        "permissionserrorstext": "Avètz pas la permission d’efectuar l’operacion demandada per {{PLURAL:$1|la rason seguenta|las rasons seguentas}} :",
        "permissionserrorstext-withaction": "Sètz pas autorizat(ada) a $2, per {{PLURAL:$1|la rason seguenta|las rasons seguentas}} :",
        "recreate-moveddeleted-warn": "'''Atencion : sètz a tornar crear una pagina qu'es estada suprimida precedentament.'''\n\nDemandatz-vos s'es vertadièrament apropriat de contunhar de l’editar.\nL’istoric de las supressions e dels cambiaments de nom es afichat çaijós :",
-       "moveddeleted-notice": "Aquesta pagina es estat suprimida.\nL'istoric de las supressions e dels cambiaments de nom es afichat çaijós coma referéncia.",
+       "moveddeleted-notice": "Aquesta pagina es estada suprimida.\nL'istoric de las supressions e dels cambiaments de nom es afichat çaijós coma referéncia.",
        "log-fulllog": "Veire lo jornal complet",
        "edit-hook-aborted": "Modificacion fracassada per croquet.\nCap d'explicacion pas balhada.",
        "edit-gone-missing": "A pas pogut metre a jorn la pagina.\nSembla que siá estada suprimida.",
index 2e02447..6ffc851 100644 (file)
        "permissionserrorstext-withaction": "This message is \"with action\" version of {{msg-mw|Permissionserrorstext}}.\n\nParameters:\n* $1 - the number of reasons that were found why the action cannot be performed\n* $2 - one of the action-* messages (for example {{msg-mw|action-edit}}) or other such messages tagged with {{tl|doc-action}} in their documentation\n\nPlease report at [[Support]] if you are unable to properly translate this message. Also see [[phab:T16246]] (now closed) for background.",
        "contentmodelediterror": "Error message shown when trying to edit an old revision with a content model different from that of the current revision\n* $1 - content model of the old revision\n* $2 - content model of the current revision",
        "recreate-moveddeleted-warn": "Warning shown when creating a page which has already been deleted. See for example [[Test]].",
-       "moveddeleted-notice": "Shown on top of a deleted page in normal view modus ([{{canonicalurl:Test}} example]).",
-       "moveddeleted-notice-recent": "Shown on top of a recently deleted page in normal view modus ([{{canonicalurl:Test}} example]).",
+       "moveddeleted-notice": "Shown on top of a deleted page in normal view modus ([{{canonicalurl:Test}} example]).\n\nSee also {{msg-mw|moveddeleted-notice-recent}}",
+       "moveddeleted-notice-recent": "Shown on top of a recently deleted page in normal view modus ([{{canonicalurl:Test}} example]).\n\nSee also {{msg-mw|moveddeleted-notice}}",
        "log-fulllog": "Used as link text.",
        "edit-hook-aborted": "Used as error message.\n\nSee also:\n* {{msg-mw|edit-gone-missing}}\n* {{msg-mw|edit-conflict}}\n* {{msg-mw|edit-no-change}}\n* {{msg-mw|edit-already-exists}}",
        "edit-gone-missing": "Used as error message.\n\nSee also:\n* {{msg-mw|edit-hook-aborted}}\n* {{msg-mw|edit-conflict}}\n* {{msg-mw|edit-no-change}}\n* {{msg-mw|edit-already-exists}}",
        "booksources-text": "Used in [[Special:BookSources/1]].\n\nThis message is followed by a list of links to other sites.\n\nSee also:\n* {{msg-mw|Booksources|title}}\n* {{msg-mw|Booksources-text|text}}",
        "booksources-invalid-isbn": "This message is displayed after an invalid ISBN is entered on [[Special:Booksources]].",
        "magiclink-tracking-rfc": "Name of the [[mw:Special:MyLanguage/Help:Tracking categories|tracking category]] where pages that use RFC magic links will be added.\n\nSee [https://en.wikipedia.org/wiki/Help:Magic_links#RFC Help:Magic links] for more information on RFC magic links.",
-       "magiclink-tracking-rfc-desc": "Description of the tracking category {{mw-msg|magiclink-tracking-rfc}}",
+       "magiclink-tracking-rfc-desc": "Description of the tracking category {{msg-mw|magiclink-tracking-rfc}}",
        "magiclink-tracking-pmid": "Name of the [[mw:Special:MyLanguage/Help:Tracking categories|tracking category]] where pages that use PMID magic links will be added.",
-       "magiclink-tracking-pmid-desc": "Description of the tracking category {{mw-msg|magiclink-tracking-pmid}}",
+       "magiclink-tracking-pmid-desc": "Description of the tracking category {{msg-mw|magiclink-tracking-pmid}}",
        "magiclink-tracking-isbn": "Name of the [[mw:Special:MyLanguage/Help:Tracking categories|tracking category]] where pages that use ISBN magic links will be added.",
-       "magiclink-tracking-isbn-desc": "Description of the tracking category {{mw-msg|magiclink-tracking-isbn}}",
+       "magiclink-tracking-isbn-desc": "Description of the tracking category {{msg-mw|magiclink-tracking-isbn}}",
        "rfcurl": "{{notranslate}}\nParameters:\n* $1 - RFC number\nSee also:\n* {{msg-mw|Pubmedurl}}",
        "pubmedurl": "{{notranslate}}\nParameters:\n* $1 - Pubmed number\nSee also:\n* {{msg-mw|Rfcurl}}",
        "specialloguserlabel": "Used in [[Special:Log]] as a label for an input field with which the log can be filtered for entries describing actions ''performed'' by the specified user.  \"Carried out\" and \"done\" are possible alternatives for \"performed\".",
        "editcomment": "Only shown if there is an edit {{msg-mw|Summary}}. Parameters:\n* $1 - the edit summary",
        "revertpage": "Parameters:\n* $1 - username 1\n* $2 - username 2\n* $3 - (Optional) revision ID of the revision reverted to\n* $4 - (Optional) timestamp of the revision reverted to\n* $5 - (Optional) revision ID of the revision reverted from\n* $6 - (Optional) timestamp of the revision reverted from\nSee also:\n* {{msg-mw|Revertpage-nouser}}\n{{Identical|Revert}}",
        "revertpage-nouser": "This is a confirmation message a user sees after reverting, when the username of the version is hidden with RevisionDelete.\n\nIn other cases the message {{msg-mw|Revertpage}} is used.\n\nParameters:\n* $1 - username 1, can be used for GENDER\n* $2 - (Optional) username 2\n* $3 - (Optional) revision ID of the revision reverted to\n* $4 - (Optional) timestamp of the revision reverted to\n* $5 - (Optional) revision ID of the revision reverted from\n* $6 - (Optional) timestamp of the revision reverted from",
-       "rollback-success": "This message shows up on screen after successful revert (generally visible only to admins). $1 describes user whose changes have been reverted, $2 describes user which produced version, which replaces reverted version.\n{{Identical|Revert}}\n{{Identical|Rollback}}",
+       "rollback-success": "This message shows up on screen after successful revert (generally visible only to admins). Parameters:\n* $1 - user whose changes have been reverted\n* $2 - user who produced version, which replaces reverted version\n* $3 - the first user's name, can be used for GENDER\n* $4 - the second user's name, can be used for GENDER\n{{Identical|Revert}}\n{{Identical|Rollback}}",
        "rollback-success-notify": "Notification shown after a successful revert.\n* $1 - User whose changes have been reverted\n* $2 - User that made the edit that was restored\n* $3 - Url to the diff of the rollback\nSee also:\n* {{msg-mw|showdiff}}\n{{related|rollback-success}}\n{{Format|jquerymsg}}",
        "sessionfailure-title": "Used as title of the error message {{msg-mw|Sessionfailure}}.",
        "sessionfailure": "Used as error message.\n\nThe title for this error message is {{msg-mw|Sessionfailure-title}}.",
index 104c497..f244230 100644 (file)
        "uploaddisabledtext": "கோப்பு பதிவேற்றங்கள் செயலிழக்கச் செய்யப்பட்டுள்ளன.",
        "php-uploaddisabledtext": "கோப்பு தரவேற்றம் PHP இல் முடக்கப்பட்டுள்ளது.தயவுகூர்ந்து file_uploads அமைப்பை சரிபார்க்கவும்.",
        "uploadscripted": "இந்தக் கோப்பு உலாவியால் பிழையாக விளங்கிக் கொள்ளக்கூடிய எச்.டி.எம்.எல். அல்லது வேறு நிரல்களைக் கொண்டுள்ளது.",
-       "uploadscriptednamespace": "இந்த SVG கோப்பு ஒரு சரியில்லாத பெயரிடைவெளியை \"<nowiki>$1</nowiki>\" கொண்டுள்ளது.",
+       "uploadscriptednamespace": "இந்த SVG கோப்பு ஒரு சரியில்லாத பெயரிடைவெளியை கொண்டுள்ளது \"<nowiki>$1</nowiki>\".",
        "uploadinvalidxml": "ஏற்றபட்ட கோப்பில் உள்ள XML ஆராய முடியாது.",
        "uploadvirus": "கோப்பு நச்சுநிரலைக் (வைரஸ்) கொண்டுள்ளது! விபரங்கள்:$1",
        "uploadjava": "இது ஒரு zip கோப்பு.இதில் java.class என்ற கோப்பு உள்ளது.\nஜாவா கோப்புகளை தகவலேற்றுவது தடைசெய்யப்பட்டுள்ளது.ஏனெனில் அது பாதுகாப்பு தடைகளை மீற வழிவகுக்கும்.",
index 20ef82c..85ef77a 100644 (file)
        "period-am": "AM",
        "period-pm": "PM",
        "pagecategories": "{{PLURAL:$1|分类}}",
-       "category_header": "å\88\86ç±»â\80\9c$1â\80\9d中的页面",
+       "category_header": "å\88\86ç±»â\80\9c$1â\80\9dä¸\8b的页面",
        "subcategories": "子分类",
        "category-media-header": "分类“$1”中的媒体文件",
        "category-empty": "<em>本分类目前不含有任何页面或媒体文件。</em>",
        "randompage-nopages": "在以下{{PLURAL:$2|名字空间}}中没有页面:$1。",
        "randomincategory": "分类中随机页面",
        "randomincategory-invalidcategory": "“$1”不是一个有效的分类名称。",
-       "randomincategory-nopages": "[[:Category:$1|$1]]å\88\86类中没有页面。",
+       "randomincategory-nopages": "[[:Category:$1|$1]]å\88\86ç±»ä¸\8b没有页面。",
        "randomincategory-category": "分类:",
        "randomincategory-legend": "分类中随机页面",
        "randomincategory-submit": "提交",
        "ancientpages": "最老页面",
        "move": "移动",
        "movethispage": "移动本页",
-       "unusedimagestext": "以下文件实际存在,但并没有插入任何页面。请注意,其他网站可能会使用直接URL链接某个文件,因此它即使被实际使用也可能在这里列出。",
+       "unusedimagestext": "存在以下没有插入任何页面的文件。请注意,其他网站可能会使用直接URL链接某个文件,因此它即使被实际使用也可能在这里列出。",
        "unusedcategoriestext": "以下分类页面实际存在,即使没有其它页面或分类利用它们。",
        "notargettitle": "无目标",
        "notargettext": "您还没有指定一个目标页面或用户以进行此项操作。",
        "variantname-gan-hant": "hant",
        "variantname-kk-cyrl": "kk-cyrl",
        "metadata": "元数据",
-       "metadata-help": "此文件中包含有扩展的信息。这些信息可能是由数码相机或扫描仪在创建或数字化过程中所添加的。\n\n如果此文件的源文件已经被修改,一些信息在修改后的文件中将不能完全反映出来。",
+       "metadata-help": "此文件中包含有额外的信息。这些信息可能是由数码相机或扫描仪在创建或数字化过程中所添加的。如果已自文件的初始状态修改,一些详细说明可能无法反映修改后的文件。",
        "metadata-expand": "显示详细资料",
        "metadata-collapse": "隐藏详细资料",
        "metadata-fields": "在本信息中所列出的 EXIF 元数据域将包含在图片显示页面,当元数据表损坏时只显示以下信息。\n其他的元数据默认为隐藏。\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
index 9044e45..2896d34 100644 (file)
        "variantname-gan-hans": "‪中文(简体)",
        "variantname-gan-hant": "‪中文(繁體)",
        "metadata": "詮釋資料",
-       "metadata-help": "此檔案包含額外的資訊,可能由數位相機或掃描機所建立的。\n若修改此檔案,部份資訊將無法保留。",
+       "metadata-help": "此檔案包含額外的資訊,可能由數位相機或掃描機所建立的。\n\n如果已自檔案初始狀態修改,一些詳細說明可能無法反映修改後的檔案。",
        "metadata-expand": "顯示詳細資料",
        "metadata-collapse": "隱藏詳細資料",
        "metadata-fields": "在本訊息中所列出的 EXIF 詮釋資料域將包含在圖片顯示頁面,當詮釋資料表損壞時只顯示以下訊息。\n其他的詮釋資料預設為隱藏。\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
index 4353dd7..0aaa4ff 100644 (file)
@@ -12,6 +12,7 @@
  *
  * @author Timo Tijhof, 2011-2012
  */
+/* eslint-env qunit */
 ( function ( mw, $ ) {
        'use strict';
 
index 72126f3..f709cff 100644 (file)
@@ -128,6 +128,7 @@ figure[typeof~='mw:Image/Frame'] > *:first-child > img,
 .mw-image-border > *:first-child > img {
        border: 1px solid #ccc;
        margin: 3px;
+       background: #fff;
 }
 
 /* Hide the caption for frameless and plain floated images */
index 7147f04..8d63902 100644 (file)
@@ -8,28 +8,28 @@
 
 .iw-headline {
        font-weight: bold;
-    font-size: 1rem;
-    font-size: 16px;
-    opacity: 0.7;
+       font-size: 1rem;
+       font-size: 16px;
+       opacity: 0.7;
 }
 
 .iw-results {
-    list-style: none;
+       list-style: none;
        margin: 0;
 }
 
 .iw-resultset {
        margin-bottom: 1.2em;
        background-color: #f2f4f7;
-    vertical-align: top;
-    width: 100%;
-    float: left;
-    list-style-type: none;
+       vertical-align: top;
+       width: 100%;
+       float: left;
+       list-style-type: none;
 }
 
 /* clearfix */
 .iw-result:after {
-    visibility: hidden;
+       visibility: hidden;
        display: block;
        font-size: 0;
        content: " ";
 }
 
 * html .interwiki-result { /* IE6 */
-    zoom: 1;
+       zoom: 1;
 }
 *:first-child + html .iw-resultset { /* IE7 */
-    zoom: 1;
+       zoom: 1;
 }
 
 /* padding each .iw-resultset section seperately.
@@ -52,55 +52,55 @@ header and footer. */
 .iw-result__title,
 .iw-result__content,
 .iw-result__footer {
-    padding: 0.25em 0.85em;
+       padding: 0.25em 0.85em;
 }
 
 /* definition titles appear inline,
 to resemble a traditional dictionary definition */
 .iw-resultset--definition .iw-result__title {
-    display: inline;
-    padding: 0;
+       display: inline;
+       padding: 0;
 }
 
 .iw-resultset > div:first-child {
-    padding-top: 0.85em;
+       padding-top: 0.85em;
 }
 
 .iw-resultset > div:last-child {
-    padding-bottom: 0.85em;
+       padding-bottom: 0.85em;
 }
 
 .iw-result__title {
-    font-size: 16px; /* rem fallback */
-    font-size: 1rem;
+       font-size: 16px; /* rem fallback */
+       font-size: 1rem;
 }
 
 .iw-result__title a.extiw {
-    color: #252525;
-    font-weight: bold;
+       color: #252525;
+       font-weight: bold;
 }
 
 .iw-result__content:after { /* clearfix */
-     visibility: hidden;
-     display: block;
-     font-size: 0;
-     content: " ";
-     clear: both;
-     height: 0;
+       visibility: hidden;
+       display: block;
+       font-size: 0;
+       content: " ";
+       clear: both;
+       height: 0;
 }
 
 .iw-result__footer {
-    float: right;
+       float: right;
 }
 
 .iw-result__icon {
-    display: inline-block;
-    width: 24px;
-    height: 24px;
-    vertical-align: middle;
-    margin-right: 0.25em;
-    background: url( images/special.search/definition-icon.svg ) no-repeat 0 0;
-    background-size: 100% 100%;
+       display: inline-block;
+       width: 24px;
+       height: 24px;
+       vertical-align: middle;
+       margin-right: 0.25em;
+       background: url( images/special.search/definition-icon.svg ) no-repeat 0 0;
+       background-size: 100% 100%;
 }
 
 @interwikiContentTypes: definition, travel, quotation, book, course, news, textbook, image;
@@ -108,78 +108,79 @@ to resemble a traditional dictionary definition */
 .generate-iwIcons();
 
 .generate-iwIcons( @i:1 ) when ( @i =< length( @interwikiContentTypes ) ) {
-     @iwIcon: extract( @interwikiContentTypes, @i );
+       @iwIcon: extract( @interwikiContentTypes, @i );
 
-    .iw-result__icon--@{iwIcon} {
-        /*  stylelint-disable-next-line function-url-quotes */
-        background-image: url( 'images/special.search/@{iwIcon}-icon.png' );
-        /*  stylelint-disable-next-line function-url-quotes */
-        background-image: url( 'images/special.search/@{iwIcon}-icon.svg' );
-    }
+       .iw-result__icon--@{iwIcon} {
+               /*  stylelint-disable-next-line function-url-quotes */
+               background-image: url( 'images/special.search/@{iwIcon}-icon.png' );
+               /*  stylelint-disable-next-line function-url-quotes */
+               background-image: url( 'images/special.search/@{iwIcon}-icon.svg' );
+       }
 
-    .generate-iwIcons( @i + 1 );
+       .generate-iwIcons( @i + 1 );
 }
 
 /* image search result */
 .iw-result__mini-gallery {
-    position: relative;
-    float: left;
-    width: 60%;
-    height: 200px;
-    box-sizing: border-box;
-    padding: 0.25rem;
+       position: relative;
+       float: left;
+       width: 60%;
+       height: 200px;
+       box-sizing: border-box;
+       padding: 0.25rem;
 }
 
-.iw-result__mini-gallery__image {
-    display: block;
-    position: relative;
-    width: 100%;
-    height: 100%;
-    background-size: cover;
-    background-repeat: no-repeat;
-    background-position: center center;
+/* second and third images are small */
+.iw-result__mini-gallery:nth-child( 2 ),
+.iw-result__mini-gallery:nth-child( 3 ) { /* stylelint-disable-line indentation */
+       width: 40%;
+       height: 100px;
 }
 
-.iw-result__mini-gallery__image:hover > .iw-result__mini-gallery__caption {
-    visibility: visible;
+.iw-result__mini-gallery__image {
+       display: block;
+       position: relative;
+       width: 100%;
+       height: 100%;
+       background-size: cover;
+       background-repeat: no-repeat;
+       background-position: center center;
 }
 
 .iw-result__mini-gallery__image > .iw-result__mini-gallery__caption { /* image gallery text */
-  visibility: hidden;
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  text-align: center;
-  color: #fff;
-  text-shadow: 0 0 10px rgba( 0, 0, 0, 0.4 ); /* improves legibility on white background*/
-  font-size: 0.8em;
-  padding: 5px;
-  background-color: rgba( 0, 0, 0, 0.5 );
+       visibility: hidden;
+       position: absolute;
+       bottom: 0;
+       left: 0;
+       text-align: center;
+       color: #fff;
+       text-shadow: 0 0 10px rgba( 0, 0, 0, 0.4 ); /* improves legibility on white background*/
+       font-size: 0.8em;
+       padding: 5px;
+       background-color: rgba( 0, 0, 0, 0.5 );
 }
 
-.iw-result__mini-gallery:nth-child(2),
-.iw-result__mini-gallery:nth-child(3) { /* second and third images are small */
-    width: 40%;
-    height: 100px;
+.iw-result__mini-gallery__image:hover > .iw-result__mini-gallery__caption {
+       visibility: visible;
 }
 
 /* different types of interwiki result boxes */
 /* quotation box */
 .iw-resultset--quotation .iw-result__content {
-    border-left: 4px solid #afb1b5;
-    margin-left: 1em;
-    padding-top: 0;
-    margin-top: 0.25em;
+       border-left: 4px solid #afb1b5;
+       margin-left: 1em;
+       padding-top: 0;
+       margin-top: 0.25em;
 }
-.iw-resultset--quotation .iw-result__title{
-    margin-left: 1em;
+.iw-resultset--quotation .iw-result__title {
+       margin-left: 1em;
 }
-.iw-result--quotation .iw-result__title:before{
-    content: ' — ';
-    display: inline-block;
+.iw-result--quotation .iw-result__title:before {
+       content: ' — ';
+       display: inline-block;
 }
 .iw-result--quotation .iw-result__footer {
-    text-align: right;
+       text-align: right;
 }
 
 /* no results
@@ -187,42 +188,37 @@ span the interwiki results across the bottom of the page.
 */
 
 .mw-search-nonefound ~ #mw-search-interwiki {
-    width: 100%;
+       width: 100%;
 }
 
 .mw-search-nonefound ~ #mw-search-interwiki .iw-resultset {
-    width: 30%;
-    max-width: 300px;
-    margin-left: 0.5em;
-    margin-right: 0.5em;
+       width: 30%;
+       max-width: 300px;
+       margin-left: 0.5em;
+       margin-right: 0.5em;
 }
 
 /* mobile */
 @media only screen and ( max-width: 768px ) {
-    #mw-interwiki-results {
-        width: 100%;
-    }
-    .mw-search-results {
-        max-width: none !important;
-    }
-    .iw-resultset {
-        width: 45% !important;
-        margin-left: 0.5em !important;
-        margin-right: 0.5em !important;
-    }
+       #mw-interwiki-results {
+               width: 100%;
+       }
+       .mw-search-results {
+               max-width: none !important;
+       }
+       .iw-resultset {
+               width: 45% !important;
+               margin-left: 0.5em !important;
+               margin-right: 0.5em !important;
+       }
 
 }
 
 @media only screen and ( max-width: 600px ) {
-    .iw-resultset {
-        width: 100% !important;
-        margin-left: 0 !important;
-        margin-right: 0 !important;
-        max-width: none !important;
-    }
-}
-
-/* Evil temporary hax for cawiki */
-#sisterproject {
-       display: none;
+       .iw-resultset {
+               width: 100% !important;
+               margin-left: 0 !important;
+               margin-right: 0 !important;
+               max-width: none !important;
+       }
 }
index 2346325..d57c1de 100644 (file)
@@ -87,7 +87,7 @@
                // Remove the inner padding and cancel buttons in Chrome on OS X and Safari on OS X
                &::-webkit-search-cancel-button,
                &::-webkit-search-decoration {
-                       -webkit-appearance: none;
+                       -webkit-appearance: none;
                }
        }
 }
index f70c03d..4a59dae 100644 (file)
@@ -1,3 +1,5 @@
+@import 'mediawiki.mixins';
+
 .mw-widgets-stashedFileWidget {
        display: inline-block;
        vertical-align: middle;
        vertical-align: middle;
        position: relative;
        overflow: hidden;
-       -webkit-box-sizing: border-box;
-          -moz-box-sizing: border-box;
-               box-sizing: border-box;
+       .box-sizing( border-box );
 
        > .mw-widgets-stashedFileWidget-label {
                line-height: 2.3em;
                margin: 0;
                overflow: hidden;
                white-space: nowrap;
-               -webkit-box-sizing: border-box;
-                  -moz-box-sizing: border-box;
-                               box-sizing: border-box;
+               .box-sizing( border-box );
                text-overflow: ellipsis;
                left: 0.5em;
                right: 2.375em;
index 660064a..37c0c9b 100644 (file)
                'stashwrongowner',
                'stashnosuchfilekey'
        ];
-       mw.log.deprecate( mw.Api, 'errors', mw.Api.errors, 'mw.Api.errors' );
+       mw.log.deprecate( mw.Api, 'errors', mw.Api.errors, null, 'mw.Api.errors' );
 
        /**
         * @static
                'duplicate',
                'exists'
        ];
-       mw.log.deprecate( mw.Api, 'warnings', mw.Api.warnings, 'mw.Api.warnings' );
+       mw.log.deprecate( mw.Api, 'warnings', mw.Api.warnings, null, 'mw.Api.warnings' );
 
 }( mediaWiki, jQuery ) );
index 1b9d2fb..a53e863 100644 (file)
@@ -44,9 +44,10 @@ tr.mw-htmlform-vertical-label td.mw-label {
        margin-left: 4px;
 }
 
-.mw-icon-question:lang(ar),
-.mw-icon-question:lang(fa),
-.mw-icon-question:lang(ur) {
+/* stylelint-disable indentation */
+.mw-icon-question:lang( ar ),
+.mw-icon-question:lang( fa ),
+.mw-icon-question:lang( ur ) {
        -webkit-transform: scaleX( -1 );
        -ms-transform: scaleX( -1 );
        transform: scaleX( -1 );
index e651c9c..3cb8e9d 100644 (file)
                        .removeAttr( 'height' );
 
                // Stretch image to take up the required size
-               if ( this.$thumbnail.width() > this.$thumbnail.height() ) {
-                       this.$img.attr( 'width', this.imageWidth + 'px' );
-               } else {
-                       this.$img.attr( 'height', this.imageHeight + 'px' );
-               }
+               this.$img.attr( 'height', ( this.imageHeight - this.$imgCaption.outerHeight() ) + 'px' );
 
                // Make the image smaller in case the current image
                // size is larger than the original file size.
                var imageLi = this.getCurrentImage(),
                        caption = imageLi.find( '.gallerytext' );
 
-               // Highlight current thumbnail
+               // The order of the following is important for size calculations
+               // 1. Highlight current thumbnail
                this.$gallery
                        .find( '.gallerybox.slideshow-current' )
                        .removeClass( 'slideshow-current' );
                imageLi.addClass( 'slideshow-current' );
 
-               // Show thumbnail stretched to the right size while the image loads
+               // 2. Show thumbnail
                this.$thumbnail = imageLi.find( 'img' );
                this.$img.attr( 'src', this.$thumbnail.attr( 'src' ) );
                this.$img.attr( 'alt', this.$thumbnail.attr( 'alt' ) );
                this.$imgLink.attr( 'href', imageLi.find( 'a' ).eq( 0 ).attr( 'href' ) );
-               this.setImageSize();
 
-               // Copy caption
+               // 3. Copy caption
                this.$imgCaption
                        .empty()
                        .append( caption.clone() );
 
-               // Load image at the required size
+               // 4. Stretch thumbnail to correct size
+               this.setImageSize();
+
+               // 5. Load image at the required size
                this.loadImage( this.$thumbnail ).done( function ( info, $img ) {
                        // Show this image to the user only if its still the current one
                        if ( this.$thumbnail.attr( 'src' ) === $img.attr( 'src' ) ) {
index 7060c4d..be6e3a8 100644 (file)
@@ -22537,25 +22537,6 @@ Ignore pipe between table row attributes
 
 !! end
 
-!!test
-Gallery override link with WikiLink (T36852)
-!! wikitext
-<gallery>
-File:foobar.jpg|caption|alt=galleryalt|link=InterWikiLink
-</gallery>
-!! html
-<ul class="gallery mw-gallery-traditional">
-               <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/InterWikiLink"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div>
-                       <div class="gallerytext">
-<p>caption
-</p>
-                       </div>
-               </div></li>
-</ul>
-
-!! end
-
 !!test
 Language parser function
 !! wikitext
diff --git a/tests/phpunit/includes/utils/ClassCollectorTest.php b/tests/phpunit/includes/utils/ClassCollectorTest.php
new file mode 100644 (file)
index 0000000..e8a228e
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @covers ClassCollector
+ */
+class ClassCollectorTest extends PHPUnit_Framework_TestCase {
+
+       public static function provideCases() {
+               return [
+                       [
+                               "class Foo {}",
+                               [ 'Foo' ],
+                       ],
+                       [
+                               "namespace Example;\nclass Foo {}\nclass Bar {}",
+                               [ 'Example\Foo', 'Example\Bar' ],
+                       ],
+                       [
+                               "class_alias( 'Foo', 'Bar' );",
+                               [ 'Bar' ],
+                       ],
+                       [
+                               "namespace Example;\nclass Foo {}\nclass_alias( 'Example\Foo', 'Foo' );",
+                               [ 'Example\Foo', 'Foo' ],
+                       ],
+                       [
+                               "namespace Example;\nclass Foo {}\nclass_alias( 'Example\Foo', 'Bar' );",
+                               [ 'Example\Foo', 'Bar' ],
+                       ],
+                       [
+                               "class_alias( Foo::class, 'Bar' );",
+                               [ 'Bar' ],
+                       ],
+                       [
+                               "namespace Example;\nclass Foo {}\nclass_alias( Foo::class, 'Bar' );",
+                               [ 'Example\Foo', 'Bar' ],
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideCases
+        */
+       public function testGetClasses( $code, array $classes, $message = null ) {
+               $cc = new ClassCollector();
+               $this->assertEquals( $classes, $cc->getClasses( "<?php\n$code" ), $message );
+       }
+}
index f36b51a..d81e8c6 100644 (file)
@@ -68,6 +68,7 @@ class AutoLoaderTest extends MediaWikiTestCase {
                        }
 
                        // We could use token_get_all() here, but this is faster
+                       // Note: Keep in sync with ClassCollector
                        $matches = [];
                        preg_match_all( '/
                                ^ [\t ]* (?:
@@ -78,6 +79,11 @@ class AutoLoaderTest extends MediaWikiTestCase {
                                                ([\'"]) (?P<original> [^\'"]+) \g{-2} \s* , \s*
                                                ([\'"]) (?P<alias> [^\'"]+ ) \g{-2} \s*
                                        \) \s* ;
+                               |
+                                       class_alias \s* \( \s*
+                                               (?P<originalStatic> [a-zA-Z0-9_]+)::class \s* , \s*
+                                               ([\'"]) (?P<aliasString> [^\'"]+ ) \g{-2} \s*
+                                       \) \s* ;
                                )
                        /imx', $contents, $matches, PREG_SET_ORDER );
 
@@ -95,11 +101,18 @@ class AutoLoaderTest extends MediaWikiTestCase {
 
                        foreach ( $matches as $match ) {
                                if ( !empty( $match['class'] ) ) {
+                                       // 'class Foo {}'
                                        $class = $fileNamespace . $match['class'];
                                        $actual[$class] = $file;
                                        $classesInFile[$class] = true;
                                } else {
-                                       $aliasesInFile[$match['alias']] = $match['original'];
+                                       if ( !empty( $match['original'] ) ) {
+                                               // 'class_alias( "Foo", "Bar" );'
+                                               $aliasesInFile[$match['alias']] = $match['original'];
+                                       } else {
+                                               // 'class_alias( Foo::class, "Bar" );'
+                                               $aliasesInFile[$match['aliasString']] = $fileNamespace . $match['originalStatic'];
+                                       }
                                }
                        }
 
diff --git a/tests/qunit/.eslintrc.json b/tests/qunit/.eslintrc.json
new file mode 100644 (file)
index 0000000..b3a46f4
--- /dev/null
@@ -0,0 +1,14 @@
+{
+       "extends": "../../.eslintrc.json",
+       "env": {
+               "qunit": true
+       },
+       "globals": {
+               "sinon": false
+       },
+       "rules": {
+               "operator-linebreak": 0,
+               "quote-props": [ "error", "as-needed" ],
+               "valid-jsdoc": 0
+       }
+}
index 5d1f1cd..1c79f6d 100644 (file)
@@ -133,7 +133,7 @@ class GenerateJqueryMsgData extends Maintenance {
                                . "// languages, and parser modes. Intended for use by a unit test framework by looping\n"
                                . "// through the object and comparing its parser return value with the 'result' property.\n"
                                . '// Last generated with ' . basename( __FILE__ ) . ' at ' . gmdate( 'r' ) . "\n"
-                               . "//jscs:disable\n"
+                               . "/* eslint-disable */\n"
                                . "\n"
                                . 'mediaWiki.libs.phpParserData = ' . FormatJson::encode( $phpParserData, true ) . ";\n";
 
index 498acc1..90dc1b2 100644 (file)
@@ -2,7 +2,7 @@
 // languages, and parser modes. Intended for use by a unit test framework by looping
 // through the object and comparing its parser return value with the 'result' property.
 // Last generated with generateJqueryMsgData.php at Fri, 10 Jul 2015 11:44:08 +0000
-//jscs:disable
+/* eslint-disable */
 
 mediaWiki.libs.phpParserData = {
     "messages": {
index 683dc1d..cef5c15 100644 (file)
@@ -1,8 +1,8 @@
-/*global CompletenessTest, sinon */
+/* global CompletenessTest, sinon */
 ( function ( $, mw, QUnit ) {
        'use strict';
 
-       var mwTestIgnore, mwTester, addons;
+       var mwTestIgnore, addons;
 
        /**
         * Add bogus to url to prevent IE crazy caching
@@ -26,6 +26,7 @@
        QUnit.config.testTimeout = 60 * 1000;
 
        // Reduce default animation duration from 400ms to 0ms for unit tests
+       // eslint-disable-next-line no-underscore-dangle
        $.fx.speeds._default = 0;
 
        // Add a checkbox to QUnit header to toggle MediaWiki ResourceLoader debug mode.
                        return false;
                };
 
-               mwTester = new CompletenessTest( mw, mwTestIgnore );
+               // eslint-disable-next-line no-new
+               new CompletenessTest( mw, mwTestIgnore );
        }
 
        /**
                }
 
                function freshMessagesCopy( custom ) {
-                       return $.extend( /*deep=*/true, {}, liveMessages.get(), custom );
+                       return $.extend( /* deep */true, {}, liveMessages.get(), custom );
                }
 
                /**
index 9af443d..e4b6157 100644 (file)
@@ -1,4 +1,6 @@
 ( function ( $ ) {
+       var getAccessKeyPrefixTestData, updateTooltipAccessKeysTestData;
+
        QUnit.module( 'jquery.accessKeyLabel', QUnit.newMwEnvironment( {
                messages: {
                        brackets: '[$1]',
@@ -6,40 +8,40 @@
                }
        } ) );
 
-       var getAccessKeyPrefixTestData = [
-                       // ua string, platform string, expected prefix
-                       // Internet Explorer
-                       [ 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)', 'Win32', 'alt-' ],
-                       [ 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)', 'Win32', 'alt-' ],
-                       [ 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; rv:11.0) like Gecko', 'Win64', 'alt-' ],
-                       [ 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136', 'Win64', 'alt-' ],
-                       // Firefox
-                       [ 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.19) Gecko/20110420 Firefox/3.5.19', 'MacIntel', 'ctrl-' ],
-                       [ 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110422 Ubuntu/10.10 (maverick) Firefox/3.6.17', 'Linux i686', 'alt-shift-' ],
-                       [ 'Mozilla/5.0 (Windows NT 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1', 'Win32', 'alt-shift-' ],
-                       [ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:50.0) Gecko/20100101 Firefox/50.0', 'MacIntel', 'ctrl-option-' ],
-                       [ 'Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20121202 Firefox/17.0 Iceweasel/17.0.1', 'Linux 1686', 'alt-shift-' ],
-                       [ 'Mozilla/5.0 (Windows NT 5.2; U; de; rv:1.8.0) Gecko/20060728 Firefox/1.5.0', 'Win32', 'alt-' ],
-                       // Safari / Konqueror
-                       [ 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; nl-nl) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7', 'MacIntel', 'ctrl-option-' ],
-                       [ 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; de-de) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 Safari/525.28.3', 'MacIntel', 'ctrl-' ],
-                       [ 'Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 Safari/525.29', 'Win32', 'alt-' ],
-                       [ 'Mozilla/5.0 (Windows; U; Windows NT 6.0; cs-CZ) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7', 'Win32', 'alt-' ],
-                       [ 'Mozilla/5.0 (X11; Linux i686) KHTML/4.9.1 (like Gecko) Konqueror/4.9', 'Linux i686', 'ctrl-' ],
-                       // Opera
-                       [ 'Opera/9.80 (Windows NT 5.1)', 'Win32', 'shift-esc-' ],
-                       [ 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36 OPR/15.0.1147.130', 'Win32', 'alt-shift-' ],
-                       // Chrome
-                       [ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30', 'MacIntel', 'ctrl-option-' ],
-                       [ 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.68 Safari/534.30', 'Linux i686', 'alt-shift-' ],
-                       // Unknown! Note: These aren't necessarily *right*, this is just
-                       // testing that we're getting the expected output based on the
-                       // platform.
-                       [ 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20021111 Chimera/0.6', 'MacPPC', 'ctrl-' ],
-                       [ 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5', 'Linux i686', 'alt-' ]
-               ],
-               // strings appended to title to make sure updateTooltipAccessKeys handles them correctly
-               updateTooltipAccessKeysTestData = [ '', ' [a]', ' [test-a]', ' [alt-b]' ];
+       getAccessKeyPrefixTestData = [
+               // ua string, platform string, expected prefix
+               // Internet Explorer
+               [ 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)', 'Win32', 'alt-' ],
+               [ 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)', 'Win32', 'alt-' ],
+               [ 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; rv:11.0) like Gecko', 'Win64', 'alt-' ],
+               [ 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136', 'Win64', 'alt-' ],
+               // Firefox
+               [ 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.19) Gecko/20110420 Firefox/3.5.19', 'MacIntel', 'ctrl-' ],
+               [ 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110422 Ubuntu/10.10 (maverick) Firefox/3.6.17', 'Linux i686', 'alt-shift-' ],
+               [ 'Mozilla/5.0 (Windows NT 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1', 'Win32', 'alt-shift-' ],
+               [ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:50.0) Gecko/20100101 Firefox/50.0', 'MacIntel', 'ctrl-option-' ],
+               [ 'Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20121202 Firefox/17.0 Iceweasel/17.0.1', 'Linux 1686', 'alt-shift-' ],
+               [ 'Mozilla/5.0 (Windows NT 5.2; U; de; rv:1.8.0) Gecko/20060728 Firefox/1.5.0', 'Win32', 'alt-' ],
+               // Safari / Konqueror
+               [ 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; nl-nl) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7', 'MacIntel', 'ctrl-option-' ],
+               [ 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; de-de) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 Safari/525.28.3', 'MacIntel', 'ctrl-' ],
+               [ 'Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 Safari/525.29', 'Win32', 'alt-' ],
+               [ 'Mozilla/5.0 (Windows; U; Windows NT 6.0; cs-CZ) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7', 'Win32', 'alt-' ],
+               [ 'Mozilla/5.0 (X11; Linux i686) KHTML/4.9.1 (like Gecko) Konqueror/4.9', 'Linux i686', 'ctrl-' ],
+               // Opera
+               [ 'Opera/9.80 (Windows NT 5.1)', 'Win32', 'shift-esc-' ],
+               [ 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36 OPR/15.0.1147.130', 'Win32', 'alt-shift-' ],
+               // Chrome
+               [ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30', 'MacIntel', 'ctrl-option-' ],
+               [ 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.68 Safari/534.30', 'Linux i686', 'alt-shift-' ],
+               // Unknown! Note: These aren't necessarily *right*, this is just
+               // testing that we're getting the expected output based on the
+               // platform.
+               [ 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20021111 Chimera/0.6', 'MacPPC', 'ctrl-' ],
+               [ 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5', 'Linux i686', 'alt-' ]
+       ];
+       // strings appended to title to make sure updateTooltipAccessKeys handles them correctly
+       updateTooltipAccessKeysTestData = [ '', ' [a]', ' [test-a]', ' [alt-b]' ];
 
        function makeInput( title, accessKey ) {
                // The properties aren't escaped, so make sure you don't call this function with values that need to be escaped!
@@ -78,8 +80,8 @@
        } );
 
        QUnit.test( 'updateTooltipAccessKeys - with access key', function ( assert ) {
-               $.fn.updateTooltipAccessKeys.setTestMode( true );
                var i, oldTitle, $input, newTitle;
+               $.fn.updateTooltipAccessKeys.setTestMode( true );
                for ( i = 0; i < updateTooltipAccessKeysTestData.length; i++ ) {
                        oldTitle = 'Title' + updateTooltipAccessKeysTestData[ i ];
                        $input = $( makeInput( oldTitle, 'a' ) );
@@ -91,9 +93,9 @@
        } );
 
        QUnit.test( 'updateTooltipAccessKeys with label element', function ( assert ) {
+               var html, $label, $input;
                $.fn.updateTooltipAccessKeys.setTestMode( true );
-               var html = '<label for="testInput" title="Title">Label</label><input id="testInput" accessKey="a" />',
-                       $label, $input;
+               html = '<label for="testInput" title="Title">Label</label><input id="testInput" accessKey="a" />';
                $( '#qunit-fixture' ).html( html );
                $label = $( '#qunit-fixture label' );
                $input = $( '#qunit-fixture input' );
        } );
 
        QUnit.test( 'updateTooltipAccessKeys with label element as parent', function ( assert ) {
+               var html, $label, $input;
                $.fn.updateTooltipAccessKeys.setTestMode( true );
-               var html = '<label title="Title">Label<input id="testInput" accessKey="a" /></label>',
-               $label, $input;
+               html = '<label title="Title">Label<input id="testInput" accessKey="a" /></label>';
                $( '#qunit-fixture' ).html( html );
                $label = $( '#qunit-fixture label' );
                $input = $( '#qunit-fixture input' );
index 804d1ca..c7b7cc0 100644 (file)
                        expected: ''
                }, options );
 
-               QUnit.asyncTest( opt.description, 1, function ( assert ) {
-                       setTimeout( function () {
-                               opt.$input.appendTo( '#qunit-fixture' );
+               QUnit.test( opt.description, function ( assert ) {
+                       opt.$input.appendTo( '#qunit-fixture' );
 
-                               // Simulate pressing keys for each of the sample characters
-                               addChars( opt.$input, opt.sample );
+                       // Simulate pressing keys for each of the sample characters
+                       addChars( opt.$input, opt.sample );
 
-                               assert.equal(
-                                       opt.$input.val(),
-                                       opt.expected,
-                                       'New value matches the expected string'
-                               );
-
-                               QUnit.start();
-                       } );
+                       assert.equal(
+                               opt.$input.val(),
+                               opt.expected,
+                               'New value matches the expected string'
+                       );
                } );
        }
 
        } );
 
        QUnit.test( 'Confirm properties and attributes set', function ( assert ) {
-               var $el, $elA, $elB;
+               var $el;
 
                $el = $( '<input>' ).attr( 'type', 'text' )
                        .attr( 'maxlength', '7' )
 
                assert.strictEqual( $el.attr( 'maxlength' ), undefined, 'maxlength attribute removed for limit with callback' );
 
-               $elA = $( '<input>' ).attr( 'type', 'text' )
+               $( '<input>' ).attr( 'type', 'text' )
                        .addClass( 'mw-test-byteLimit-foo' )
                        .attr( 'maxlength', '7' )
                        .appendTo( '#qunit-fixture' );
 
-               $elB = $( '<input>' ).attr( 'type', 'text' )
+               $( '<input>' ).attr( 'type', 'text' )
                        .addClass( 'mw-test-byteLimit-foo' )
                        .attr( 'maxlength', '12' )
                        .appendTo( '#qunit-fixture' );
        QUnit.test( 'Trim from insertion when limit exceeded', function ( assert ) {
                var $el;
 
-               // Use a new <input /> because the bug only occurs on the first time
+               // Use a new <input> because the bug only occurs on the first time
                // the limit it reached (T42850)
                $el = $( '<input>' ).attr( 'type', 'text' )
                        .appendTo( '#qunit-fixture' )
index 2878999..74d8509 100644 (file)
@@ -4,7 +4,7 @@
        QUnit.test( 'getAttrs()', function ( assert ) {
                var attrs = {
                                foo: 'bar',
-                               'class': 'lorem',
+                               class: 'lorem',
                                'data-foo': 'data value'
                        },
                        $el = $( '<div>' ).attr( attrs );
index 2f9e960..6a265eb 100644 (file)
@@ -7,8 +7,8 @@
        } );
 
        QUnit.test( 'bracketedDevicePixelRatio', function ( assert ) {
-               var devicePixelRatio = $.devicePixelRatio();
-               assert.equal( typeof devicePixelRatio, 'number', '$.bracketedDevicePixelRatio() returns a number' );
+               var ratio = $.bracketedDevicePixelRatio();
+               assert.equal( typeof ratio, 'number', '$.bracketedDevicePixelRatio() returns a number' );
        } );
 
        QUnit.test( 'bracketDevicePixelRatio', function ( assert ) {
index 9f87596..0dac22e 100644 (file)
        QUnit.module( 'jquery.highlightText', QUnit.newMwEnvironment() );
 
        QUnit.test( 'Check', function ( assert ) {
-               var $fixture, cases = [
-                       {
-                               desc: 'Test 001',
-                               text: 'Blue Öyster Cult',
-                               highlight: 'Blue',
-                               expected: '<span class="highlight">Blue</span> Öyster Cult'
-                       },
-                       {
-                               desc: 'Test 002',
-                               text: 'Blue Öyster Cult',
-                               highlight: 'Blue ',
-                               expected: '<span class="highlight">Blue</span> Öyster Cult'
-                       },
-                       {
-                               desc: 'Test 003',
-                               text: 'Blue Öyster Cult',
-                               highlight: 'Blue Ö',
-                               expected: '<span class="highlight">Blue</span> <span class="highlight">Ö</span>yster Cult'
-                       },
-                       {
-                               desc: 'Test 004',
-                               text: 'Blue Öyster Cult',
-                               highlight: 'Blue Öy',
-                               expected: '<span class="highlight">Blue</span> <span class="highlight">Öy</span>ster Cult'
-                       },
-                       {
-                               desc: 'Test 005',
-                               text: 'Blue Öyster Cult',
-                               highlight: ' Blue',
-                               expected: '<span class="highlight">Blue</span> Öyster Cult'
-                       },
-                       {
-                               desc: 'Test 006',
-                               text: 'Blue Öyster Cult',
-                               highlight: ' Blue ',
-                               expected: '<span class="highlight">Blue</span> Öyster Cult'
-                       },
-                       {
-                               desc: 'Test 007',
-                               text: 'Blue Öyster Cult',
-                               highlight: ' Blue Ö',
-                               expected: '<span class="highlight">Blue</span> <span class="highlight">Ö</span>yster Cult'
-                       },
-                       {
-                               desc: 'Test 008',
-                               text: 'Blue Öyster Cult',
-                               highlight: ' Blue Öy',
-                               expected: '<span class="highlight">Blue</span> <span class="highlight">Öy</span>ster Cult'
-                       },
-                       {
-                               desc: 'Test 009: Highlighter broken on starting Umlaut?',
-                               text: 'Österreich',
-                               highlight: 'Österreich',
-                               expected: '<span class="highlight">Österreich</span>'
-                       },
-                       {
-                               desc: 'Test 010: Highlighter broken on starting Umlaut?',
-                               text: 'Österreich',
-                               highlight: 'Ö',
-                               expected: '<span class="highlight">Ö</span>sterreich'
-                       },
-                       {
-                               desc: 'Test 011: Highlighter broken on starting Umlaut?',
-                               text: 'Österreich',
-                               highlight: 'Öst',
-                               expected: '<span class="highlight">Öst</span>erreich'
-                       },
-                       {
-                               desc: 'Test 012: Highlighter broken on starting Umlaut?',
-                               text: 'Österreich',
-                               highlight: 'Oe',
-                               expected: 'Österreich'
-                       },
-                       {
-                               desc: 'Test 013: Highlighter broken on punctuation mark?',
-                               text: 'So good. To be there',
-                               highlight: 'good',
-                               expected: 'So <span class="highlight">good</span>. To be there'
-                       },
-                       {
-                               desc: 'Test 014: Highlighter broken on space?',
-                               text: 'So good. To be there',
-                               highlight: 'be',
-                               expected: 'So good. To <span class="highlight">be</span> there'
-                       },
-                       {
-                               desc: 'Test 015: Highlighter broken on space?',
-                               text: 'So good. To be there',
-                               highlight: ' be',
-                               expected: 'So good. To <span class="highlight">be</span> there'
-                       },
-                       {
-                               desc: 'Test 016: Highlighter broken on space?',
-                               text: 'So good. To be there',
-                               highlight: 'be ',
-                               expected: 'So good. To <span class="highlight">be</span> there'
-                       },
-                       {
-                               desc: 'Test 017: Highlighter broken on space?',
-                               text: 'So good. To be there',
-                               highlight: ' be ',
-                               expected: 'So good. To <span class="highlight">be</span> there'
-                       },
-                       {
-                               desc: 'Test 018: en de Highlighter broken on special character at the end?',
-                               text: 'So good. xbß',
-                               highlight: 'xbß',
-                               expected: 'So good. <span class="highlight">xbß</span>'
-                       },
-                       {
-                               desc: 'Test 019: en de Highlighter broken on special character at the end?',
-                               text: 'So good. xbß.',
-                               highlight: 'xbß.',
-                               expected: 'So good. <span class="highlight">xbß.</span>'
-                       },
-                       {
-                               desc: 'Test 020: RTL he Hebrew',
-                               text: 'חסיד אומות העולם',
-                               highlight: 'חסיד אומות העולם',
-                               expected: '<span class="highlight">חסיד</span> <span class="highlight">אומות</span> <span class="highlight">העולם</span>'
-                       },
-                       {
-                               desc: 'Test 021: RTL he Hebrew',
-                               text: 'חסיד אומות העולם',
-                               highlight: 'חסי',
-                               expected: '<span class="highlight">חסי</span>ד אומות העולם'
-                       },
-                       {
-                               desc: 'Test 022: ja Japanese',
-                               text: '諸国民の中の正義の人',
-                               highlight: '諸国民の中の正義の人',
-                               expected: '<span class="highlight">諸国民の中の正義の人</span>'
-                       },
-                       {
-                               desc: 'Test 023: ja Japanese',
-                               text: '諸国民の中の正義の人',
-                               highlight: '諸国',
-                               expected: '<span class="highlight">諸国</span>民の中の正義の人'
-                       },
-                       {
-                               desc: 'Test 024: fr French text and « french quotes » (guillemets)',
-                               text: '« L\'oiseau est sur l’île »',
-                               highlight: '« L\'oiseau est sur l’île »',
-                               expected: '<span class="highlight">«</span> <span class="highlight">L\'oiseau</span> <span class="highlight">est</span> <span class="highlight">sur</span> <span class="highlight">l’île</span> <span class="highlight">»</span>'
-                       },
-                       {
-                               desc: 'Test 025: fr French text and « french quotes » (guillemets)',
-                               text: '« L\'oiseau est sur l’île »',
-                               highlight: '« L\'oise',
-                               expected: '<span class="highlight">«</span> <span class="highlight">L\'oise</span>au est sur l’île »'
-                       },
-                       {
-                               desc: 'Test 025a: fr French text and « french quotes » (guillemets) - does it match the single strings "«" and "L" separately?',
-                               text: '« L\'oiseau est sur l’île »',
-                               highlight: '« L',
-                               expected: '<span class="highlight">«</span> <span class="highlight">L</span>\'oiseau est sur <span class="highlight">l</span>’île »'
-                       },
-                       {
-                               desc: 'Test 026: ru Russian',
-                               text: 'Праведники мира',
-                               highlight: 'Праведники мира',
-                               expected: '<span class="highlight">Праведники</span> <span class="highlight">мира</span>'
-                       },
-                       {
-                               desc: 'Test 027: ru Russian',
-                               text: 'Праведники мира',
-                               highlight: 'Праве',
-                               expected: '<span class="highlight">Праве</span>дники мира'
-                       },
-                       {
-                               desc: 'Test 028 ka Georgian',
-                               text: 'მთავარი გვერდი',
-                               highlight: 'მთავარი გვერდი',
-                               expected: '<span class="highlight">მთავარი</span> <span class="highlight">გვერდი</span>'
-                       },
-                       {
-                               desc: 'Test 029 ka Georgian',
-                               text: 'მთავარი გვერდი',
-                               highlight: 'მთა',
-                               expected: '<span class="highlight">მთა</span>ვარი გვერდი'
-                       },
-                       {
-                               desc: 'Test 030 hy Armenian',
-                               text: 'Նոնա Գափրինդաշվիլի',
-                               highlight: 'Նոնա Գափրինդաշվիլի',
-                               expected: '<span class="highlight">Նոնա</span> <span class="highlight">Գափրինդաշվիլի</span>'
-                       },
-                       {
-                               desc: 'Test 031 hy Armenian',
-                               text: 'Նոնա Գափրինդաշվիլի',
-                               highlight: 'Նոն',
-                               expected: '<span class="highlight">Նոն</span>ա Գափրինդաշվիլի'
-                       },
-                       {
-                               desc: 'Test 032: th Thai',
-                               text: 'พอล แอร์ดิช',
-                               highlight: 'พอล แอร์ดิช',
-                               expected: '<span class="highlight">พอล</span> <span class="highlight">แอร์ดิช</span>'
-                       },
-                       {
-                               desc: 'Test 033: th Thai',
-                               text: 'พอล แอร์ดิช',
-                               highlight: 'พอ',
-                               expected: '<span class="highlight">พอ</span>ล แอร์ดิช'
-                       },
-                       {
-                               desc: 'Test 034: RTL ar Arabic',
-                               text: 'بول إيردوس',
-                               highlight: 'بول إيردوس',
-                               expected: '<span class="highlight">بول</span> <span class="highlight">إيردوس</span>'
-                       },
-                       {
-                               desc: 'Test 035: RTL ar Arabic',
-                               text: 'بول إيردوس',
-                               highlight: 'بو',
-                               expected: '<span class="highlight">بو</span>ل إيردوس'
-                       }
-               ];
+               var $fixture,
+                       cases = [
+                               {
+                                       desc: 'Test 001',
+                                       text: 'Blue Öyster Cult',
+                                       highlight: 'Blue',
+                                       expected: '<span class="highlight">Blue</span> Öyster Cult'
+                               },
+                               {
+                                       desc: 'Test 002',
+                                       text: 'Blue Öyster Cult',
+                                       highlight: 'Blue ',
+                                       expected: '<span class="highlight">Blue</span> Öyster Cult'
+                               },
+                               {
+                                       desc: 'Test 003',
+                                       text: 'Blue Öyster Cult',
+                                       highlight: 'Blue Ö',
+                                       expected: '<span class="highlight">Blue</span> <span class="highlight">Ö</span>yster Cult'
+                               },
+                               {
+                                       desc: 'Test 004',
+                                       text: 'Blue Öyster Cult',
+                                       highlight: 'Blue Öy',
+                                       expected: '<span class="highlight">Blue</span> <span class="highlight">Öy</span>ster Cult'
+                               },
+                               {
+                                       desc: 'Test 005',
+                                       text: 'Blue Öyster Cult',
+                                       highlight: ' Blue',
+                                       expected: '<span class="highlight">Blue</span> Öyster Cult'
+                               },
+                               {
+                                       desc: 'Test 006',
+                                       text: 'Blue Öyster Cult',
+                                       highlight: ' Blue ',
+                                       expected: '<span class="highlight">Blue</span> Öyster Cult'
+                               },
+                               {
+                                       desc: 'Test 007',
+                                       text: 'Blue Öyster Cult',
+                                       highlight: ' Blue Ö',
+                                       expected: '<span class="highlight">Blue</span> <span class="highlight">Ö</span>yster Cult'
+                               },
+                               {
+                                       desc: 'Test 008',
+                                       text: 'Blue Öyster Cult',
+                                       highlight: ' Blue Öy',
+                                       expected: '<span class="highlight">Blue</span> <span class="highlight">Öy</span>ster Cult'
+                               },
+                               {
+                                       desc: 'Test 009: Highlighter broken on starting Umlaut?',
+                                       text: 'Österreich',
+                                       highlight: 'Österreich',
+                                       expected: '<span class="highlight">Österreich</span>'
+                               },
+                               {
+                                       desc: 'Test 010: Highlighter broken on starting Umlaut?',
+                                       text: 'Österreich',
+                                       highlight: 'Ö',
+                                       expected: '<span class="highlight">Ö</span>sterreich'
+                               },
+                               {
+                                       desc: 'Test 011: Highlighter broken on starting Umlaut?',
+                                       text: 'Österreich',
+                                       highlight: 'Öst',
+                                       expected: '<span class="highlight">Öst</span>erreich'
+                               },
+                               {
+                                       desc: 'Test 012: Highlighter broken on starting Umlaut?',
+                                       text: 'Österreich',
+                                       highlight: 'Oe',
+                                       expected: 'Österreich'
+                               },
+                               {
+                                       desc: 'Test 013: Highlighter broken on punctuation mark?',
+                                       text: 'So good. To be there',
+                                       highlight: 'good',
+                                       expected: 'So <span class="highlight">good</span>. To be there'
+                               },
+                               {
+                                       desc: 'Test 014: Highlighter broken on space?',
+                                       text: 'So good. To be there',
+                                       highlight: 'be',
+                                       expected: 'So good. To <span class="highlight">be</span> there'
+                               },
+                               {
+                                       desc: 'Test 015: Highlighter broken on space?',
+                                       text: 'So good. To be there',
+                                       highlight: ' be',
+                                       expected: 'So good. To <span class="highlight">be</span> there'
+                               },
+                               {
+                                       desc: 'Test 016: Highlighter broken on space?',
+                                       text: 'So good. To be there',
+                                       highlight: 'be ',
+                                       expected: 'So good. To <span class="highlight">be</span> there'
+                               },
+                               {
+                                       desc: 'Test 017: Highlighter broken on space?',
+                                       text: 'So good. To be there',
+                                       highlight: ' be ',
+                                       expected: 'So good. To <span class="highlight">be</span> there'
+                               },
+                               {
+                                       desc: 'Test 018: en de Highlighter broken on special character at the end?',
+                                       text: 'So good. xbß',
+                                       highlight: 'xbß',
+                                       expected: 'So good. <span class="highlight">xbß</span>'
+                               },
+                               {
+                                       desc: 'Test 019: en de Highlighter broken on special character at the end?',
+                                       text: 'So good. xbß.',
+                                       highlight: 'xbß.',
+                                       expected: 'So good. <span class="highlight">xbß.</span>'
+                               },
+                               {
+                                       desc: 'Test 020: RTL he Hebrew',
+                                       text: 'חסיד אומות העולם',
+                                       highlight: 'חסיד אומות העולם',
+                                       expected: '<span class="highlight">חסיד</span> <span class="highlight">אומות</span> <span class="highlight">העולם</span>'
+                               },
+                               {
+                                       desc: 'Test 021: RTL he Hebrew',
+                                       text: 'חסיד אומות העולם',
+                                       highlight: 'חסי',
+                                       expected: '<span class="highlight">חסי</span>ד אומות העולם'
+                               },
+                               {
+                                       desc: 'Test 022: ja Japanese',
+                                       text: '諸国民の中の正義の人',
+                                       highlight: '諸国民の中の正義の人',
+                                       expected: '<span class="highlight">諸国民の中の正義の人</span>'
+                               },
+                               {
+                                       desc: 'Test 023: ja Japanese',
+                                       text: '諸国民の中の正義の人',
+                                       highlight: '諸国',
+                                       expected: '<span class="highlight">諸国</span>民の中の正義の人'
+                               },
+                               {
+                                       desc: 'Test 024: fr French text and « french quotes » (guillemets)',
+                                       text: '« L\'oiseau est sur l’île »',
+                                       highlight: '« L\'oiseau est sur l’île »',
+                                       expected: '<span class="highlight">«</span> <span class="highlight">L\'oiseau</span> <span class="highlight">est</span> <span class="highlight">sur</span> <span class="highlight">l’île</span> <span class="highlight">»</span>'
+                               },
+                               {
+                                       desc: 'Test 025: fr French text and « french quotes » (guillemets)',
+                                       text: '« L\'oiseau est sur l’île »',
+                                       highlight: '« L\'oise',
+                                       expected: '<span class="highlight">«</span> <span class="highlight">L\'oise</span>au est sur l’île »'
+                               },
+                               {
+                                       desc: 'Test 025a: fr French text and « french quotes » (guillemets) - does it match the single strings "«" and "L" separately?',
+                                       text: '« L\'oiseau est sur l’île »',
+                                       highlight: '« L',
+                                       expected: '<span class="highlight">«</span> <span class="highlight">L</span>\'oiseau est sur <span class="highlight">l</span>’île »'
+                               },
+                               {
+                                       desc: 'Test 026: ru Russian',
+                                       text: 'Праведники мира',
+                                       highlight: 'Праведники мира',
+                                       expected: '<span class="highlight">Праведники</span> <span class="highlight">мира</span>'
+                               },
+                               {
+                                       desc: 'Test 027: ru Russian',
+                                       text: 'Праведники мира',
+                                       highlight: 'Праве',
+                                       expected: '<span class="highlight">Праве</span>дники мира'
+                               },
+                               {
+                                       desc: 'Test 028 ka Georgian',
+                                       text: 'მთავარი გვერდი',
+                                       highlight: 'მთავარი გვერდი',
+                                       expected: '<span class="highlight">მთავარი</span> <span class="highlight">გვერდი</span>'
+                               },
+                               {
+                                       desc: 'Test 029 ka Georgian',
+                                       text: 'მთავარი გვერდი',
+                                       highlight: 'მთა',
+                                       expected: '<span class="highlight">მთა</span>ვარი გვერდი'
+                               },
+                               {
+                                       desc: 'Test 030 hy Armenian',
+                                       text: 'Նոնա Գափրինդաշվիլի',
+                                       highlight: 'Նոնա Գափրինդաշվիլի',
+                                       expected: '<span class="highlight">Նոնա</span> <span class="highlight">Գափրինդաշվիլի</span>'
+                               },
+                               {
+                                       desc: 'Test 031 hy Armenian',
+                                       text: 'Նոնա Գափրինդաշվիլի',
+                                       highlight: 'Նոն',
+                                       expected: '<span class="highlight">Նոն</span>ա Գափրինդաշվիլի'
+                               },
+                               {
+                                       desc: 'Test 032: th Thai',
+                                       text: 'พอล แอร์ดิช',
+                                       highlight: 'พอล แอร์ดิช',
+                                       expected: '<span class="highlight">พอล</span> <span class="highlight">แอร์ดิช</span>'
+                               },
+                               {
+                                       desc: 'Test 033: th Thai',
+                                       text: 'พอล แอร์ดิช',
+                                       highlight: 'พอ',
+                                       expected: '<span class="highlight">พอ</span>ล แอร์ดิช'
+                               },
+                               {
+                                       desc: 'Test 034: RTL ar Arabic',
+                                       text: 'بول إيردوس',
+                                       highlight: 'بول إيردوس',
+                                       expected: '<span class="highlight">بول</span> <span class="highlight">إيردوس</span>'
+                               },
+                               {
+                                       desc: 'Test 035: RTL ar Arabic',
+                                       text: 'بول إيردوس',
+                                       highlight: 'بو',
+                                       expected: '<span class="highlight">بو</span>ل إيردوس'
+                               }
+                       ];
 
                $.each( cases, function ( i, item ) {
                        $fixture = $( '<p>' ).text( item.text ).highlightText( item.highlight );
index 1b68809..a3e46ab 100644 (file)
@@ -51,6 +51,7 @@
        } );
 
        QUnit.test( 'Options', function ( assert ) {
+               var html, $lc, x, sitename = 'Wikipedia';
                mw.messages.set( {
                        'foo-lorem': 'Lorem',
                        'foo-ipsum': 'Ipsum',
@@ -60,7 +61,6 @@
                        'foo-bazz-label': 'The Bazz ($1)',
                        'foo-welcome': 'Welcome to $1! (last visit: $2)'
                } );
-               var html, $lc, x, sitename = 'Wikipedia';
 
                // Message key prefix
                html = '<div><span title-msg="lorem"><html:msg key="ipsum" /></span></div>';
index b80af4c..4e77d72 100644 (file)
@@ -12,8 +12,7 @@
 
        // This test is first because if it fails, then almost all of the latter tests are meaningless.
        QUnit.test( 'testing hooks/triggers', function ( assert ) {
-               var test = this,
-                       $collapsible = prepareCollapsible(
+               var $collapsible = prepareCollapsible(
                                '<div class="mw-collapsible">' + loremIpsum + '</div>'
                        ),
                        $content = $collapsible.find( '.mw-collapsible-content' ),
@@ -45,8 +44,7 @@
        } );
 
        QUnit.test( 'basic operation (<div>)', function ( assert ) {
-               var test = this,
-                       $collapsible = prepareCollapsible(
+               var $collapsible = prepareCollapsible(
                                '<div class="mw-collapsible">' + loremIpsum + '</div>'
                        ),
                        $content = $collapsible.find( '.mw-collapsible-content' ),
@@ -71,8 +69,7 @@
        } );
 
        QUnit.test( 'basic operation (<table>)', function ( assert ) {
-               var test = this,
-                       $collapsible = prepareCollapsible(
+               var $collapsible = prepareCollapsible(
                                '<table class="mw-collapsible">' +
                                        '<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
                                        '<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
        } );
 
        QUnit.test( 'cloned collapsibles can be made collapsible again', function ( assert ) {
-               var test = this,
-                       $collapsible = prepareCollapsible(
+               var $collapsible = prepareCollapsible(
                                '<div class="mw-collapsible">' + loremIpsum + '</div>'
                        ),
                        $clone = $collapsible.clone() // clone without data and events
index 73e4313..dd7666b 100644 (file)
@@ -1,4 +1,5 @@
 ( function ( $ ) {
+       var html, testElement;
 
        QUnit.module( 'jquery.placeholder', QUnit.newMwEnvironment() );
 
                return;
        }
 
-       var html = '<form>' +
-                       '<input id="input-type-search" type="search" placeholder="Search this site...">' +
-                       '<input id="input-type-text" type="text" placeholder="e.g. John Doe">' +
-                       '<input id="input-type-email" type="email" placeholder="e.g. address@example.ext">' +
-                       '<input id="input-type-url" type="url" placeholder="e.g. http://mathiasbynens.be/">' +
-                       '<input id="input-type-tel" type="tel" placeholder="e.g. +32 472 77 69 88">' +
-                       '<input id="input-type-password" type="password" placeholder="e.g. hunter2">' +
-                       '<textarea id="textarea" name="message" placeholder="Your message goes here"></textarea>' +
-               '</form>',
+       html = '<form>' +
+               '<input id="input-type-search" type="search" placeholder="Search this site...">' +
+               '<input id="input-type-text" type="text" placeholder="e.g. John Doe">' +
+               '<input id="input-type-email" type="email" placeholder="e.g. address@example.ext">' +
+               '<input id="input-type-url" type="url" placeholder="e.g. http://mathiasbynens.be/">' +
+               '<input id="input-type-tel" type="tel" placeholder="e.g. +32 472 77 69 88">' +
+               '<input id="input-type-password" type="password" placeholder="e.g. hunter2">' +
+               '<textarea id="textarea" name="message" placeholder="Your message goes here"></textarea>' +
+       '</form>';
        testElement = function ( $el, assert ) {
-
                var el = $el[ 0 ],
                        placeholder = el.getAttribute( 'placeholder' );
 
        } );
 
        QUnit.test( 'emulates placeholder for <input type=password>', function ( assert ) {
+               var $el, el, placeholder, selector = '#input-type-password';
+
                $( '<div>' ).html( html ).appendTo( $( '#qunit-fixture' ) );
 
-               var selector = '#input-type-password',
-                       $el = $( selector ),
-                       el = $el[ 0 ],
-                       placeholder = el.getAttribute( 'placeholder' );
+               $el = $( selector );
+               el = $el[ 0 ];
+               placeholder = el.getAttribute( 'placeholder' );
 
                assert.strictEqual( $el.placeholder(), $el, 'should be chainable' );
 
 
        } );
 
-       QUnit.test( 'emulates placeholder for <textarea></textarea>', function ( assert ) {
+       QUnit.test( 'emulates placeholder for <textarea>', function ( assert ) {
                $( '<div>' ).html( html ).appendTo( $( '#qunit-fixture' ) );
                testElement( $( '#textarea' ), assert );
        } );
index 97b2c0e..c0b1657 100644 (file)
                                                'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ]
                                },
                                names: [ 'January', 'February', 'March', 'April', 'May', 'June',
-                                               'July', 'August', 'September', 'October', 'November', 'December' ],
+                                       'July', 'August', 'September', 'October', 'November', 'December' ],
                                genitive: [ 'January', 'February', 'March', 'April', 'May', 'June',
-                                               'July', 'August', 'September', 'October', 'November', 'December' ],
+                                       'July', 'August', 'September', 'October', 'November', 'December' ],
                                abbrev: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
-                                               'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
+                                       'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
                        };
                },
                teardown: function () {
index 6f84945..5b973f6 100644 (file)
                                                'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ]
                                },
                                names: [ 'January', 'February', 'March', 'April', 'May', 'June',
-                                               'July', 'August', 'September', 'October', 'November', 'December' ],
+                                       'July', 'August', 'September', 'October', 'November', 'December' ],
                                genitive: [ 'January', 'February', 'March', 'April', 'May', 'June',
-                                               'July', 'August', 'September', 'October', 'November', 'December' ],
+                                       'July', 'August', 'September', 'October', 'November', 'December' ],
                                abbrev: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
-                                               'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
+                                       'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
                        };
                },
                teardown: function () {
                $tr.appendTo( $thead );
 
                for ( i = 0; i < data.length; i++ ) {
-                       /*jshint loopfunc: true */
                        $tr = $( '<tr>' );
+                       // eslint-disable-next-line no-loop-func
                        $.each( data[ i ], function ( j, str ) {
                                var $td = $( '<td>' );
                                $td.text( str ).appendTo( $tr );
                simple,
                simpleAsc,
                function ( $table ) {
+                       var event;
                        $table.tablesorter(
                                { sortList: [ { 0: 'desc' }, { 1: 'desc' } ] }
                        );
                        $table.find( '.headerSort:eq(0)' ).click();
 
                        // Pretend to click while pressing the multi-sort key
-                       var event = $.Event( 'click' );
+                       event = $.Event( 'click' );
                        event[ $table.data( 'tablesorter' ).config.sortMultiSortKey ] = true;
                        $table.find( '.headerSort:eq(1)' ).trigger( event );
                }
index 3ab8428..f958e09 100644 (file)
@@ -1,4 +1,28 @@
 ( function ( $ ) {
+       var caretSample,
+               sig = {
+                       pre: '--~~~~'
+               },
+               bold = {
+                       pre: '\'\'\'',
+                       peri: 'Bold text',
+                       post: '\'\'\''
+               },
+               h2 = {
+                       pre: '== ',
+                       peri: 'Heading 2',
+                       post: ' ==',
+                       regex: /^(\s*)(={1,6})(.*?)\2(\s*)$/,
+                       regexReplace: '$1==$3==$4',
+                       ownline: true
+               },
+               ulist = {
+                       pre: '* ',
+                       peri: 'Bulleted list item',
+                       post: '',
+                       ownline: true,
+                       splitlines: true
+               };
 
        QUnit.module( 'jquery.textSelection', QUnit.newMwEnvironment() );
 
                } );
        }
 
-       var caretSample,
-               sig = {
-                       pre: '--~~~~'
-               },
-               bold = {
-                       pre: '\'\'\'',
-                       peri: 'Bold text',
-                       post: '\'\'\''
-               },
-               h2 = {
-                       pre: '== ',
-                       peri: 'Heading 2',
-                       post: ' ==',
-                       regex: /^(\s*)(={1,6})(.*?)\2(\s*)$/,
-                       regexReplace: '$1==$3==$4',
-                       ownline: true
-               },
-               ulist = {
-                       pre: '* ',
-                       peri: 'Bulleted list item',
-                       post: '',
-                       ownline: true,
-                       splitlines: true
-               };
-
        encapsulateTest( {
                description: 'Adding sig to end of text',
                before: {
index f83f66c..13d7dcc 100644 (file)
@@ -15,7 +15,7 @@
                                                pages: [ {
                                                        pageid: 1,
                                                        ns: 0,
-                                                       title:  'Sandbox',
+                                                       title: 'Sandbox',
                                                        revisions: [ {
                                                                timestamp: '2016-01-01T12:00:00Z',
                                                                contentformat: 'text/x-wiki',
@@ -56,7 +56,7 @@
                                                pages: [ {
                                                        pageid: 4,
                                                        ns: 0,
-                                                       title:  'Async',
+                                                       title: 'Async',
                                                        revisions: [ {
                                                                timestamp: '2016-02-01T12:00:00Z',
                                                                contentformat: 'text/x-wiki',
@@ -97,7 +97,7 @@
                                                pages: [ {
                                                        pageid: 3,
                                                        ns: 0,
-                                                       title:  'Param',
+                                                       title: 'Param',
                                                        revisions: [ {
                                                                timestamp: '2016-03-01T12:00:00Z',
                                                                contentformat: 'text/x-wiki',
                        if ( /edit.+text=Sand/.test( req.requestBody ) ) {
                                req.respond( 200, { 'Content-Type': 'application/json' }, JSON.stringify( {
                                        edit: {
-                                               'new': true,
+                                               new: true,
                                                result: 'Success',
                                                newrevid: 41,
                                                newtimestamp: '2016-04-01T12:00:00Z'
index f3d29c9..854e4b1 100644 (file)
 
                // Requests are POST, match requestBody instead of url
                this.server.respond( function ( request ) {
-                       switch ( request.requestBody ) {
+                       if ( $.inArray( request.requestBody, [
                                // simple
-                               case 'action=options&format=json&formatversion=2&change=foo%3Dbar&token=%2B%5C':
+                               'action=options&format=json&formatversion=2&change=foo%3Dbar&token=%2B%5C',
                                // two options
-                               case 'action=options&format=json&formatversion=2&change=foo%3Dbar%7Cbaz%3Dquux&token=%2B%5C':
+                               'action=options&format=json&formatversion=2&change=foo%3Dbar%7Cbaz%3Dquux&token=%2B%5C',
                                // not bundleable
-                               case 'action=options&format=json&formatversion=2&optionname=foo&optionvalue=bar%7Cquux&token=%2B%5C':
-                               case 'action=options&format=json&formatversion=2&optionname=bar&optionvalue=a%7Cb%7Cc&token=%2B%5C':
-                               case 'action=options&format=json&formatversion=2&change=baz%3Dquux&token=%2B%5C':
+                               'action=options&format=json&formatversion=2&optionname=foo&optionvalue=bar%7Cquux&token=%2B%5C',
+                               'action=options&format=json&formatversion=2&optionname=bar&optionvalue=a%7Cb%7Cc&token=%2B%5C',
+                               'action=options&format=json&formatversion=2&change=baz%3Dquux&token=%2B%5C',
                                // reset an option
-                               case 'action=options&format=json&formatversion=2&change=foo&token=%2B%5C':
+                               'action=options&format=json&formatversion=2&change=foo&token=%2B%5C',
                                // reset an option, not bundleable
-                               case 'action=options&format=json&formatversion=2&optionname=foo%7Cbar%3Dquux&token=%2B%5C':
-                                       assert.ok( true, 'Repond to ' + request.requestBody );
-                                       request.respond( 200, { 'Content-Type': 'application/json' },
-                                               '{ "options": "success" }' );
-                                       break;
-                               default:
-                                       assert.ok( false, 'Unexpected request: ' + request.requestBody );
+                               'action=options&format=json&formatversion=2&optionname=foo%7Cbar%3Dquux&token=%2B%5C'
+                       ] ) !== -1 ) {
+                               assert.ok( true, 'Repond to ' + request.requestBody );
+                               request.respond( 200, { 'Content-Type': 'application/json' },
+                                       '{ "options": "success" }' );
+                       } else {
+                               assert.ok( false, 'Unexpected request: ' + request.requestBody );
                        }
                } );
 
 
                // Requests are POST, match requestBody instead of url
                this.server.respond( function ( request ) {
-                       switch ( request.requestBody ) {
+                       if ( $.inArray( request.requestBody, [
                                // simple
-                               case 'action=options&format=json&formatversion=2&change=foo%3Dbar&token=%2B%5C':
+                               'action=options&format=json&formatversion=2&change=foo%3Dbar&token=%2B%5C',
                                // two options
-                               case 'action=options&format=json&formatversion=2&change=foo%3Dbar%7Cbaz%3Dquux&token=%2B%5C':
+                               'action=options&format=json&formatversion=2&change=foo%3Dbar%7Cbaz%3Dquux&token=%2B%5C',
                                // bundleable with unit separator
-                               case 'action=options&format=json&formatversion=2&change=%1Ffoo%3Dbar%7Cquux%1Fbar%3Da%7Cb%7Cc%1Fbaz%3Dquux&token=%2B%5C':
+                               'action=options&format=json&formatversion=2&change=%1Ffoo%3Dbar%7Cquux%1Fbar%3Da%7Cb%7Cc%1Fbaz%3Dquux&token=%2B%5C',
                                // not bundleable with unit separator
-                               case 'action=options&format=json&formatversion=2&optionname=baz%3Dbaz&optionvalue=quux&token=%2B%5C':
-                               case 'action=options&format=json&formatversion=2&change=%1Ffoo%3Dbar%7Cquux%1Fbar%3Da%7Cb%7Cc&token=%2B%5C':
+                               'action=options&format=json&formatversion=2&optionname=baz%3Dbaz&optionvalue=quux&token=%2B%5C',
+                               'action=options&format=json&formatversion=2&change=%1Ffoo%3Dbar%7Cquux%1Fbar%3Da%7Cb%7Cc&token=%2B%5C',
                                // reset an option
-                               case 'action=options&format=json&formatversion=2&change=foo&token=%2B%5C':
+                               'action=options&format=json&formatversion=2&change=foo&token=%2B%5C',
                                // reset an option, not bundleable
-                               case 'action=options&format=json&formatversion=2&optionname=foo%7Cbar%3Dquux&token=%2B%5C':
-                                       assert.ok( true, 'Repond to ' + request.requestBody );
-                                       request.respond( 200, { 'Content-Type': 'application/json' },
+                               'action=options&format=json&formatversion=2&optionname=foo%7Cbar%3Dquux&token=%2B%5C'
+                       ] ) !== -1 ) {
+                               assert.ok( true, 'Repond to ' + request.requestBody );
+                               request.respond( 200, { 'Content-Type': 'application/json' },
                                                '{ "options": "success" }' );
-                                       break;
-                               default:
-                                       assert.ok( false, 'Unexpected request: ' + request.requestBody );
+                       } else {
+                               assert.ok( false, 'Unexpected request: ' + request.requestBody );
                        }
                } );
 
index 7d27352..74da009 100644 (file)
@@ -39,7 +39,7 @@
                ] );
 
                return new mw.Api().parse( new mw.Title( 'Earth' ) ).done( function ( html ) {
-                       assert.equal( html, '<p><b>Earth</b> is a planet.</p>', 'Parse page by Title object'  );
+                       assert.equal( html, '<p><b>Earth</b> is a planet.</p>', 'Parse page by Title object' );
                } );
        } );
 }( mediaWiki ) );
index 6629f5c..e10a7fa 100644 (file)
 
                return api.postWithToken( 'testassertpost', { action: 'example', key: 'foo', assert: 'user' } )
                        // Cast error to success and vice versa
-                       .then( function ( ) {
+                       .then( function () {
                                return $.Deferred().reject( 'Unexpected success' );
                        }, function ( errorCode ) {
                                assert.equal( errorCode, 'assertuserfailed', 'getToken fails assert' );
                this.server.respond( [ 200, { 'Content-Type': 'application/json' }, '{ "example": "quux" }' ] );
 
                return api.postWithToken( 'csrf',
-                               { action: 'example' },
-                               {
-                                       headers: {
-                                               'X-Foo': 'Bar'
-                                       }
+                       { action: 'example' },
+                       {
+                               headers: {
+                                       'X-Foo': 'Bar'
                                }
-                       )
-                       .then( function () {
-                               assert.equal( test.server.requests[ 0 ].requestHeaders[ 'X-Foo' ], 'Bar', 'Header sent' );
+                       }
+               )
+               .then( function () {
+                       assert.equal( test.server.requests[ 0 ].requestHeaders[ 'X-Foo' ], 'Bar', 'Header sent' );
 
-                               return api.postWithToken( 'csrf',
-                                       { action: 'example' },
-                                       function () {
-                                               assert.ok( false, 'This parameter cannot be a callback' );
-                                       }
-                               );
-                       } )
-                       .then( function ( data ) {
-                               assert.equal( data.example, 'quux' );
+                       return api.postWithToken( 'csrf',
+                               { action: 'example' },
+                               function () {
+                                       assert.ok( false, 'This parameter cannot be a callback' );
+                               }
+                       );
+               } )
+               .then( function ( data ) {
+                       assert.equal( data.example, 'quux' );
 
-                               assert.equal( test.server.requests.length, 2, 'Request made' );
-                       } );
+                       assert.equal( test.server.requests.length, 2, 'Request made' );
+               } );
        } );
 
        QUnit.test( 'postWithToken() - badtoken', function ( assert ) {
index 49a5b18..a5b12c9 100644 (file)
                                hidefilter4: 0,
                                hidefilter5: 0,
                                hidefilter6: 0,
-                               group3: 'all',
+                               group3: 'all'
                        },
                        'Unselected filters return all parameters falsey or \'all\'.'
                );
                                        filters: [
                                                { name: 'filter1' },
                                                { name: 'filter2' },
-                                               { name: 'filter3' },
+                                               { name: 'filter3' }
                                        ]
                                },
                                group2: {
                                        filters: [
                                                { name: 'filter4' },
                                                { name: 'filter5' },
-                                               { name: 'filter6' },
+                                               { name: 'filter6' }
                                        ]
                                }
                        },
+                       model = new mw.rcfilters.dm.FiltersViewModel(),
                        isCapsuleItemMuted = function ( filterName ) {
                                var itemModel = model.getItemByName( filterName ),
                                        groupModel = itemModel.getGroupModel();
                                filter4: false,
                                filter5: false,
                                filter6: false
-                       },
-                       model = new mw.rcfilters.dm.FiltersViewModel();
+                       };
 
                model.initializeFilters( definition );
 
                                                        conflicts: [ 'filter3' ]
                                                },
                                                {
-                                                       name: 'filter6',
+                                                       name: 'filter6'
                                                }
                                        ]
                                }
                        $.extend( true, {}, baseFullState, {
                                filter1: { selected: true },
                                filter2: { conflicted: true },
-                               filter4: { conflicted: true },
+                               filter4: { conflicted: true }
                        } ),
                        'Selecting a filter set its conflicts list as "conflicted".'
                );
                        $.extend( true, {}, baseFullState, {
                                filter1: { selected: true, conflicted: true },
                                filter2: { conflicted: true },
-                               filter4: { selected: true, conflicted: true },
+                               filter4: { selected: true, conflicted: true }
                        } ),
                        'Selecting a conflicting filter sets both sides to conflicted and selected.'
                );
index ca15185..1bc4c06 100644 (file)
@@ -1,79 +1,80 @@
 ( function ( mw, $ ) {
+       /* eslint-disable camelcase */
        var repeat = function ( input, multiplier ) {
-               return new Array( multiplier + 1 ).join( input );
-       },
-       cases = {
+                       return new Array( multiplier + 1 ).join( input );
+               },
                // See also TitleTest.php#testSecureAndSplit
-               valid: [
-                       'Sandbox',
-                       'A "B"',
-                       'A \'B\'',
-                       '.com',
-                       '~',
-                       '"',
-                       '\'',
-                       'Talk:Sandbox',
-                       'Talk:Foo:Sandbox',
-                       'File:Example.svg',
-                       'File_talk:Example.svg',
-                       'Foo/.../Sandbox',
-                       'Sandbox/...',
-                       'A~~',
-                       ':A',
-                       // Length is 256 total, but only title part matters
-                       'Category:' + repeat( 'x', 248 ),
-                       repeat( 'x', 252 )
-               ],
-               invalid: [
-                       '',
-                       ':',
-                       '__  __',
-                       '  __  ',
-                       // Bad characters forbidden regardless of wgLegalTitleChars
-                       'A [ B',
-                       'A ] B',
-                       'A { B',
-                       'A } B',
-                       'A < B',
-                       'A > B',
-                       'A | B',
-                       'A \t B',
-                       'A \n B',
-                       // URL encoding
-                       'A%20B',
-                       'A%23B',
-                       'A%2523B',
-                       // XML/HTML character entity references
-                       // Note: The ones with # are commented out as those are interpreted as fragment and
-                       // as such end up being valid.
-                       'A &eacute; B',
-                       // 'A &#233; B',
-                       // 'A &#x00E9; B',
-                       // Subject of NS_TALK does not roundtrip to NS_MAIN
-                       'Talk:File:Example.svg',
-                       // Directory navigation
-                       '.',
-                       '..',
-                       './Sandbox',
-                       '../Sandbox',
-                       'Foo/./Sandbox',
-                       'Foo/../Sandbox',
-                       'Sandbox/.',
-                       'Sandbox/..',
-                       // Tilde
-                       'A ~~~ Name',
-                       'A ~~~~ Signature',
-                       'A ~~~~~ Timestamp',
-                       repeat( 'x', 256 ),
-                       // Extension separation is a js invention, for length
-                       // purposes it is part of the title
-                       repeat( 'x', 252 ) + '.json',
-                       // Namespace prefix without actual title
-                       'Talk:',
-                       'Category: ',
-                       'Category: #bar'
-               ]
-       };
+               cases = {
+                       valid: [
+                               'Sandbox',
+                               'A "B"',
+                               'A \'B\'',
+                               '.com',
+                               '~',
+                               '"',
+                               '\'',
+                               'Talk:Sandbox',
+                               'Talk:Foo:Sandbox',
+                               'File:Example.svg',
+                               'File_talk:Example.svg',
+                               'Foo/.../Sandbox',
+                               'Sandbox/...',
+                               'A~~',
+                               ':A',
+                               // Length is 256 total, but only title part matters
+                               'Category:' + repeat( 'x', 248 ),
+                               repeat( 'x', 252 )
+                       ],
+                       invalid: [
+                               '',
+                               ':',
+                               '__  __',
+                               '  __  ',
+                               // Bad characters forbidden regardless of wgLegalTitleChars
+                               'A [ B',
+                               'A ] B',
+                               'A { B',
+                               'A } B',
+                               'A < B',
+                               'A > B',
+                               'A | B',
+                               'A \t B',
+                               'A \n B',
+                               // URL encoding
+                               'A%20B',
+                               'A%23B',
+                               'A%2523B',
+                               // XML/HTML character entity references
+                               // Note: The ones with # are commented out as those are interpreted as fragment and
+                               // as such end up being valid.
+                               'A &eacute; B',
+                               // 'A &#233; B',
+                               // 'A &#x00E9; B',
+                               // Subject of NS_TALK does not roundtrip to NS_MAIN
+                               'Talk:File:Example.svg',
+                               // Directory navigation
+                               '.',
+                               '..',
+                               './Sandbox',
+                               '../Sandbox',
+                               'Foo/./Sandbox',
+                               'Foo/../Sandbox',
+                               'Sandbox/.',
+                               'Sandbox/..',
+                               // Tilde
+                               'A ~~~ Name',
+                               'A ~~~~ Signature',
+                               'A ~~~~~ Timestamp',
+                               repeat( 'x', 256 ),
+                               // Extension separation is a js invention, for length
+                               // purposes it is part of the title
+                               repeat( 'x', 252 ) + '.json',
+                               // Namespace prefix without actual title
+                               'Talk:',
+                               'Category: ',
+                               'Category: #bar'
+                       ]
+               };
 
        QUnit.module( 'mediawiki.Title', QUnit.newMwEnvironment( {
                // mw.Title relies on these three config vars
                                // testing custom / localized namespace
                                100: 'Penguins'
                        },
-                       // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
                        wgNamespaceIds: {
                                media: -2,
                                special: -1,
                                penguins: 100,
                                antarctic_waterfowl: 100
                        },
-                       // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
                        wgCaseSensitiveNamespaces: []
                }
        } ) );
                        title = new mw.Title( cases.valid[ i ] );
                }
                for ( i = 0; i < cases.invalid.length; i++ ) {
-                       /*jshint loopfunc:true */
                        title = cases.invalid[ i ];
+                       // eslint-disable-next-line no-loop-func
                        assert.throws( function () {
                                return new mw.Title( title );
                        }, cases.invalid[ i ] );
index e20fc4c..e56c933 100644 (file)
                } );
                assert.equal( uri.toString(), 'http://example.com/bar/baz', 'normalize URI without protocol or // in loose mode' );
 
-               /*jshint -W001 */
                uri = new mw.Uri( 'http://example.com/index.php?key=key&hasOwnProperty=hasOwnProperty&constructor=constructor&watch=watch' );
                assert.deepEqual(
                        uri.query,
                        },
                        'Keys in query strings support names of Object prototypes (bug T114344)'
                );
-               /*jshint +W001 */
        } );
 
        QUnit.test( 'Constructor( Object )', function ( assert ) {
index 02212cb..4170897 100644 (file)
@@ -1,6 +1,4 @@
 ( function ( mw, $ ) {
-       QUnit.module( 'mediawiki.cldr', QUnit.newMwEnvironment() );
-
        var pluralTestcases = {
                /*
                 * Sample:
                ]
        };
 
+       QUnit.module( 'mediawiki.cldr', QUnit.newMwEnvironment() );
+
        function pluralTest( langCode, tests ) {
                QUnit.test( 'Plural Test for ' + langCode, function ( assert ) {
-                       for ( var i = 0; i < tests.length; i++ ) {
+                       var i;
+                       for ( i = 0; i < tests.length; i++ ) {
                                assert.equal(
                                        mw.language.convertPlural( tests[ i ][ 0 ], tests[ i ][ 1 ] ),
                                        tests[ i ][ 2 ],
index bc0ef40..46d7837 100644 (file)
@@ -24,7 +24,7 @@
                w.onerror( errorMessage, errorUrl, errorLine, errorColumn, errorObject );
                sinon.assert.calledWithExactly( mw.track, 'global.error',
                        sinon.match( { errorMessage: errorMessage, url: errorUrl, lineNumber: errorLine,
-                       columnNumber: errorColumn, errorObject: errorObject } ) );
+                               columnNumber: errorColumn, errorObject: errorObject } ) );
 
                w = { onerror: oldHandler };
 
index eff990c..3b549bd 100644 (file)
@@ -1,4 +1,5 @@
 ( function ( mw, $ ) {
+       /* eslint-disable camelcase */
        var formatText, formatParse, formatnumTests, specialCharactersPageName, expectedListUsers,
                expectedListUsersSitename, expectedLinkPagenamee, expectedEntrypoints,
                mwLanguageCache = {},
@@ -45,7 +46,6 @@
                },
                config: {
                        wgArticlePath: '/wiki/$1',
-                       // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
                        wgNamespaceIds: {
                                template: 10,
                                template_talk: 11,
@@ -53,7 +53,6 @@
                                szablon: 10,
                                dyskusja_szablonu: 11
                        },
-                       // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
                        wgFormattedNamespaces: {
                                // Localised
                                10: 'Szablon',
         *  that may be asynchronous. Invoke the callback parameter when done.
         */
        function process( tasks ) {
-               /*jshint latedef:false */
                function abort() {
                        tasks.splice( 0, tasks.length );
+                       // eslint-disable-next-line no-use-before-define
                        next();
                }
                function next() {
+                       var task;
                        if ( !tasks ) {
                                // This happens if after the process is completed, one of our callbacks is
                                // invoked. This can happen if a test timed out but the process was still
                                // running. In that case, ignore it. Don't invoke complete() a second time.
                                return;
                        }
-                       var task = tasks.shift();
+                       task = tasks.shift();
                        if ( task ) {
                                task( next, abort );
                        } else {
        } );
 
        QUnit.test( 'Match PHP parser', function ( assert ) {
+               var tasks;
                mw.messages.set( mw.libs.phpParserData.messages );
-               var tasks = $.map( mw.libs.phpParserData.tests, function ( test ) {
+               tasks = $.map( mw.libs.phpParserData.tests, function ( test ) {
                        var done = assert.async();
                        return function ( next, abort ) {
                                getMwLanguage( test.lang )
                                        .then( function ( langClass ) {
+                                               var parser;
                                                mw.config.set( 'wgUserLanguage', test.lang );
-                                               var parser = new mw.jqueryMsg.parser( { language: langClass } );
+                                               // eslint-disable-next-line new-cap
+                                               parser = new mw.jqueryMsg.parser( { language: langClass } );
                                                assert.equal(
                                                        parser.parse( test.key, test.args ).html(),
                                                        test.result,
        ];
 
        QUnit.test( 'formatnum', function ( assert ) {
+               var queue;
                mw.messages.set( 'formatnum-msg', '{{formatnum:$1}}' );
                mw.messages.set( 'formatnum-msg-int', '{{formatnum:$1|R}}' );
-               var queue = $.map( formatnumTests, function ( test ) {
+               queue = $.map( formatnumTests, function ( test ) {
                        var done = assert.async();
                        return function ( next, abort ) {
                                getMwLanguage( test.lang )
                                        .then( function ( langClass ) {
+                                               var parser;
                                                mw.config.set( 'wgUserLanguage', test.lang );
-                                               var parser = new mw.jqueryMsg.parser( { language: langClass } );
+                                               // eslint-disable-next-line new-cap
+                                               parser = new mw.jqueryMsg.parser( { language: langClass } );
                                                assert.equal(
                                                        parser.parse( test.integer ? 'formatnum-msg-int' : 'formatnum-msg',
                                                                [ test.number ] ).html(),
        } );
 
        QUnit.test( 'Behavior in case of invalid wikitext', function ( assert ) {
+               var logSpy;
                mw.messages.set( 'invalid-wikitext', '<b>{{FAIL}}</b>' );
 
                this.suppressWarnings();
-               var logSpy = this.sandbox.spy( mw.log, 'warn' );
+               logSpy = this.sandbox.spy( mw.log, 'warn' );
 
                assert.equal(
                        formatParse( 'invalid-wikitext' ),
index d185d3c..b965079 100644 (file)
@@ -1,6 +1,8 @@
 ( function ( mw, $ ) {
        'use strict';
 
+       var grammarTests;
+
        QUnit.module( 'mediawiki.language', QUnit.newMwEnvironment( {
                setup: function () {
                        this.liveLangData = mw.language.data;
@@ -82,8 +84,8 @@
                // The test works only if the content language is opt.language
                // because it requires [lang].js to be loaded.
                QUnit.test( 'Grammar test for lang=' + langCode, function ( assert ) {
-
-                       for ( var i = 0; i < test.length; i++ ) {
+                       var i;
+                       for ( i = 0; i < test.length; i++ ) {
                                assert.equal(
                                        mw.language.convertGrammar( test[ i ].word, test[ i ].grammarForm ),
                                        test[ i ].expected,
@@ -94,7 +96,7 @@
        }
 
        // These tests run only for the current UI language.
-       var grammarTests = {
+       grammarTests = {
                bs: [
                        {
                                word: 'word',
index fb3bedb..6f9af76 100644 (file)
 
                function isCssImportApplied() {
                        // Trigger reflow, repaint, redraw, whatever (cross-browser)
-                       var x = $element.css( 'height' );
-                       x = el.innerHTML;
+                       $element.css( 'height' );
+                       el.innerHTML;
                        el.className = el.className;
-                       x = document.documentElement.clientHeight;
+                       document.documentElement.clientHeight;
 
                        return $element.css( prop ) === val;
                }
index ac5b3f8..01665e5 100644 (file)
@@ -29,7 +29,7 @@
                        [ false, ':::' ],
                        [ false, '::0:', 'IPv6 ending in a lone ":"' ],
 
-                       [ true,  '::', 'IPv6 zero address' ],
+                       [ true, '::', 'IPv6 zero address' ],
 
                        [ false, '::fc:100:a:d:1:e:ac:0', 'IPv6 with "::" and 8 words' ],
                        [ false, '::fc:100:a:d:1:e:ac:0:1', 'IPv6 with 9 words' ],
                        [ false, 'fc::100:', 'IPv6 ending with lone ":"' ],
                        [ false, 'fc:::100', 'IPv6 with ":::" in the middle' ],
 
-                       [ true,  'fc::100', 'IPv6 with "::" and 2 words' ],
-                       [ true,  'fc::100:a', 'IPv6 with "::" and 3 words' ],
-                       [ true,  'fc::100:a:d', 'IPv6 with "::" and 4 words' ],
-                       [ true,  'fc::100:a:d:1', 'IPv6 with "::" and 5 words' ],
-                       [ true,  'fc::100:a:d:1:e', 'IPv6 with "::" and 6 words' ],
-                       [ true,  'fc::100:a:d:1:e:ac', 'IPv6 with "::" and 7 words' ],
-                       [ true,  '2001::df', 'IPv6 with "::" and 2 words' ],
-                       [ true,  '2001:5c0:1400:a::df', 'IPv6 with "::" and 5 words' ],
-                       [ true,  '2001:5c0:1400:a::df:2', 'IPv6 with "::" and 6 words' ],
+                       [ true, 'fc::100', 'IPv6 with "::" and 2 words' ],
+                       [ true, 'fc::100:a', 'IPv6 with "::" and 3 words' ],
+                       [ true, 'fc::100:a:d', 'IPv6 with "::" and 4 words' ],
+                       [ true, 'fc::100:a:d:1', 'IPv6 with "::" and 5 words' ],
+                       [ true, 'fc::100:a:d:1:e', 'IPv6 with "::" and 6 words' ],
+                       [ true, 'fc::100:a:d:1:e:ac', 'IPv6 with "::" and 7 words' ],
+                       [ true, '2001::df', 'IPv6 with "::" and 2 words' ],
+                       [ true, '2001:5c0:1400:a::df', 'IPv6 with "::" and 5 words' ],
+                       [ true, '2001:5c0:1400:a::df:2', 'IPv6 with "::" and 6 words' ],
 
                        [ false, 'fc::100:a:d:1:e:ac:0', 'IPv6 with "::" and 8 words' ],
                        [ false, 'fc::100:a:d:1:e:ac:0:1', 'IPv6 with 9 words' ]
index 7466bed..02ca243 100644 (file)
@@ -1,4 +1,4 @@
-/*global isCompatible: true */
+/* global isCompatible: true */
 ( function ( $ ) {
        var testcases = {
                tested: [
 
        QUnit.test( 'isCompatible( featureTestable )', function ( assert ) {
                $.each( testcases.tested, function ( i, ua ) {
-                               assert.strictEqual( isCompatible( ua ), true, ua );
-                       }
-               );
+                       assert.strictEqual( isCompatible( ua ), true, ua );
+               } );
        } );
 
        QUnit.test( 'isCompatible( blacklisted )', function ( assert ) {
                $.each( testcases.blacklisted, function ( i, ua ) {
-                               assert.strictEqual( isCompatible( ua ), false, ua );
-                       }
-               );
+                       assert.strictEqual( isCompatible( ua ), false, ua );
+               } );
        } );
 }( jQuery ) );