Merge "Hide edit toolbar Signature button in non-discussion namespaces"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 4 Aug 2015 20:05:32 +0000 (20:05 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 4 Aug 2015 20:05:32 +0000 (20:05 +0000)
59 files changed:
RELEASE-NOTES-1.26
autoload.php
docs/extension.schema.json
includes/GlobalFunctions.php
includes/Linker.php
includes/OutputPage.php
includes/Sanitizer.php
includes/User.php
includes/api/i18n/uk.json
includes/api/i18n/zh-hans.json
includes/dao/DBAccessObjectUtils.php [new file with mode: 0644]
includes/jobqueue/jobs/EnqueueJob.php
includes/libs/BufferingStatsdDataFactory.php
includes/libs/SamplingStatsdClient.php [new file with mode: 0644]
includes/page/WikiPage.php
includes/resourceloader/ResourceLoaderStartUpModule.php
includes/skins/Skin.php
includes/specials/SpecialConfirmemail.php
includes/specials/SpecialJavaScriptTest.php
includes/specials/SpecialWhatlinkshere.php
languages/i18n/azb.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/cu.json
languages/i18n/cv.json
languages/i18n/de.json
languages/i18n/es.json
languages/i18n/fa.json
languages/i18n/he.json
languages/i18n/hu.json
languages/i18n/ia.json
languages/i18n/ksh.json
languages/i18n/ku-latn.json
languages/i18n/lb.json
languages/i18n/lt.json
languages/i18n/nan.json
languages/i18n/nl.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/roa-tara.json
languages/i18n/sl.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/uk.json
languages/i18n/zh-hans.json
resources/Resources.php
resources/src/mediawiki.legacy/ajax.js [deleted file]
resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js
resources/src/mediawiki.page/mediawiki.page.startup.js
resources/src/mediawiki.page/mediawiki.page.watch.ajax.js
resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.js
resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.less
resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.js
resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.less
resources/src/mediawiki/mediawiki.js
resources/src/startup.js
tests/parser/parserTests.txt
tests/phpunit/includes/OutputPageTest.php
tests/phpunit/includes/libs/SamplingStatsdClientTest.php [new file with mode: 0644]

index bbd63b5..b470272 100644 (file)
@@ -141,6 +141,8 @@ changes to languages because of Phabricator reports.
 * SpecialPageFactory::setGroup was removed (deprecated in 1.21).
 * SpecialPageFactory::getGroup was removed (deprecated in 1.21).
 * DatabaseBase::ignoreErrors() is now protected.
+* BREAKING CHANGE: mediawiki.legacy.ajax has been removed, following
+  a lengthy deprecation period.
 
 == Compatibility ==
 
index 0d2e4a8..a6c7488 100644 (file)
@@ -279,6 +279,7 @@ $wgAutoloadLocalClasses = array(
        'CurlHttpRequest' => __DIR__ . '/includes/HttpFunctions.php',
        'DBAccessBase' => __DIR__ . '/includes/dao/DBAccessBase.php',
        'DBAccessError' => __DIR__ . '/includes/db/LBFactory.php',
+       'DBAccessObjectUtils' => __DIR__ . '/includes/dao/DBAccessObjectUtils.php',
        'DBConnRef' => __DIR__ . '/includes/db/DBConnRef.php',
        'DBConnectionError' => __DIR__ . '/includes/db/DatabaseError.php',
        'DBError' => __DIR__ . '/includes/db/DatabaseError.php',
@@ -1058,6 +1059,7 @@ $wgAutoloadLocalClasses = array(
        'SQLiteField' => __DIR__ . '/includes/db/DatabaseSqlite.php',
        'SVGMetadataExtractor' => __DIR__ . '/includes/media/SVGMetadataExtractor.php',
        'SVGReader' => __DIR__ . '/includes/media/SVGMetadataExtractor.php',
+       'SamplingStatsdClient' => __DIR__ . '/includes/libs/SamplingStatsdClient.php',
        'Sanitizer' => __DIR__ . '/includes/Sanitizer.php',
        'SavepointPostgres' => __DIR__ . '/includes/db/DatabasePostgres.php',
        'ScopedCallback' => __DIR__ . '/includes/libs/ScopedCallback.php',
index c9f8e42..1d78ecc 100644 (file)
                                                                "bottom",
                                                                "top"
                                                        ]
+                                               },
+                                               "templates": {
+                                                       "type": "object",
+                                                       "description": "Templates to be loaded for client-side usage"
                                                }
                                        }
                                }
index 167305d..b7b733d 100644 (file)
@@ -1259,7 +1259,7 @@ function wfLogProfilingData() {
                        $statsdHost = $statsdServer[0];
                        $statsdPort = isset( $statsdServer[1] ) ? $statsdServer[1] : 8125;
                        $statsdSender = new SocketSender( $statsdHost, $statsdPort );
-                       $statsdClient = new StatsdClient( $statsdSender, true, false );
+                       $statsdClient = new SamplingStatsdClient( $statsdSender, true, false );
                        $statsdClient->send( $context->getStats()->getBuffer() );
                } catch ( Exception $ex ) {
                        MWExceptionHandler::logException( $ex );
index bb65cdf..d6a4056 100644 (file)
@@ -1704,8 +1704,7 @@ class Linker {
        }
 
        /**
-        * Generate a table of contents from a section tree
-        * Currently unused.
+        * Generate a table of contents from a section tree.
         *
         * @param array $tree Return value of ParserOutput::getSections()
         * @param string|Language|bool $lang Language for the toc title, defaults to user language
index 07c1a8a..0f0b2f5 100644 (file)
@@ -2703,7 +2703,6 @@ class OutputPage extends ContextSource {
                }
 
                $ret .= $this->buildCssLinks() . "\n";
-
                $ret .= $this->getHeadScripts() . "\n";
 
                foreach ( $this->mHeadItems as $item ) {
@@ -2762,18 +2761,16 @@ class OutputPage extends ContextSource {
        }
 
        /**
-        * @todo Document
+        * Construct neccecary html and loader preset states to load modules on a page.
+        *
+        * Use getHtmlFromLoaderLinks() to convert this array to HTML.
+        *
         * @param array|string $modules One or more module names
         * @param string $only ResourceLoaderModule TYPE_ class constant
-        * @param array $extraQuery Array with extra query parameters to add to each
-        *   request. array( param => value ).
-        * @param bool $loadCall If true, output an (asynchronous) mw.loader.load()
-        *   call rather than a "<script src='...'>" tag.
-        * @return string The html "<script>", "<link>" and "<style>" tags
-        */
-       public function makeResourceLoaderLink( $modules, $only, array $extraQuery = array(),
-               $loadCall = false
-       ) {
+        * @param array $extraQuery [optional] Array with extra query parameters for the request
+        * @return array A list of HTML strings and array of client loader preset states
+        */
+       public function makeResourceLoaderLink( $modules, $only, array $extraQuery = array() ) {
                $modules = (array)$modules;
 
                $links = array(
@@ -2796,7 +2793,7 @@ class OutputPage extends ContextSource {
                        if ( ResourceLoader::inDebugMode() ) {
                                // Recursively call us for every item
                                foreach ( $modules as $name ) {
-                                       $link = $this->makeResourceLoaderLink( $name, $only );
+                                       $link = $this->makeResourceLoaderLink( $name, $only, $extraQuery );
                                        $links['html'] = array_merge( $links['html'], $link['html'] );
                                        $links['states'] += $link['states'];
                                }
@@ -2908,30 +2905,19 @@ class OutputPage extends ContextSource {
                                // Automatically select style/script elements
                                if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
                                        $link = Html::linkedStyle( $url );
-                               } elseif ( $loadCall ) {
-                                       $link = ResourceLoader::makeInlineScript(
-                                               Xml::encodeJsCall( 'mw.loader.load', array( $url, 'text/javascript', true ) )
-                                       );
                                } else {
-                                       $link = Html::linkedScript( $url );
-                                       if ( !$context->getRaw() && !$isRaw ) {
-                                               // Wrap only=script / only=combined requests in a conditional as
-                                               // browsers not supported by the startup module would unconditionally
-                                               // execute this module. Otherwise users will get "ReferenceError: mw is
-                                               // undefined" or "jQuery is undefined" from e.g. a "site" module.
+                                       if ( $context->getRaw() || $isRaw ) {
+                                               // Startup module can't load itself, needs to use <script> instead of mw.loader.load
+                                               $link = Html::element( 'script', array(
+                                                       // In SpecialJavaScriptTest, QUnit must load synchronous
+                                                       'async' => !isset( $extraQuery['sync'] ),
+                                                       'src' => $url
+                                               ) );
+                                       } else {
                                                $link = ResourceLoader::makeInlineScript(
-                                                       Xml::encodeJsCall( 'document.write', array( $link ) )
+                                                       Xml::encodeJsCall( 'mw.loader.load', array( $url ) )
                                                );
                                        }
-
-                                       // For modules requested directly in the html via <link> or <script>,
-                                       // tell mw.loader they are being loading to prevent duplicate requests.
-                                       foreach ( $grpModules as $key => $module ) {
-                                               // Don't output state=loading for the startup module..
-                                               if ( $key !== 'startup' ) {
-                                                       $links['states'][$key] = 'loading';
-                                               }
-                                       }
                                }
 
                                if ( $group == 'noscript' ) {
@@ -2980,8 +2966,20 @@ class OutputPage extends ContextSource {
         * @return string HTML fragment
         */
        function getHeadScripts() {
-               // Startup - this will immediately load jquery and mediawiki modules
                $links = array();
+
+               // Client profile classes for <html>. Allows for easy hiding/showing of UI components.
+               // Must be done synchronously on every page to avoid flashes of wrong content.
+               // Note: This class distinguishes MediaWiki-supported JavaScript from the rest.
+               // The "rest" includes browsers that support JavaScript but not supported by our runtime.
+               // For the performance benefit of the majority, this is added unconditionally here and is
+               // then fixed up by the startup module for unsupported browsers.
+               $links[] = Html::inlineScript(
+                       'document.documentElement.className = document.documentElement.className'
+                       . '.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );'
+               );
+
+               // Startup - this provides the client with the module manifest and loads jquery and mediawiki base modules
                $links[] = $this->makeResourceLoaderLink( 'startup', ResourceLoaderModule::TYPE_SCRIPTS );
 
                // Load config before anything else
@@ -3013,7 +3011,7 @@ class OutputPage extends ContextSource {
                );
 
                if ( $this->getConfig()->get( 'ResourceLoaderExperimentalAsyncLoading' ) ) {
-                       $links[] = $this->getScriptsForBottomQueue( true );
+                       $links[] = $this->getScriptsForBottomQueue();
                }
 
                return self::getHtmlFromLoaderLinks( $links );
@@ -3026,23 +3024,21 @@ class OutputPage extends ContextSource {
         * 'bottom', legacy scripts ($this->mScripts), user preferences, site JS
         * and user JS.
         *
-        * @param bool $inHead If true, this HTML goes into the "<head>",
-        *   if false it goes into the "<body>".
+        * @param bool $unused Previously used to let this method change its output based
+        *  on whether it was called by getHeadScripts() or getBottomScripts().
         * @return string
         */
-       function getScriptsForBottomQueue( $inHead ) {
+       function getScriptsForBottomQueue( $unused = null ) {
                // Scripts "only" requests marked for bottom inclusion
                // If we're in the <head>, use load() calls rather than <script src="..."> tags
                $links = array();
 
                $links[] = $this->makeResourceLoaderLink( $this->getModuleScripts( true, 'bottom' ),
-                       ResourceLoaderModule::TYPE_SCRIPTS, /* $extraQuery = */ array(),
-                       /* $loadCall = */ $inHead
+                       ResourceLoaderModule::TYPE_SCRIPTS
                );
 
                $links[] = $this->makeResourceLoaderLink( $this->getModuleStyles( true, 'bottom' ),
-                       ResourceLoaderModule::TYPE_STYLES, /* $extraQuery = */ array(),
-                       /* $loadCall = */ $inHead
+                       ResourceLoaderModule::TYPE_STYLES
                );
 
                // Modules requests - let the client calculate dependencies and batch requests as it likes
@@ -3050,7 +3046,7 @@ class OutputPage extends ContextSource {
                $modules = $this->getModules( true, 'bottom' );
                if ( $modules ) {
                        $links[] = ResourceLoader::makeInlineScript(
-                               Xml::encodeJsCall( 'mw.loader.load', array( $modules, null, true ) )
+                               Xml::encodeJsCall( 'mw.loader.load', array( $modules ) )
                        );
                }
 
@@ -3069,7 +3065,7 @@ class OutputPage extends ContextSource {
                        // We're on a preview of a JS subpage. Exclude this page from the user module (T28283)
                        // and include the draft contents as a raw script instead.
                        $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED,
-                               array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() ), $inHead
+                               array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() )
                        );
                        // Load the previewed JS
                        $links[] = ResourceLoader::makeInlineScript(
@@ -3093,15 +3089,11 @@ class OutputPage extends ContextSource {
                        // the excluded subpage.
                } else {
                        // Include the user module normally, i.e., raw to avoid it being wrapped in a closure.
-                       $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED,
-                               /* $extraQuery = */ array(), /* $loadCall = */ $inHead
-                       );
+                       $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED );
                }
 
                // Group JS is only enabled if site JS is enabled.
-               $links[] = $this->makeResourceLoaderLink( 'user.groups', ResourceLoaderModule::TYPE_COMBINED,
-                       /* $extraQuery = */ array(), /* $loadCall = */ $inHead
-               );
+               $links[] = $this->makeResourceLoaderLink( 'user.groups', ResourceLoaderModule::TYPE_COMBINED );
 
                return self::getHtmlFromLoaderLinks( $links );
        }
@@ -3114,17 +3106,11 @@ class OutputPage extends ContextSource {
                // In case the skin wants to add bottom CSS
                $this->getSkin()->setupSkinUserCss( $this );
 
-               // Optimise jQuery ready event cross-browser.
-               // This also enforces $.isReady to be true at </body> which fixes the
-               // mw.loader bug in Firefox with using document.write between </body>
-               // and the DOMContentReady event (bug 47457).
-               $html = Html::inlineScript( 'if(window.jQuery)jQuery.ready();' );
-
-               if ( !$this->getConfig()->get( 'ResourceLoaderExperimentalAsyncLoading' ) ) {
-                       $html .= $this->getScriptsForBottomQueue( false );
+               if ( $this->getConfig()->get( 'ResourceLoaderExperimentalAsyncLoading' ) ) {
+                       // Already handled by getHeadScripts()
+                       return '';
                }
-
-               return $html;
+               return  $this->getScriptsForBottomQueue();
        }
 
        /**
index ddaf1b2..387f24f 100644 (file)
@@ -1276,9 +1276,10 @@ class Sanitizer {
                        # Double-quoted
                        return $set[3];
                } elseif ( !isset( $set[2] ) ) {
-                       # In XHTML, attributes must have a value.
-                       # For 'reduced' form, return explicitly the attribute name here.
-                       return $set[1];
+                       # In XHTML, attributes must have a value so return an empty string.
+                       # See "Empty attribute syntax",
+                       # http://www.w3.org/TR/html5/syntax.html#syntax-attribute-name
+                       return "";
                } else {
                        throw new MWException( "Tag conditions not met. This should never happen and is a bug." );
                }
index cefbe62..665a689 100644 (file)
@@ -519,19 +519,24 @@ class User implements IDBAccessObject {
         * If the code is invalid or has expired, returns NULL.
         *
         * @param string $code Confirmation code
+        * @param int $flags User::READ_* bitfield
         * @return User|null
         */
-       public static function newFromConfirmationCode( $code ) {
-               $dbr = wfGetDB( DB_SLAVE );
-               $id = $dbr->selectField( 'user', 'user_id', array(
-                       'user_email_token' => md5( $code ),
-                       'user_email_token_expires > ' . $dbr->addQuotes( $dbr->timestamp() ),
-                       ) );
-               if ( $id !== false ) {
-                       return User::newFromId( $id );
-               } else {
-                       return null;
-               }
+       public static function newFromConfirmationCode( $code, $flags = 0 ) {
+               $db = ( $flags & self::READ_LATEST ) == self::READ_LATEST
+                       ? wfGetDB( DB_MASTER )
+                       : wfGetDB( DB_SLAVE );
+
+               $id = $db->selectField(
+                       'user',
+                       'user_id',
+                       array(
+                               'user_email_token' => md5( $code ),
+                               'user_email_token_expires > ' . $db->addQuotes( $db->timestamp() ),
+                       )
+               );
+
+               return $id ? User::newFromId( $id ) : null;
        }
 
        /**
index 87f5f70..1ce3830 100644 (file)
        "apihelp-query+search-example-generator": "Отримати інформацію про сторінки, на яких знайдено <kbd>meaning</kbd>.",
        "apihelp-query+siteinfo-description": "Видати загальну інформацію про сайт.",
        "apihelp-query+siteinfo-param-prop": "Яку інформацію отримати:\n;general:Загальна системна інформація.\n;namespaces:Список зареєстрованих просторів назв та їхні канонічні назви.\n;namespacealiases:Список зареєстрованих синонімів просторів назв.\n;specialpagealiases:Список аліасів спеціальної сторінки.\n;magicwords:Список магічних слів та їх аліасів.\n;statistics:Видає статистику сайту.\n;interwikimap:Видає карту інтервікі (за бажанням, фільтровану, за бажанням локалізовану з використанням <var>$1inlanguagecode</var>).\n;dbrepllag:Видає сервер бази даних з найбільшою затримкою відповіді.\n;usergroups:Видає групи користувачів і пов'язані дозволи.\n;libraries:Видає бібліотеки, встановлені у вікі.\n;extensions:Видає розширення, встановлені у вікі.\n;fileextensions:Видає список розширень файлів, які дозволено завантажувати.\n;rightsinfo:Видає інформацію щодо прав (ліцензії) вікі, якщо наявна.\n;restrictions:Видає інформацію про наявні типи обмежень (захисту).\n;languages:Видає список мов, які підтримує MediaWiki (за бажанням локалізовані через <var>$1inlanguagecode</var>).\n;skins:Видє список усіх доступних тем оформлення (опціонально локалізовані з використанням <var>$1inlanguagecode</var>, в іншому разі — мовою вмісту).\n;extensiontags:Видає список теґів розширення парсеру.\n;functionhooks:Видає список of parser function hooks.\n;showhooks:Returns a list of all subscribed hooks (contents of <var>[[mw:Manual:$wgHooks|$wgHooks]]</var>).\n;variables:Returns a list of variable IDs.\n;protocols:Returns a list of protocols that are allowed in external links.\n;defaultoptions:Returns the default values for user preferences.",
+       "apihelp-query+siteinfo-param-filteriw": "Видати лише локальні або лише нелокальні елементи карти інтервікі.",
+       "apihelp-query+siteinfo-param-showalldb": "Перелічити усі сервери баз даних, а не лише той, який робить найбільшу затримку.",
+       "apihelp-query+siteinfo-param-numberingroup": "Перераховує кількість користувачів у групах користувачів.",
+       "apihelp-query+siteinfo-param-inlanguagecode": "Код мови для локалізованих назв мов (найкращий варіант) і назв тем оформлення.",
+       "apihelp-query+siteinfo-example-simple": "Вибрати інформацію про сайт.",
+       "apihelp-query+siteinfo-example-interwiki": "Отримати список локальних інтервікі-префіксів.",
+       "apihelp-query+siteinfo-example-replag": "Перевірити поточне відставання реплікації.",
+       "apihelp-query+stashimageinfo-description": "Видає інформацію про приховані файли.",
+       "apihelp-query+stashimageinfo-param-filekey": "Ключ, який ідентифікує попереднє завантаження, що було тимчасово приховане.",
+       "apihelp-query+stashimageinfo-param-sessionkey": "Аліас для $1filekey, для зворотної сумісності.",
+       "apihelp-query+stashimageinfo-example-simple": "Видає інформацію про прихований файл.",
+       "apihelp-query+stashimageinfo-example-params": "Видає мініатюри для двох прихованих файлів.",
+       "apihelp-query+tags-description": "Перелічити мітки змін.",
+       "apihelp-query+tags-param-limit": "Максимальна кількість міток у списку.",
+       "apihelp-query+tags-param-prop": "Які властивості отримати:\n;name:Додає назву мітки.\n;displayname:Додає системне повідомлення для мітки.\n;description:Додає опис мітки.\n;hitcount:Додає кількість версій та записів журналу, які мають цю мітку.\n;defined:Показує, чи мітка визначена.\n;source:Отримує джерела мітки, що може включати <samp>extension</samp> для визначених розширеннями міток і <samp>manual</samp> для міток, які користувачі можуть застосовувати вручну.\n;active:Чи мітка ще застосовується.",
+       "apihelp-query+tags-example-simple": "Перелічити доступні мітки.",
+       "apihelp-query+templates-description": "Видає усі сторінки, які включені на вказаних сторінках.",
+       "apihelp-query+templates-param-namespace": "Показати шаблони лише у цьому просторі назв.",
+       "apihelp-query+templates-param-limit": "Скільки шаблонів виводити.",
+       "apihelp-query+templates-param-templates": "Перерахувати лише ці шаблони. Корисно для перевірки, чи певна сторінка використовує певний шаблон.",
+       "apihelp-query+templates-param-dir": "Напрямок, у якому перелічити.",
+       "apihelp-query+templates-example-simple": "Отримати шаблони, використані на сторінці <kbd>Main Page</kbd>.",
+       "apihelp-query+templates-example-generator": "Отримати інформацію про сторінки шаблонів, використаних на сторінці <kbd>Main Page</kbd>.",
+       "apihelp-query+templates-example-namespaces": "Отримати сторінки у просторах назв {{ns:user}} і {{ns:template}}, які включені на сторінці <kbd>Main Page</kbd>.",
+       "apihelp-query+tokens-description": "Отримує токени для дій, що змінюють дані.",
+       "apihelp-query+tokens-param-type": "Типи токена для запиту.",
+       "apihelp-query+tokens-example-simple": "Отримати csrf-токен (за замовчуванням).",
+       "apihelp-query+tokens-example-types": "Отримати токен спостереження і токен патрулювання.",
+       "apihelp-query+transcludedin-description": "Знайти усі сторінки, що включають подані сторінки.",
+       "apihelp-query+transcludedin-param-prop": "Які властивості отримати:\n;pageid:ID кожної сторінки.\n;title:Назва кожної сторінки.\n;redirect:Помітка, якщо сторінка є перенаправленням.",
+       "apihelp-query+transcludedin-param-namespace": "Включати сторінки лише в цих просторах назв.",
+       "apihelp-query+transcludedin-param-limit": "Скільки результатів виводити.",
+       "apihelp-query+transcludedin-param-show": "Показати лише елементи, що відповідають цим критеріям:\n;redirect:Показати лише перенаправлення.\n;!redirect:Показати лише не перенаправлення.",
+       "apihelp-query+transcludedin-example-simple": "Отримати список сторінок, що включають <kbd>Main Page</kbd>.",
+       "apihelp-query+transcludedin-example-generator": "Отримати інформацію про сторінки, які включають <kbd>Main Page</kbd>.",
+       "apihelp-query+usercontribs-description": "Отримати всі редагування користувача.",
+       "apihelp-query+usercontribs-param-limit": "Максимальна кількість елементів внеску для виведення.",
+       "apihelp-query+usercontribs-param-start": "З якої часової мітки виводити.",
+       "apihelp-query+usercontribs-param-end": "До якої часової мітки виводити.",
+       "apihelp-query+usercontribs-param-user": "Користувачі, для яких отримати внесок.",
+       "apihelp-query+usercontribs-param-userprefix": "Отримати внесок усіх користувачів, чиї імена починаються цим значенням. Перевизначає $1user.",
+       "apihelp-query+usercontribs-param-namespace": "Перерахувати записи внеску лише в цих просторах назв.",
+       "apihelp-query+usercontribs-param-prop": "Включити додаткові відомомсті:\n;ids:Додає ID сторінки й ID версії.\n;title:Додає назву й ID простору назв сторінки.\n;timestamp:Додає часову мітку редагування.\n;comment:Додає коментар редагування.\n;parsedcomment:Додає проаналізований коментар редагування.\n;size:Додає новий розмір редагування.\n;sizediff:Додає зміну розміру порівняно з попереднім редагуванням.\n;flags:Додає прапорці редагування.\n;patrolled:Відзначає патрульовані редагування.\n;tags:Перелічує мітки редагування.",
+       "apihelp-query+usercontribs-param-show": "Показати лише елементи, що відповідають цим критеріям, наприклад, лише не незначні редагування: <kbd>$2show=!minor</kbd>.\n\nЯкщо вказано <kbd>$2show=patrolled</kbd> або <kbd>$2show=!patrolled</kbd>, версії, старіші ніж <var>[[mw:Manual:$wgRCMaxAge|$wgRCMaxAge]]</var> ($1 {{PLURAL:$1|секунда|секунди|секунд}}) не будуть показуватися.",
+       "apihelp-query+usercontribs-param-tag": "Перерахувати лише версії, помічені цим теґом.",
+       "apihelp-query+usercontribs-param-toponly": "Виводити лише зміни, які є останньою версією.",
+       "apihelp-query+usercontribs-example-user": "Показати внесок користувача <kbd>Example</kbd>.",
+       "apihelp-query+usercontribs-example-ipprefix": "Показати внесок з усіх IP-адрес з префіксом <kbd>192.0.2.</kbd>.",
+       "apihelp-query+userinfo-description": "Отримати інформацію про поточного користувача.",
+       "apihelp-query+users-description": "Отримати інформацію про список користувачів.",
+       "apihelp-query+users-param-prop": "Яку інформацію включити:\n;blockinfo:Мітки про те чи є користувач заблокованим, ким, і з якою причиною.\n;groups:Перелічує всі групи, до яких належить кожен з користувачів.\n;implicitgroups:Перелічує всі групи, членом яких користувач є автоматично.\n;rights:Перелічує всі права, які має кожен з користувачів.\n;editcount:Додає лічильник редагувань користувача.\n;registration:Додає часову мітку реєстрації користувача.\n;emailable:Помічає чи хоче користувач отримувати електронну пошту через [[Special:Emailuser]].\n;gender:Помічає стать користувача. Повертає \"male\", \"female\", або \"unknown\".",
+       "apihelp-revisiondelete-description": "Вилучити або відновити версії.",
+       "apihelp-revisiondelete-param-type": "Тип здійснюваного вилучення версії.",
+       "apihelp-revisiondelete-param-target": "Назва сторінки, версію якої вилучити, якщо вимагається для цього типу.",
+       "apihelp-revisiondelete-param-ids": "Ідентифікатори версій, які слід вилучити.",
+       "apihelp-revisiondelete-param-hide": "Що приховати у кожній з версій.",
+       "apihelp-revisiondelete-param-show": "Що показати у кожній з версії.",
+       "apihelp-revisiondelete-param-suppress": "Чи приховати дані від адміністраторів так само як від усіх інших.",
+       "apihelp-revisiondelete-param-reason": "Причина вилучення або відновлення.",
+       "apihelp-revisiondelete-example-revision": "Приховати вміст версії <kbd>12345</kbd> сторінки <kbd>Main Page</kbd>.",
+       "apihelp-revisiondelete-example-log": "Приховати всі дані у записі журналу <kbd>67890</kbd> з причиною <kbd>BLP violation</kbd>.",
+       "apihelp-rollback-description": "Скасувати останнє редагування цієї сторінки.\n\nЯкщо користувач, який редагував сторінку, зробив декілька редагувань підряд, їх усі буде відкочено.",
+       "apihelp-rollback-param-title": "Назва сторінки, у якій здійснити відкіт. Не може використовуватись разом з <var>$1pageid</var>.",
+       "apihelp-rollback-param-pageid": "Ідентифікатор сторінки у якій здійснити відкіт. Не може використовуватись разом з <var>$1title</var>.",
+       "apihelp-rollback-param-user": "Ім'я користувача чиї редагування слід відкотити.",
+       "apihelp-rollback-param-summary": "Нестандартний опис редагування. Якщо порожній, буде використано опис редагування за замовчуванням.",
+       "apihelp-rollback-param-markbot": "Позначити відкинуті редагування та відкіт як редагування бота.",
+       "apihelp-rollback-param-watchlist": "Безумовно додати або вилучити сторінку із списку спостереження поточного користувача, використати налаштування, або не змінювати статус (не)спостереження.",
+       "apihelp-rollback-example-simple": "Відкинути останні редагування сторінки <kbd>Main Page</kbd> здійснені користувачем <kbd>Example</kbd>.",
+       "apihelp-rollback-example-summary": "Відкинути останні редагування сторінки <kbd>Main Page</kbd> здійснені IP-користувачем <kbd>192.0.2.5</kbd> з причиною <kbd>Reverting vandalism</kbd>, та позначити ці редагування та відкіт як редагування бота.",
+       "apihelp-setnotificationtimestamp-description": "Оновити часову мітку сповіщень для сторінок, що спостерігаються.\n\nЦе зачепить підсвічування змінених сторінок у списку спостереження та історії, а також надсилання електронного листа якщо опція налаштувань «{{int:tog-enotifwatchlistpages}}» увімкнена.",
+       "apihelp-setnotificationtimestamp-param-entirewatchlist": "Опрацювати всі сторінки, що спостерігаються.",
+       "apihelp-setnotificationtimestamp-param-timestamp": "Часова мітка, яку вказати у якості часової мітки сповіщень.",
+       "apihelp-setnotificationtimestamp-param-torevid": "Версія до якої вказати часову мітку сповіщень (лише одна сторінка).",
+       "apihelp-setnotificationtimestamp-param-newerthanrevid": "Версія, до новішої від якої вказати часову мітку сповіщень (лише одна сторінка).",
+       "apihelp-setnotificationtimestamp-example-all": "Стерти статус сповіщень для всього списку спостереження.",
+       "apihelp-setnotificationtimestamp-example-page": "Стерти статус сповіщень для <kbd>Main page</kbd>.",
+       "apihelp-setnotificationtimestamp-example-pagetimestamp": "Встановити часову мітку сповіщень для <kbd>Main page</kbd> так, що всі редагування після 1 січня 2012 будуть виглядати як не переглянуті.",
+       "apihelp-setnotificationtimestamp-example-allpages": "Стерти статус сповіщень для сторінок у просторі назв <kbd>{{ns:user}}</kbd>.",
+       "apihelp-tag-description": "Додати або вилучити зміни міток з окремих версій або записів журналу.",
+       "apihelp-tag-param-rcid": "Один або більше ідентифікаторів останніх змін, до яких додати або вилучити мітки.",
+       "apihelp-tag-param-revid": "Один або більше ідентифікатор з якого додати або вилучити мітку.",
+       "apihelp-tag-param-logid": "Один або більше ідентифікатор запису журналу з якого вилучити або додати мітку.",
+       "apihelp-tag-param-add": "Мітки, які слід додати. Лише визначені вручну мітки може бути додано.",
+       "apihelp-tag-param-remove": "Мітки, які слід вилучити. Лише мітки, які було визначено вручну, або взагалі не визначено, можуть бути вилучені.",
+       "apihelp-tag-param-reason": "Причина зміни.",
+       "apihelp-tag-example-rev": "Додати мітку <kbd>vandalism</kbd> до версії з ідентифікатором 123 без вказання причини",
+       "apihelp-tag-example-log": "Вилучити мітку <kbd>spam</kbd> з запису журналу з ідентифікатором 123 з причиною <kbd>Wrongly applied</kbd>",
+       "apihelp-tokens-description": "Отримати жетони для дій пов'язаних зі зміною даних.\n\nЦей модуль застарів на користь [[Special:ApiHelp/query+tokens|action=query&meta=tokens]].",
+       "apihelp-tokens-param-type": "Які типи жетонів запитати.",
+       "apihelp-tokens-example-edit": "Отримати жетон редагування (за замовчуванням).",
+       "apihelp-tokens-example-emailmove": "Отримати жетон електронної пошти та жетон перейменування.",
+       "apihelp-unblock-description": "Розблокувати користувача.",
+       "apihelp-unblock-param-id": "Ідентифікатор блоку чи розблокування (отриманий через <kbd>list=blocks</kbd>). Не може бути використано разом з <var>$1user</var>.",
+       "apihelp-unblock-param-user": "Ім'я користувача, IP-адреса чи IP-діапазон до розблокування. Не може бути використано разом з <var>$1id</var>.",
+       "apihelp-unblock-param-reason": "Причина розблокування.",
+       "apihelp-unblock-example-id": "Зняти блокування з ідентифікатором #<kbd>105</kbd>.",
+       "apihelp-unblock-example-user": "Розблокувати користувача <kbd>Bob</kbd> з причиною <kbd>Sorry Bob</kbd>.",
+       "apihelp-undelete-description": "Відновити версії вилученої сторінки.\n\nСписок вилучених версій (включено з часовими мітками) може бути отримано через [[Special:ApiHelp/query+deletedrevs|list=deletedrevs]], а список ідентифікаторів вилучених файлів може бути отримано через [[Special:ApiHelp/query+filearchive|list=filearchive]].",
+       "apihelp-undelete-param-title": "Назва сторінки, яку слід відновити.",
+       "apihelp-undelete-param-reason": "Причина відновлення.",
+       "apihelp-undelete-param-timestamps": "Часові мітки версій, які слід відновити. Якщо і <var>$1timestamps</var>, і <var>$1fileids</var> порожні, буде відновлено всі версії.",
+       "apihelp-undelete-param-fileids": "Ідентифікатори версій файлів, які слід відновити. Якщо і <var>$1timestamps</var>, і <var>$1fileids</var> порожні, буде відновлено всі версії.",
+       "apihelp-undelete-param-watchlist": "Безумовно додати або вилучити сторінку із списку спостереження поточного користувача, використати налаштування, або не змінювати статус (не)спостереження.",
+       "apihelp-undelete-example-page": "Відновити сторінку <kbd>Main Page</kbd>.",
+       "apihelp-undelete-example-revisions": "Відновити дві версії сторінки <kbd>Main Page</kbd>.",
+       "apihelp-upload-description": "Завантажити файл, або отримати статус завантажень у процесі.\n\nДоступні декілька методів:\n* Завантажити вміст файлу напряму, використовуючи параметр <var>$1file</var>.\n* Завантажити файл шматками, використовуючи параметри <var>$1filesize</var>, <var>$1chunk</var>, та <var>$1offset</var>.\n* Змусити сервер Медіавікі отримати файл за URL, використовуючи параметр <var>$1url</var>.\n* Завершити раніше розпочате завантаження, яке не вдалось через попередження, використовуючи параметр <var>$1filekey</var>.\nЗауважте, що HTTP POST повинен бути здійснений як завантаження файлу (наприклад, використовуючи <code>multipart/form-data</code>)",
+       "apihelp-upload-param-filename": "Цільова назва файлу.",
+       "apihelp-upload-param-comment": "Коментар завантаження. Також використовується як початковий текст сторінок для нових файлів, якщо <var>$1text</var> не вказано.",
+       "apihelp-upload-param-text": "Початковий текст сторінок для нових файлів.",
+       "apihelp-upload-param-watch": "Спостерігати за сторінкою.",
+       "apihelp-upload-param-watchlist": "Безумовно додати або вилучити сторінку із списку спостереження поточного користувача, використати налаштування, або не змінювати статус (не)спостереження.",
+       "apihelp-upload-param-ignorewarnings": "Ігнорувати всі попередження.",
+       "apihelp-upload-param-file": "Вміст файлу.",
+       "apihelp-upload-param-url": "URL з якого отримати файл.",
+       "apihelp-upload-param-filekey": "Ключ, що ідентифікує попереднє завантаження яке було відкладено тимчасово",
+       "apihelp-upload-param-stash": "Якщо вказано, сервер тимчасово відкладе файл замість додати його до репозиторію.",
+       "apihelp-upload-param-filesize": "Розмір файлу цілого завантаження.",
+       "apihelp-upload-param-offset": "Зміщення шматка в байтах.",
+       "apihelp-upload-param-chunk": "Шматок вмісту.",
+       "apihelp-upload-param-async": "Зробити операції з потенційно великими файлами асинхронними коли можливо.",
+       "apihelp-upload-param-asyncdownload": "Зробити отримання за URL асинхронним.",
+       "apihelp-upload-param-statuskey": "Отримати статус завантаження для цього ключа файлу (завантаження за URL)",
+       "apihelp-upload-param-checkstatus": "Отримувати статус завантаження лише для даного ключа файлу.",
+       "apihelp-upload-example-url": "Завантаження з URL.",
+       "apihelp-upload-example-filekey": "Завершити завантаження, що не вдалось через попередження.",
        "apihelp-userrights-description": "Змінити членство користувача у групах.",
        "apihelp-userrights-param-user": "Ім'я користувача.",
        "apihelp-userrights-param-userid": "Ідентифікатор користувача.",
        "api-pageset-param-pageids": "Список ідентифікаторів сторінок над якими працювати.",
        "api-pageset-param-revids": "Список ідентифікаторів версій над якими працювати.",
        "api-pageset-param-generator": "Отримати список сторінок над якими працювати шляхом виконання вказаного модуля запиту.\n\n<strong>Примітка:</strong> Назви параметрів генератора повинні мати префікс «g», див. приклади.",
+       "api-pageset-param-redirects-generator": "Автоматично вирішувати перенаправлення у <var>$1titles</var>, <var>$1pageids</var>, і <var>$1revids</var>, та у сторінках, повернених <var>$1generator</var>.",
+       "api-pageset-param-redirects-nogenerator": "Автоматично вирішувати перенаправлення у <var>$1titles</var>, <var>$1pageids</var>, та <var>$1revids</var>.",
+       "api-pageset-param-converttitles": "Конвертувати назви в інші варіанти за необхідності. Працює лише для вікі, мова вмісту яких підтримує конвертування варіантів. Мовами, що підтримують конвертування варіантів є $1.",
+       "api-help-title": "Довідка API Медіавікі",
+       "api-help-lead": "Це автоматично генерована сторінка документації API Медіавікі.\n\nДокументація та приклади: https://www.mediawiki.org/wiki/API",
+       "api-help-main-header": "Головний модуль",
+       "api-help-flag-deprecated": "Цей модуль є застарілим.",
+       "api-help-license": "Ліцензія: [[$1|$2]]",
+       "api-help-license-noname": "Ліцензія: [[$1|див. посилання]]",
+       "api-help-license-unknown": "Ліцензія: <span class=\"apihelp-unknown\">невідома</span>",
+       "api-help-param-deprecated": "Застарілий.",
        "api-help-datatypes-header": "Типи даних"
 }
index f97b83a..bcc333e 100644 (file)
        "apihelp-query+watchlistraw-param-totitle": "要列举的最终标题(带名字空间前缀)。",
        "apihelp-query+watchlistraw-example-simple": "列出当前用户的监视列表中的页面。",
        "apihelp-revisiondelete-description": "删除和恢复修订版本。",
+       "apihelp-revisiondelete-param-ids": "用于将被删除的修订的标识符。",
        "apihelp-revisiondelete-param-hide": "每次修订要隐藏的东西。",
        "apihelp-revisiondelete-param-show": "每次修订要恢复显示的东西。",
        "apihelp-revisiondelete-param-reason": "删除或恢复的原因。",
diff --git a/includes/dao/DBAccessObjectUtils.php b/includes/dao/DBAccessObjectUtils.php
new file mode 100644 (file)
index 0000000..58f991f
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * This file contains database access object related constants.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Database
+ */
+
+/**
+ * Helper class for DAO classes
+ *
+ * @since 1.26
+ */
+class DBAccessObjectUtils {
+       /**
+        * @param integer $bitfield
+        * @param integer $flags IDBAccessObject::READ_* constant
+        * @return bool Bitfield has flag $flag set
+        */
+       public static function hasFlags( $bitfield, $flags ) {
+               return ( $bitfield & $flags ) == $flags;
+       }
+
+       /**
+        * Get an appropriate DB index and options for a query
+        *
+        * @param integer $bitfield
+        * @return array (DB_MASTER/DB_SLAVE, SELECT options array)
+        */
+       public static function getDBOptions( $bitfield ) {
+               $index = self::hasFlags( $bitfield, IDBAccessObject::READ_LATEST )
+                       ? DB_MASTER
+                       : DB_SLAVE;
+
+               $options = array();
+               if ( self::hasFlags( $bitfield, IDBAccessObject::READ_EXCLUSIVE ) ) {
+                       $options[] = 'FOR UPDATE';
+               } elseif ( self::hasFlags( $bitfield, IDBAccessObject::READ_LOCKING ) ) {
+                       $options[] = 'LOCK IN SHARE MODE';
+               }
+
+               return array( $index, $options );
+       }
+}
\ No newline at end of file
index ca597ca..a3b6b96 100644 (file)
@@ -59,6 +59,8 @@ final class EnqueueJob extends Job {
         * @return EnqueueJob
         */
        public static function newFromJobsByWiki( array $jobsByWiki ) {
+               $deduplicate = true;
+
                $jobMapsByWiki = array();
                foreach ( $jobsByWiki as $wiki => $jobs ) {
                        $jobMapsByWiki[$wiki] = array();
@@ -68,10 +70,16 @@ final class EnqueueJob extends Job {
                                } else {
                                        throw new InvalidArgumentException( "Jobs must be of type JobSpecification." );
                                }
+                               $deduplicate = $deduplicate && $job->ignoreDuplicates();
                        }
                }
 
-               return new self( Title::newMainPage(), array( 'jobsByWiki' => $jobMapsByWiki ) );
+               $eJob = new self( Title::newMainPage(), array( 'jobsByWiki' => $jobMapsByWiki ) );
+               // If *all* jobs to be pushed are to be de-duplicated (a common case), then
+               // de-duplicate this whole job itself to avoid build up in high traffic cases
+               $eJob->removeDuplicates = $deduplicate;
+
+               return $eJob;
        }
 
        public function run() {
index 3d7fad5..100d2a4 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  */
 
+use Liuggio\StatsdClient\Entity\StatsdData;
 use Liuggio\StatsdClient\Entity\StatsdDataInterface;
 use Liuggio\StatsdClient\Factory\StatsdDataFactory;
 
@@ -75,6 +76,9 @@ class BufferingStatsdDataFactory extends StatsdDataFactory {
                return $entity;
        }
 
+       /**
+        * @return StatsdData[]
+        */
        public function getBuffer() {
                return $this->buffer;
        }
diff --git a/includes/libs/SamplingStatsdClient.php b/includes/libs/SamplingStatsdClient.php
new file mode 100644 (file)
index 0000000..d7791a8
--- /dev/null
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Copyright 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use Liuggio\StatsdClient\StatsdClient;
+use Liuggio\StatsdClient\Entity\StatsdData;
+use Liuggio\StatsdClient\Entity\StatsdDataInterface;
+
+/**
+ * A statsd client that applies the sampling rate to the data items before sending them.
+ *
+ * @since 1.26
+ */
+class SamplingStatsdClient extends StatsdClient {
+       /**
+        * Sets sampling rate for all items in $data.
+        * The sample rate specified in a StatsdData entity overrides the sample rate specified here.
+        *
+        * {@inheritDoc}
+        */
+       public function appendSampleRate( $data, $sampleRate = 1 ) {
+               if ( $sampleRate < 1 ) {
+                       array_walk( $data, function( $item ) use ( $sampleRate ) {
+                               /** @var $item StatsdData */
+                               if ( $item->getSampleRate() === 1 ) {
+                                       $item->setSampleRate( $sampleRate );
+                               }
+                       });
+               }
+
+               return $data;
+       }
+
+       /**
+        * Sample the metrics according to their sample rate and send the remaining ones.
+        *
+        * {@inheritDoc}
+        */
+       public function send( $data, $sampleRate = 1 ) {
+               if ( !is_array( $data ) ) {
+                       $data = array( $data );
+               }
+               if ( !$data ) {
+                       return;
+               }
+               foreach ( $data as $item ) {
+                       if ( !( $item instanceof StatsdDataInterface ) ) {
+                               throw new InvalidArgumentException(
+                                       'SamplingStatsdClient does not accept stringified messages' );
+                       }
+               }
+
+               // add sampling
+               if ( $sampleRate < 1 ) {
+                       $data = $this->appendSampleRate( $data, $sampleRate );
+               }
+               $data = $this->sampleData( $data );
+
+               $messages = array_map( 'strval', $data );
+
+               // reduce number of packets
+               if ( $this->getReducePacket() ) {
+                       $data = $this->reduceCount( $data );
+               }
+               //failures in any of this should be silently ignored if ..
+               $written = 0;
+               try {
+                       $fp = $this->getSender()->open();
+                       if ( !$fp ) {
+                               return;
+                       }
+                       foreach ( $messages as $message ) {
+                               $written += $this->getSender()->write( $fp, $message );
+                       }
+                       $this->getSender()->close( $fp );
+               } catch ( Exception $e ) {
+                       $this->throwException( $e );
+               }
+
+               return $written;
+       }
+
+       /**
+        * Throw away some of the data according to the sample rate.
+        * @param StatsdDataInterface[] $data
+        * @return array
+        * @throws LogicException
+        */
+       protected function sampleData( $data ) {
+               $newData = array();
+               $mt_rand_max = mt_getrandmax();
+               foreach ( $data as $item ) {
+                       $samplingRate = $item->getSampleRate();
+                       if ( $samplingRate <= 0.0 || $samplingRate > 1.0 ) {
+                               throw new LogicException( 'Sampling rate shall be within ]0, 1]' );
+                       }
+                       if (
+                               $samplingRate === 1 ||
+                               ( mt_rand() / $mt_rand_max <= $samplingRate )
+                       ) {
+                               $newData[] = $item;
+                       }
+               }
+               return $newData;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       protected function throwException( Exception $exception ) {
+               if ( !$this->getFailSilently() ) {
+                       throw $exception;
+               }
+       }
+}
index ae28cb8..b129bd2 100644 (file)
@@ -361,18 +361,18 @@ class WikiPage implements Page, IDBAccessObject {
                        return;
                }
 
-               if ( $from === self::READ_LOCKING ) {
-                       $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle, array( 'FOR UPDATE' ) );
-               } elseif ( $from === self::READ_LATEST ) {
-                       $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
-               } elseif ( $from === self::READ_NORMAL ) {
-                       $data = $this->pageDataFromTitle( wfGetDB( DB_SLAVE ), $this->mTitle );
+               if ( is_int( $from ) ) {
+                       list( $index, $opts ) = DBAccessObjectUtils::getDBOptions( $from );
+                       $data = $this->pageDataFromTitle( wfGetDB( $index ), $this->mTitle, $opts );
+
                        if ( !$data
+                               && $index == DB_SLAVE
                                && wfGetLB()->getServerCount() > 1
                                && wfGetLB()->hasOrMadeRecentMasterChanges()
                        ) {
                                $from = self::READ_LATEST;
-                               $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
+                               list( $index, $opts ) = DBAccessObjectUtils::getDBOptions( $from );
+                               $data = $this->pageDataFromTitle( wfGetDB( $index ), $this->mTitle, $opts );
                        }
                } else {
                        // No idea from where the caller got this data, assume slave database.
index 2936d76..89b9de6 100644 (file)
@@ -336,7 +336,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                }, array(
                        '$VARS.wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
                        '$VARS.configuration' => $this->getConfigSettings( $context ),
-                       '$VARS.baseModulesScript' => Html::linkedScript( self::getStartupModulesUrl( $context ) ),
+                       '$VARS.baseModulesUri' => self::getStartupModulesUrl( $context ),
                ) );
                $pairs['$CODE.registrations()'] = str_replace( "\n", "\n\t", trim( $this->getModuleRegistrations( $context ) ) );
 
index 327ef7c..2a1b0a3 100644 (file)
@@ -209,8 +209,6 @@ abstract class Skin extends ContextSource {
 
                // Add various resources if required
                if ( $wgUseAjax ) {
-                       $modules['legacy'][] = 'mediawiki.legacy.ajax';
-
                        if ( $wgEnableAPI ) {
                                if ( $wgEnableWriteAPI && $wgAjaxWatch && $user->isLoggedIn()
                                        && $user->isAllowed( 'writeapi' )
index b6ab112..6356155 100644 (file)
@@ -120,7 +120,7 @@ class EmailConfirmation extends UnlistedSpecialPage {
         * @param string $code Confirmation code
         */
        function attemptConfirm( $code ) {
-               $user = User::newFromConfirmationCode( $code );
+               $user = User::newFromConfirmationCode( $code, User::READ_LATEST );
                if ( !is_object( $user ) ) {
                        $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
 
@@ -164,7 +164,7 @@ class EmailInvalidation extends UnlistedSpecialPage {
         * @param string $code Confirmation code
         */
        function attemptInvalidate( $code ) {
-               $user = User::newFromConfirmationCode( $code );
+               $user = User::newFromConfirmationCode( $code, User::READ_LATEST );
                if ( !is_object( $user ) ) {
                        $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
 
index 442b764..b5f3815 100644 (file)
@@ -210,8 +210,21 @@ HTML;
                $query['only'] = 'scripts';
                $startupContext = new ResourceLoaderContext( $rl, new FauxRequest( $query ) );
 
+               $query['raw'] = true;
+
                $modules = $rl->getTestModuleNames( 'qunit' );
 
+               // Disable autostart because we load modules asynchronously. By default, QUnit would start
+               // at domready when there are no tests loaded and also fire 'QUnit.done' which then instructs
+               // Karma to end the run before the tests even started.
+               $qunitConfig = 'QUnit.config.autostart = false;'
+                       . 'if (window.__karma__) {'
+                       // karma-qunit's use of autostart=false and QUnit.start conflicts with ours.
+                       // Hack around this by replacing 'karma.loaded' with a no-op and call it ourselves later.
+                       // See <https://github.com/karma-runner/karma-qunit/issues/27>.
+                       . 'window.__karma__.loaded = function () {};'
+                       . '}';
+
                // The below is essentially a pure-javascript version of OutputPage::getHeadScripts.
                $startup = $rl->makeModuleResponse( $startupContext, array(
                        'startup' => $rl->getModule( 'startup' ),
@@ -225,35 +238,39 @@ HTML;
                        'user.options' => $rl->getModule( 'user.options' ),
                        'user.tokens' => $rl->getModule( 'user.tokens' ),
                ) );
-               $code .= Xml::encodeJsCall( 'mw.loader.load', array( $modules ) );
+               // Catch exceptions (such as "dependency missing" or "unknown module") so that we
+               // always start QUnit. Re-throw so that they are caught and reported as global exceptions
+               // by QUnit and Karma.
+               $code .= '(function () {'
+                       . 'var start = window.__karma__ ? window.__karma__.start : QUnit.start;'
+                       . 'try {'
+                       . 'mw.loader.using( ' . Xml::encodeJsVar( $modules ) . ' ).always( start );'
+                       . '} catch ( e ) { start(); throw e; }'
+                       . '}());';
 
                header( 'Content-Type: text/javascript; charset=utf-8' );
                header( 'Cache-Control: private, no-cache, must-revalidate' );
                header( 'Pragma: no-cache' );
+               echo $qunitConfig;
                echo $startup;
-               echo "\n";
-               // Note: The following has to be wrapped in a script tag because the startup module also
-               // writes a script tag (the one loading mediawiki.js). Script tags are synchronous, block
-               // each other, and run in order. But they don't nest. The code appended after the startup
-               // module runs before the added script tag is parsed and executed.
-               echo Xml::encodeJsCall( 'document.write', array( Html::inlineScript( $code ) ) );
+               // The following has to be deferred via RLQ because the startup module is asynchronous.
+               echo ResourceLoader::makeLoaderConditionalScript( $code );
        }
 
        private function plainQUnit() {
                $out = $this->getOutput();
                $out->disable();
 
-               $url = $this->getPageTitle( 'qunit/export' )->getFullURL( array(
-                       'debug' => ResourceLoader::inDebugMode() ? 'true' : 'false',
-               ) );
-
                $styles = $out->makeResourceLoaderLink( 'jquery.qunit',
                        ResourceLoaderModule::TYPE_STYLES
                );
-               // Use 'raw' since this is a plain HTML page without ResourceLoader
+
+               // Use 'raw' because QUnit loads before ResourceLoader initialises (omit mw.loader.state call)
+               // Use 'test' to ensure OutputPage doesn't use the "async" attribute because QUnit must
+               // load before qunit/export.
                $scripts = $out->makeResourceLoaderLink( 'jquery.qunit',
                        ResourceLoaderModule::TYPE_SCRIPTS,
-                       array( 'raw' => 'true' )
+                       array( 'raw' => true, 'sync' => true )
                );
 
                $head = implode( "\n", array_merge( $styles['html'], $scripts['html'] ) );
@@ -265,6 +282,10 @@ $head
 $summary
 <div id="qunit"></div>
 HTML;
+
+               $url = $this->getPageTitle( 'qunit/export' )->getFullURL( array(
+                       'debug' => ResourceLoader::inDebugMode() ? 'true' : 'false',
+               ) );
                $html .= "\n" . Html::linkedScript( $url );
 
                header( 'Content-Type: text/html; charset=utf-8' );
index a6f92d6..39980d2 100644 (file)
@@ -323,7 +323,7 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
                static $msgcache = null;
                if ( $msgcache === null ) {
                        static $msgs = array( 'isredirect', 'istemplate', 'semicolon-separator',
-                               'whatlinkshere-links', 'isimage', 'edit' );
+                               'whatlinkshere-links', 'isimage', 'editlink' );
                        $msgcache = array();
                        foreach ( $msgs as $msg ) {
                                $msgcache[$msg] = $this->msg( $msg )->escaped();
@@ -364,7 +364,7 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
                }
 
                # Space for utilities links, with a what-links-here link provided
-               $wlhLink = $this->wlhLink( $nt, $msgcache['whatlinkshere-links'], $msgcache['edit'] );
+               $wlhLink = $this->wlhLink( $nt, $msgcache['whatlinkshere-links'], $msgcache['editlink'] );
                $wlh = Xml::wrapClass(
                        $this->msg( 'parentheses' )->rawParams( $wlhLink )->escaped(),
                        'mw-whatlinkshere-tools'
index 38c8498..ab9ffd4 100644 (file)
@@ -14,7 +14,8 @@
                        "아라",
                        "Koroğlu",
                        "Baloch Afghanistan",
-                       "Macofe"
+                       "Macofe",
+                       "Sadiqr"
                ]
        },
        "tog-underline": "باغلانتی‌لارین آلتینی خطله:",
        "no-null-revision": "\"$1\" صحیفه‌سی اوچون یئنی بوش بیر نوسخه یارادیلا بیلمه‌دی",
        "badtitle": "پیس باشلیق",
        "badtitletext": "آختاریلان صحیفه‌‌ آدی سهودیر و يا بوْشدور، يا دا دۆزگون اوْلمايان دیللر‌آراسی، ياخود ویکیلرآراسی کئچید ایستیفاده ائدیلیب. \nباشلیقلاردا ایستیفاده ائدیلمه‌سی قاداغان اوْلونان بیر و يا داها چوْخ سیمووْل ایستیفاده ائدیلمیش اوْلا بیلر.",
+       "title-invalid-empty": "آختاردیٛغیٛنیٛز صفحه‌‌نین آدیٛ بوْشدۇر و یا آدلارفضاسیٛندا یالنیٛز آدیٛ وار.",
+       "title-invalid-utf8": "ایستنیلن صفحه‌نین آدیندا بیر یانلیش UTF-8 کاراکتِری وار.",
+       "title-invalid-characters": "ایستنیلن صفحه‌نین آدیندا، یانلیش کاراکتِرلر وار: «$1»",
        "perfcached": "بو بیلگی، کَش اولوب‌دور و اولا بیلر گونجل اولماسین. چوخو {{PLURAL:$1|بیر نتیجه|$1 نتیجه}} کَش‌ده‌دیر.",
        "perfcachedts": "بو بیلگی کَش اولوب‌دور، سون دفعه $1 واختیندا گونجلیب‌دیر. چوخو {{PLURAL:$4|بیر نتیجه|$4 نتیجه}} کَش‌ده‌دیر.",
        "querypage-no-updates": "بو یارپاق‌دا گونجل‌له‌مک ایندی باغلانیب‌دیر.\nبورداکی بیلگیلر یئنی‌لشمیه‌جکلر.",
        "actionthrottled": "سیزین چالیشمانیزین قاباغی آلیندی",
        "actionthrottledtext": "آنتی-ایسپام حرکت‌لری گؤره، بیر حرکتی قیسا بیر زامان آرالیغیندا چوخئتمه‌نیز انگللندی، و سیز حدی آشمیسینیز. لطفاً بیر نئچه دقیقه سونرا یئنی‌دن یوخلایین.",
        "protectedpagetext": "بو صحیفه دیَیشدیرمک و باشقا ایشلر اوچون باغلی‌دیر.",
-       "viewsourcetext": "سیز بو صحیفه‌نین مزمونونو گؤره و کؤچوره بیلرسینیز:",
-       "viewyourtext": "'''اؤز دَییشیکلیکلرینیز''' ین کودونو گؤروب و بو صحیفه‌یه کوپی ائده بیلرسینیز:",
+       "viewsourcetext": "سیز بو صفحه‌نین قایناغینی گؤروب و کؤچوره بیلرسینیز.",
+       "viewyourtext": "سیز بو صفحه‌ده <strong>اؤز دَییشیکلیکلرینیزین</strong> قایناغینی گؤروب و کوپی ائده بیلرسینیز.",
        "protectedinterface": "بو صحیفه‌ده پروقرام تأمیناتی اوچون سیستئم بیلگی‌لری وار و سوی-ایستیفاده‌نین قارشی‌سینی آلماق اوچون محافظه اولونما‌لی‌دیر.",
        "editinginterface": "<strong>دیقت:</strong> سیز بیر یازیلیم آرا-اوزونه یازی تعمین ائدن صحیفه‌نی دَییشدیرمک‌ده‌سینیز.\nبو صحیفه‌نی دَییشدیرمک، بو ویکی‌نی ایستیفاده ائدن باشقا ایستیفاده‌چیلرین گؤرونوشونو دَییشه‌جک‌دیر.",
        "translateinterface": "ترجومه و یا اونون دَییشدیرمک هامی ویکی لر اوچون [//translatewiki.net/ translatewiki.net]،مدیا ویکی نین یئرلری ائتمک پروژه سیندن ایستفاده ائدین",
        "boteditletter": "ب",
        "number_of_watching_users_pageview": "[{{PLURAL:$1|بیر|$1}} ایزله‌ین ایستیفاده‌چی]",
        "rc_categories": "بؤلمه‌لره محدودلاشدیر («|» ایله آییر)",
-       "rc_categories_any": "هر",
+       "rc_categories_any": "سئچیلمیشلرین هر بیریسی",
        "rc-change-size-new": "دَییشیکلیک‌دن سونرا {{PLURAL:|بیر|$1}} بایت",
        "newsectionsummary": "/* $1 */ یئنی بؤلمه",
        "rc-enhanced-expand": "تفصیل‌لری گؤستر",
        "randomincategory-nopages": "[[:Category:$1|$1]] بؤلمه‌سین‌ده، هئچ صحیفه یوخدور.",
        "randomincategory-category": "بؤلمه:",
        "randomincategory-legend": "بؤلمه‌ده راست‌گله صفحه",
+       "randomincategory-submit": "گئت",
        "randomredirect": "راست‌گله یول‌لاندیرما",
        "randomredirect-nopages": "«$1» آدفضاسیندا هئچ بیر یول‌لاندیرما یوخدور.",
        "statistics": "آمارلار",
        "tooltip-pt-logout": "چیخیش",
        "tooltip-pt-createaccount": "سیزدن دعوت اولونور ایشلدن حسابی آچیب و گیریش ائده‌سیز؛ آنجاق حساب یاراتماق ایستگه باغلی‌دیر",
        "tooltip-ca-talk": "ایچینده‌کیلره گؤره دانیشیق",
-       "tooltip-ca-edit": "سÛ\8cز Ø¨Ù\88 ØµÙ\81Ø­Ù\87â\80\8cÙ\86Û\8c Ø¯Ù\8eÛ\8cÛ\8cشدÛ\8cرÙ\87 Ø¨Û\8cÙ\84رسÛ\8cÙ\86Û\8cز. Ù\84Ø·Ù\81اÙ\8b Ù\82ئÛ\8cد Ø§Ø¦ØªÙ\85Ù\87â\80\8cدÙ\86 Ù\82اباÙ\82 Ø§Ø¤Ù\86â\80\8cگؤسترÛ\8cØ´ Ø¯Ù\88Ú¯Ù\85Ù\87â\80\8cسÛ\8cÙ\86Û\8c Ø§Û\8cØ´Ù\84دÛ\8cÙ\86",
+       "tooltip-ca-edit": "بÛ\87 ØµÙ\81Ø­Ù\87â\80\8câ\80\8cÙ\86Û\8c Ø¯Ù\8eÛ\8cÛ\8cشدÛ\8cر",
        "tooltip-ca-addsection": "یئنی بؤلوم یارات",
        "tooltip-ca-viewsource": "بو صحیفه‌‌ قورونوب‌دور.\nاونون قایناغینا باخا بیلرسیز",
        "tooltip-ca-history": "بو صفحه‌نین گئچمیش سۆروملری",
        "watchlistedit-raw-done": "ایزله‌دیکلرینیز گونجل‌لندی.",
        "watchlistedit-raw-added": "{{PLURAL:$1|بیر|$1}} باشلیق آرلیریلدی:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|بیر|$1}} باشلیق چیخاریلدی:",
+       "watchlistedit-clear-legend": "ایزلدیکلریمین لیستین سیل",
        "watchlistedit-clear-titles": "باشلیق‌لار:",
+       "watchlisttools-clear": "ایزلدیکلریمین لیستین سیل",
        "watchlisttools-view": "ایلگیلی دَییشیکلیکلره باخین",
        "watchlisttools-edit": "ایزله‌دیکلره باخ و اونلاری دَییشدیر",
        "watchlisttools-raw": "چیی ایزله‌دیکلری دَییشدیر",
        "version-libraries": "نصب اولونموش کیتابخانا",
        "version-libraries-library": "کیتاب‌ائوی",
        "version-libraries-version": "نوسخه‌",
+       "version-libraries-authors": "یازارلار",
        "redirect": "فایل، ایستیفاده‌چی، صفحه یا نوسخه آی‌دی-سی ایله یول‌لاندیرما",
        "redirect-legend": "بیر فایل یا صحیفه‌یه یول‌لاندیرما",
        "redirect-summary": "بو اؤزل صحیفه، بیر فایلا (فایل آدی ایله)، صفحه‌یه (نوسخه یا صفحه آی‌دی-سی ایله) یا ایستیفاده‌چی صفحه‌سینه (ایستیفاده‌چی نومره آی‌دی-سی ایله) یول‌لاندیریر. ایشلتمک: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]]، [[{{#Special:Redirect}}/revision/328429]]، یا [[{{#Special:Redirect}}/user/101]].",
        "tags-active-no": "یوْخ",
        "tags-edit": "دَییشدیر",
        "tags-delete": "سیل",
+       "tags-activate": "ائتکینلشدیر",
        "tags-hitcount": "$1 {{PLURAL:$1|دییشیکلیک|دییشیک‌لیک}}",
        "tags-create-submit": "یارات",
        "tags-edit-title": "اِتیکِتلری دَییشدیر",
        "htmlform-cloner-create": "چوْخراق آرتیر",
        "htmlform-cloner-delete": "سیل",
        "htmlform-cloner-required": "ان آزی بیر دیَر گرکلیدیر.",
+       "htmlform-title-badnamespace": "[[:$1]]، «{{ns:$2}}» آدفضاسیندا دئییل.",
+       "htmlform-title-not-creatable": "«$1» بیر یارانا بیلن صفحه آدی دئییل",
+       "htmlform-title-not-exists": "[[:$1]] یوخدور.",
+       "htmlform-user-not-exists": "<strong>$1</strong> یوخدور.",
+       "htmlform-user-not-valid": "<strong>$1</strong> بیر دوزگون ایشلدن آدی دئییل.",
        "sqlite-has-fts": "$1 بوتون یازی آختارما دستگی‌له",
        "sqlite-no-fts": "$1 بوتون یازی آختارماماق‌لا",
        "logentry-delete-delete": "$1، $3 صحیفه‌سینی {{GENDER:$2|سیلدی}}",
        "pagelang-name": "صفحه",
        "pagelang-language": "دیل",
        "pagelang-select-lang": "دیل سئچمه‌سی",
+       "right-pagelang": "صفحه دیلینی دَییشدیر",
+       "action-pagelang": "صفحه دیلینی دَییشدیر",
+       "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (ائتکین)",
+       "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''ائتکیسیز''')",
+       "mediastatistics": "مئدیا آمارلاری",
+       "mediastatistics-nbytes": "{{PLURAL:$1|$1}} بایت ($2؛ ٪$3)",
+       "mediastatistics-table-mimetype": "MIME تیپی",
        "mediastatistics-table-count": "فایل‌لارین سایی",
        "mediastatistics-header-unknown": "بیلینمه‌ین",
        "mediastatistics-header-bitmap": "بیت‌مپ گؤرونتولر",
        "mediastatistics-header-audio": "سس",
        "mediastatistics-header-video": "ویدیولار",
        "mediastatistics-header-office": "دفتر",
+       "mediastatistics-header-text": "یازیلی",
        "headline-anchor-title": "بو بؤلومه باغلانتی",
        "special-characters-group-latin": "لاتین",
        "special-characters-group-latinextended": "لاتین گئنیشلندیریلمیش",
        "special-characters-group-khmer": "خمر",
        "special-characters-title-endash": "آرالیق خطی دی",
        "special-characters-title-emdash": "آرالیق خطی چکیلیب",
-       "special-characters-title-minus": "منفی علامتی"
+       "special-characters-title-minus": "منفی علامتی",
+       "mw-widgets-dateinput-no-date": "تاریخ سئچیلمه‌ییب",
+       "mw-widgets-titleinput-description-new-page": "صفحه هله‌لیک یوخدور",
+       "mw-widgets-titleinput-description-redirect": "$1-ه یول‌لاندیر"
 }
index 0bb94da..fce5289 100644 (file)
        "actionthrottled": "কাজের গতি ধীরকরণ",
        "actionthrottledtext": "স্প্যাম-রোধী সমাধান হিসেবে এই কাজটি খুব কম সময়ে অনেক বেশিবার সম্পাদনা করার সীমা বেঁধে দেওয়া হয়েছে। আপনি সেই সীমা অতিক্রম করেছেন। অনুগ্রহ করে কয়েক মিনিট পরে আবার চেষ্টা করুন।",
        "protectedpagetext": "সম্পাদনা অথবা স্থানান্তর এড়াতে এ পাতাটির ব্যবহার নিয়ন্ত্রণ করা হয়েছে।",
-       "viewsourcetext": "এ পাতাটি আপনি দেখতে এবং উৎসের অনুলিপি নিতে পারবেন:",
-       "viewyourtext": "আপনি এই পাতায় <strong>আপনার সম্পাদনা</strong>দেখতে এবং অনুলিপি করতে পারেন:",
+       "viewsourcetext": "এ পাতাটি আপনি দেখতে এবং উৎসের অনুলিপি নিতে পারবেন",
+       "viewyourtext": "আপনি এই পাতায় <strong>আপনার সম্পাদনা</strong>দেখতে এবং অনুলিপি করতে পারেন",
        "protectedinterface": "এই পাতার বিষয়বস্তু এই উইকি সফটওয়্যারের একটি ইন্টারফেস বার্তা প্রদান করে, তাই এটিকে সুরক্ষিত করে রাখা হয়েছে।\nসকল উইকির অনুবাদে কোনো ধরনের সংযোজন বা পরিবর্তন করতে, অনুগ্রহ করে মিডিয়াউইকি স্থানীয়করন প্রকল্প [//translatewiki.net/ translatewiki.net] ব্যবহার করুন।",
        "editinginterface": "<strong>সতর্কীকরণ:</strong> আপনি এমন একটি পাতা সম্পাদনা করছেন যা সফটওয়্যারের জন্য ইন্টারফেস টেক্সট প্রদান করে।\nএই পাতাতে সংঘটিত পরিবর্তন এই উইকির ব্যবহারকারীদের ইন্টারফেসে প্রভাব ফেলবে, যা অন্য ব্যবহারকারীরা দেখতে পাবেন।",
        "translateinterface": "সকল উইকির জন্য অনুবাদ যোগ বা পরিবর্তন করতে, দয়া করে [//translatewiki.net/ translatewiki.net], মিডিয়াউইকি স্থানীয়করণ প্রকল্প ব্যবহার করুন।",
        "newpageletter": "ন",
        "boteditletter": "ব",
        "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|জন ব্যবহারকারী|জন ব্যবহারকারী}} এই পাতার উপর নজর রাখছেন]",
-       "rc_categories": "à¦\8fà¦\87 à¦¬à¦¿à¦·à¦¯à¦¼à¦¶à§\8dরà§\87ণà§\80à¦\97à§\81লিতà§\87 à¦¸à§\80মাবদà§\8dধ à¦\95রা à¦¹à§\8bà¦\95 (\"|\" à¦¦à¦¿à¦¯à¦¼à§\87 à¦\86লাদা à¦\95রà§\87 à¦²à¦¿à¦\96à§\81ন)",
-       "rc_categories_any": "যà§\87à¦\95à§\8bনà§\8b",
+       "rc_categories": "বিষয়শà§\8dরà§\87ণà§\80à¦\97à§\81লিতà§\87 à¦¸à§\80মা (\"|\" à¦¦à¦¿à¦¯à¦¼à§\87 à¦\86লাদা à¦\95রà§\81ন):",
+       "rc_categories_any": "à¦\9aয়নà§\87র à¦\9cনà§\8dয à¦¯à§\87à¦\95à§\8bনà§\8b à¦\95িà¦\9bà§\81",
        "rc-change-size-new": "পরিবর্তনের পর $1 {{PLURAL:$1|বাইট}}",
        "newsectionsummary": "/* $1 */ নতুন অনুচ্ছেদ",
        "rc-enhanced-expand": "বিস্তারিত দেখাও",
index 34f3a3c..18d4036 100644 (file)
        "viewsourcelink": "pogledaj izvor",
        "editsectionhint": "Uredi sekciju: $1",
        "toc": "Sadržaj",
-       "showtoc": "pokaži",
+       "showtoc": "prikaži",
        "hidetoc": "sakrij",
        "collapsible-collapse": "sklopi",
        "collapsible-expand": "Proširi",
        "rev-deleted-diff-view": "Jedna od revizija u ovoj razlici je '''obrisana'''.\nVi možete vidjeti ovu razliku; detalji o tome se mogu vidjeti u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} zapisniku brisanja].",
        "rev-suppressed-diff-view": "Jedna od revizija u ovoj razlici je '''sakrivena'''.\nVi možete vidjeti ovu razliku; detalji se mogu vidjeti u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} zapisniku sakrivanja].",
        "rev-delundel": "pokaži/sakrij",
-       "rev-showdeleted": "Pokaži",
+       "rev-showdeleted": "prikaži",
        "revisiondelete": "Obriši/vrati revizije",
        "revdelete-nooldid-title": "Nije unesena tačna revizija",
        "revdelete-nooldid-text": "Niste odredili odredišnu verziju da se izvrši ova funkcija, ili ta verzija ne postoji, ili pokušavate sakriti trenutnu verziju.",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|spisak novih stranica]])",
        "rcnotefrom": "Ispod {{PLURAL:$5|je izmjena|su izmjene}} od <strong>$3, $4</strong> (do <strong>$1</strong> prikazano).",
        "rclistfrom": "Prikaži nove izmjene počev od $3 $2",
-       "rcshowhideminor": "$1 male izmjene",
-       "rcshowhideminor-show": "Pokaži",
+       "rcshowhideminor": "$1 manje izmjene",
+       "rcshowhideminor-show": "Prikaži",
        "rcshowhideminor-hide": "Sakrij",
        "rcshowhidebots": "$1 botove",
-       "rcshowhidebots-show": "Pokaži",
+       "rcshowhidebots-show": "Prikaži",
        "rcshowhidebots-hide": "Sakrij",
        "rcshowhideliu": "$1 registrovane korisnike",
-       "rcshowhideliu-show": "Pokaži",
+       "rcshowhideliu-show": "Prikaži",
        "rcshowhideliu-hide": "Sakrij",
        "rcshowhideanons": "$1 anonimne korisnike",
-       "rcshowhideanons-show": "Pokaži",
+       "rcshowhideanons-show": "Prikaži",
        "rcshowhideanons-hide": "Sakrij",
        "rcshowhidepatr": "$1 patrolirane izmjene",
-       "rcshowhidepatr-show": "Pokaži",
+       "rcshowhidepatr-show": "Prikaži",
        "rcshowhidepatr-hide": "Sakrij",
        "rcshowhidemine": "$1 moje izmjene",
-       "rcshowhidemine-show": "Pokaži",
+       "rcshowhidemine-show": "Prikaži",
        "rcshowhidemine-hide": "Sakrij",
        "rclinks": "Prikaži najskorijih $1 izmjena u posljednjih $2 dana<br />$3",
        "diff": "razl",
        "withoutinterwiki": "Članci bez interwiki linkova",
        "withoutinterwiki-summary": "Slijedeće stranice nemaju linkove prema verzijama na drugim jezicima.",
        "withoutinterwiki-legend": "Prefiks",
-       "withoutinterwiki-submit": "Pokaži",
+       "withoutinterwiki-submit": "Prikaži",
        "fewestrevisions": "Stranice sa najmanje izmjena",
        "nbytes": "$1 {{PLURAL:$1|bajt|bajtova}}",
        "ncategories": "$1 {{PLURAL:$1|kategorija|kategorije}}",
        "linksearch-line": "$1 vodi sa $2",
        "linksearch-error": "Džokeri se mogu pojavljivati samo na početku adrese.",
        "listusersfrom": "Prikaži korisnike koji počinju sa:",
-       "listusers-submit": "Pokaži",
+       "listusers-submit": "Prikaži",
        "listusers-noresult": "Nije pronađen korisnik.",
        "listusers-blocked": "(blokiran)",
        "activeusers": "Spisak aktivnih korisnika",
index 144fcbe..241494e 100644 (file)
@@ -6,7 +6,8 @@
                        "Svetko",
                        "Wolliger Mensch",
                        "ОйЛ",
-                       "아라"
+                       "아라",
+                       "Илья Драконов"
                ]
        },
        "tog-oldsig": "нꙑнѣшьн҄ь аѵтографъ :",
        "minoreditletter": "м҃л",
        "newpageletter": "н҃в",
        "boteditletter": "а҃ѵ",
+       "rc_categories_any": "Любы из выбраных",
        "rc-change-size-new": "$1 {{PLURAL:$1|баитъ|баита|баитъ}} послѣди мѣнꙑ",
        "rc-old-title": "напрьва страница створѥна ꙗко ⁖ $1 ⁖",
        "recentchangeslinked": "съвѧꙁанꙑ страницѧ",
        "protectedarticle": "⁖ [[$1]] ⁖ ꙁабранѥна ѥстъ",
        "prot_1movedto2": "⁖ [[$1]] ⁖ нарєчєнъ ⁖ [[$2]] ⁖ ѥстъ",
        "protectcomment": "какъ съмꙑслъ :",
+       "protect-cascadeon": "Эта страница защищена от редактирования {{PLURAL:$1|page, which has|pages, which have}}.",
        "protect-level-sysop": "толико съмотритєлє",
        "protect-othertime": "ино врѣмѧ :",
        "protect-othertime-op": "ино врѣмѧ",
index 246070f..81a1bd2 100644 (file)
        "prefixindex": "Сăмах пуçламăшĕсен кăтартмăшĕ",
        "shortpages": "Кĕске статьясем",
        "longpages": "Вăрăм страницăсем",
-       "deadendpages": "Ниăçта та урăх ертмен страницăсем",
+       "deadendpages": "Нимĕнпе те çыхăнман страницăсем",
        "protectedpages": "Хӳтĕленĕ страницăсем",
        "protectedtitles": "Юраман ятсем",
        "listusers": "Хутшăнакансен списокĕ",
index 2d92b7d..7b26497 100644 (file)
        "boteditletter": "B",
        "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|beobachtender|beobachtende}} Benutzer]",
        "rc_categories": "Nur Seiten aus den Kategorien (getrennt mit „|“):",
-       "rc_categories_any": "Alle",
+       "rc_categories_any": "Beliebige der ausgewählten",
        "rc-change-size": "$1 {{PLURAL:$1|Byte|Bytes}}",
        "rc-change-size-new": "$1 {{PLURAL:$1|Byte|Bytes}} nach der Änderung",
        "newsectionsummary": "Neuer Abschnitt /* $1 */",
index 1a045c5..517b588 100644 (file)
        "mostrevisions": "Artículos con más ediciones",
        "prefixindex": "Todas las páginas con prefijo",
        "prefixindex-namespace": "Todas las páginas con el prefijo (espacio de nombres $1)",
-       "prefixindex-strip": "Prefijo de la hilera en la lista",
+       "prefixindex-strip": "Quitar prefijos en la lista",
        "shortpages": "Páginas cortas",
        "longpages": "Páginas largas",
        "deadendpages": "Páginas sin salida",
        "special-characters-title-endash": "semirraya",
        "special-characters-title-emdash": "raya",
        "special-characters-title-minus": "signo de resta",
+       "mw-widgets-dateinput-no-date": "Ninguna fecha seleccionada",
        "mw-widgets-titleinput-description-new-page": "la página aún no existe",
        "mw-widgets-titleinput-description-redirect": "redirigir a $1"
 }
index 5add3cc..19a7170 100644 (file)
        "throttled-mailpassword": "یک ایمیل بازنشانی گذرواژه در $1 {{PLURAL:$1|ساعت|ساعت}} گذشته فرستاده شده است.\nبرای جلوگیری از سوءاستفاده، هر $1 {{PLURAL:$1|ساعت|ساعت}} تنها یک ایمیل بازنشانی گذرواژه فرستاده می‌شود.",
        "mailerror": "خطا در ارسال ایمیل: $1",
        "acct_creation_throttle_hit": "بازدیدکنندگان این ویکی که از نشانی آی‌پی شما استفاده می‌کنند در روز گذشته {{PLURAL:$1|یک حساب کاربری|$1 حساب کاربری}} ساخته‌اند، که بیشترین تعداد مجاز در آن بازهٔ زمانی است.\nبه همین خاطر، بازدیدکنندگانی که از این نشانی آی‌پی استفاده می‌کنند نمی‌توانند در حال حاضر حساب جدیدی بسازند.",
-       "emailauthenticated": "آدرس ایمیل شما در $2 ساعت $3 تأیید شده است.",
+       "emailauthenticated": "نشانی ایمیل شما در $2 ساعت $3 تأیید شده است.",
        "emailnotauthenticated": "آدرس ایمیل شما هنوز تأیید نشده است.\nبرای هیچ‌یک از ویژگی‌های زیر، ایمیل ارسال نخواهد شد.",
        "noemailprefs": "برای راه‌اندازی این قابلیت‌ها یک آدرس ایمیل در ترجیحات خود مشخص کنید.",
-       "emailconfirmlink": "آدرس ایمیل خود را تأیید کنید",
+       "emailconfirmlink": "نشانی ایمیل خود را تأیید کنید",
        "invalidemailaddress": "آدرس ایمیل واردشدهٔ قابل قبول نیست، چرا که دارای ساختار نامعتبری است.\nلطفاً آدرسی با ساختار صحیح وارد کنید و یا بخش مربوط را خالی بگذارید.",
        "cannotchangeemail": "آدرس‌های ایمیل حساب کاربری در این ویکی قابل تغییر نیست.",
        "emaildisabled": "این وب سایت قادر به ارسال ایمیل نیست.",
        "hr_tip": "خط افقی (از آن کم استفاده کنید)",
        "summary": "خلاصه:",
        "subject": "موضوع/عنوان:",
-       "minoredit": "این ویرایش جزئی‌است",
+       "minoredit": "این ویرایشْ جزئی است",
        "watchthis": "پی‌گیری این صفحه",
        "savearticle": "صفحه ذخیره شود",
        "preview": "پیش‌نمایش",
        "exif-compression-3": "رمزگذاری نمابر سی‌سی‌آی‌تی‌تی گروه ۳",
        "exif-compression-4": "رمزگذاری نمابر سی‌سی‌آی‌تی‌تی گروه ۴",
        "exif-copyrighted-true": "دارای حق تکثیر",
-       "exif-copyrighted-false": "وضعیت حق‌تکثیر تعیین نشدهاست",
+       "exif-copyrighted-false": "وضعیت حق‌تکثیر تعیین نشده است",
        "exif-unknowndate": "تاریخ نامعلوم",
        "exif-orientation-1": "عادی",
        "exif-orientation-2": "افقی پشت و روشده",
        "exif-urgency-other": "اولویت تعریف شده توسط کاربر ($1)",
        "namespacesall": "همه",
        "monthsall": "همهٔ ماه‌ها",
-       "confirmemail": "تأیید آدرس ایمیل",
+       "confirmemail": "تأیید نشانی ایمیل",
        "confirmemail_noemail": "شما در صفحهٔ [[Special:Preferences|ترجیحات کاربری]] خود آدرس ایمیل معتبری وارد نکرده‌اید.",
        "confirmemail_text": "این ویکی، شما را ملزم به تأیید آدرس ایمیل خود، پیش از استفاده از خدمات ایمیل در اینجا می‌کند. دکمهٔ زیرین را فعال کنید تا ایمیلی تأییدی به آدرس ایمیل شما فرستاده شود. این ایمیل دربردارندهٔ پیوندی خواهد بود که حاوی یک کد است. پیوند را در مرورگر خود بار کنید کنید تا آدرس ایمیل شما تأیید شود.",
        "confirmemail_pending": "یک کد تأییدی پیشتر برای شما به صورت ایمیل فرستاده شده است. اگر همین اواخر حساب خود را باز کرده‌اید شاید بد نباشد که پیش از درخواست یک کد جدید چند دقیقه درنگ کنید تا شاید ایمیل قبلی برسد.",
        "confirmemail_invalid": "کد تأیید نامعتبر است. ممکن است که منقضی شده باشد.",
        "confirmemail_needlogin": "لطفاً برای تأیید آدرس ایمیلتان $1.",
        "confirmemail_success": "آدرس ایمیل شما تأیید شده‌است.\n\nاکنون می‌توانید [[Special:UserLogin|به سیستم وارد شوید]] و از ویکی لذت ببرید.",
-       "confirmemail_loggedin": "آدرس ایمیل شما تأیید شد.",
-       "confirmemail_subject": "تأیید آدرس ایمیل {{SITENAME}}",
+       "confirmemail_loggedin": "نشانی ایمیل شما تأیید شد.",
+       "confirmemail_subject": "تأیید نشانی ایمیل {{SITENAME}}",
        "confirmemail_body": "یک نفر، احتمالاً خود شما، از نشانی آی‌پی $1 حساب کاربری‌ای با نام «$2» و این آدرس ایمیل در {{SITENAME}} ایجاد کرده است.\n\nبرای تأیید این که این حساب واقعاً متعلق به شماست و نیز برای فعال سازی قابلیت ایمیل {{SITENAME}} پیوند زیر را در مرورگر اینترنت خود باز کنید:\n\n$3\n\nاگر شما این حساب کاربری را ثبت *نکرده‌اید*، لطفاً پیوند زیر را\nباز کنید تا تأیید آدرس ایمیل لغو شود:\n\n$5\n\nاین کدِ تأیید در تاریخ $4 منقضی خواهد شد.",
        "confirmemail_body_changed": "یک نفر، احتمالاً خود شما، از نشانی آی‌پی $1 آدرس ایمیل حساب «$2» در {{SITENAME}} را تغییر داده است.\n\nبرای تأیید این که این حساب واقعاً به شما تعلق دارد و فعال کردن دوبارهٔ قابلیت ایمیل در {{SITENAME}}، پیوند زیر را در مرورگرتان باز کنید:\n\n$3\n\nاگر این حساب متعلق به شما نیست، پیوند زیر را باز کنید تا تغییر آدرس ایمیل لغو شود:\n\n$5\n\nاین تأییدیه در $4 منقضی می‌گردد.",
        "confirmemail_body_set": "یک نفر، احتمالاً خود شما، از نشانی آی‌پی $1,\nآدرس ایمیل حساب «$2» در {{SITENAME}} را به این آدرس تغییر داده است.\n\nبرای تأیید این که این حساب واقعاً به شما تعلق دارد و فعال کردن دوبارهٔ قابلیت ایمیل در {{SITENAME}}، پیوند زیر را در مرورگرتان باز کنید:\n\n$3\n\nاگر این حساب متعلق به شما نیست، پیوند زیر را باز تا تغییر آدرس ایمیل، لغو شود:\n\n$5\n\nاین تأییدیه در $4 منقضی می‌گردد.",
-       "confirmemail_invalidated": "تأیید آدرس ایمیل لغو شد",
-       "invalidateemail": "لغو تأیید آدرس ایمیل",
+       "confirmemail_invalidated": "تأیید نشانی ایمیل لغو شد",
+       "invalidateemail": "لغو تأیید نشانی ایمیل",
        "scarytranscludedisabled": "[تراگنجانش بین‌ویکیانه فعال نیست]",
        "scarytranscludefailed": "[فراخوانی الگو برای $1 میسر نشد]",
        "scarytranscludefailed-httpstatus": "[فراخوانی الگو برای $1 میسر نشد: خطای اچ‌تی‌تی‌پی $2]",
index 06aad64..a7d08cc 100644 (file)
        "newpageletter": "ח",
        "boteditletter": "ב",
        "number_of_watching_users_pageview": "[{{PLURAL:$1|משתמש אחד עוקב|$1 משתמשים עוקבים}} אחרי הדף]",
-       "rc_categories": "×\94×\92×\91×\9c×\94 ×\9cק×\98×\92×\95ר×\99×\95ת (×\99ש ×\9c×\94פר×\99×\93 ×¢×\9d \"|\")",
-       "rc_categories_any": "×\94×\9b×\95×\9c",
+       "rc_categories": "×\94×\92×\91×\9c×\94 ×\9cק×\98×\92×\95ר×\99×\95ת (×\9e×\95פר×\93×\95×\93 ×\91ת×\95 \"|\"):",
+       "rc_categories_any": "×\9b×\9c ×\90×\97ת ×\9e×\94× ×\91×\97ר×\95ת",
        "rc-change-size-new": "{{PLURAL:$1|בית אחד|$1 בתים}} לאחר השינוי",
        "newsectionsummary": "/* $1 */ פסקה חדשה",
        "rc-enhanced-expand": "הצגת הפרטים",
index a90ae69..5b5c921 100644 (file)
        "saturday-at": "$1 (szombat)",
        "sunday-at": "$1 (vasárnap)",
        "yesterday-at": "Tegnap $1",
-       "bad_image_list": "A formátum a következő:\n\nCsak a listatételek (csillaggal * kezdődő tételek) vannak figyelembe véve. Egy sor első hivatkozásának egy rossz képre mutató hivatkozásnak kell lennie.\nUgyanazon sor további hivatkozásai kivételnek tekintettek, pl. a szócikkek, ahol a kép bennük fordulhat elő.",
+       "bad_image_list": "A formátum a következő:\n\nCsak a listatételek (csillaggal * kezdődő sorok) vannak figyelembe véve.\nEgy sor első hivatkozásának egy rossz képre mutató hivatkozásnak kell lennie.\nUgyanazon sor további hivatkozásai kivételnek tekintettek: szócikkek, amikben a kép előfordulhat.",
        "metadata": "Metaadatok",
        "metadata-help": "Ez a kép járulékos adatokat tartalmaz, amelyek feltehetően a kép létrehozásához használt digitális fényképezőgép vagy lapolvasó beállításairól adnak tájékoztatást.  Ha a képet az eredetihez képest módosították, ezen adatok eltérhetnek a kép tényleges jellemzőitől.",
        "metadata-expand": "További képadatok",
index a6cf564..7c88e3d 100644 (file)
        "tags-create-warnings-below": "Vole tu continuar a crear le etiquetta?",
        "tags-delete-title": "Deler etiquetta",
        "tags-delete-explanation-initial": "Tu es sur le puncto de deler le etiquetta \"$1\" del base de datos.",
+       "tags-delete-explanation-in-use": "Illo essera removite ab {{PLURAL:$2|$2 version o entrata de registro al qual|tote le $2 versiones e/o entratas de registro al quales}} illo es actualmente applicate.",
        "tags-delete-reason": "Motivo:",
        "comparepages": "Comparar paginas",
        "compare-page1": "Pagina 1",
index c5c1c3a..8f62a07 100644 (file)
        "boteditletter": "B",
        "unpatrolledletter": "!",
        "number_of_watching_users_pageview": "[{{PLURAL:$1|eine|$1|kein}} Oppasser]",
-       "rc_categories": "Nor de Saachjroppe (met „|“ dozwesche):",
-       "rc_categories_any": "All, wat mer han",
+       "rc_categories": "Bejränz op de Saachjroppe (schrihv „|“ dozwesche):",
+       "rc_categories_any": "Öhndseijne vun dä aanjejovve Saachjroppe",
        "rc-change-size": "$1 {{PLURAL:$1|Byte|Bytes}}",
        "rc-change-size-new": "$1 {{PLURAL:$1|Byte|Bytes|Bytes}} noh dem Ändere",
        "newsectionsummary": "Neu Avschnet /* $1 */",
        "trackingcategories-name": "Dä Nohreesch udder däm Täxschtöck singe Nahme",
        "trackingcategories-desc": "Bedengonge för enjeschloße ze sin",
        "noindex-category-desc": "Di Sigg sull vun de Wäbkrauler Robots un de Söhkmaschihne nit opjenumme wähde, weil dat Zauberwoot <code><nowiki>__NOINDEX__</nowiki></code> dren schteiht un se en enem Appachemang es, woh dat zohjelohße es.",
-       "index-category-desc": "Di Sigg sull vun de Wäbkrauler Robots un de Söhkmaschihne opjenumme wähde, weil dat Zauberwoot <code><nowiki>__INDEX__</nowiki></code> dren schteiht un se en enem Appachemang es, woh dat zohjelohße es, un wat nommahlerwies nit vun de Robots dorschsöhk weed.",
+       "index-category-desc": "Di Sigg sull vun de Wäbkrauler Robots un de Söhkmaschihne opjenumme wähde, weil dat Zauberwoot <code><nowiki>__INDEX__</nowiki></code> dren schteiht un se en enem Appachemang es, woh dat zohjelohße es, un wat nommahlerwihs nit vun de Robots dorschsöhk weed.",
        "post-expand-template-inclusion-category-desc": "Nohdämm a paa Schablohne enjesaz woode sen, hät di Sigg mieh Dahte wi <code xml:lang=\"en\" lang=\"en\">$wgMaxArticleSize</code> zohlöhß. Et sin nit alle Oprohve vun Schablohne opjelöhß.",
        "post-expand-template-argument-category-desc": "Di Sigg hät mieh Dahte wi <code xml:lang=\"en\" lang=\"en\">$wgMaxArticleSize</code> zohlöhß, nohdämm dä Wäät för ene Parramehter — jät met drei jeschweifte Klammere drömeröm, wi <code>{{{Dengenskersche}}}</code> — enjesaz woode es.",
        "expensive-parserfunction-category-desc": "Di Sigg hät zoh vill düüre Befähle met Pahserfonxjuhne, för e Beijschpell esu jät, wi <code xml:lang=\"en\" lang=\"en\">#ifexist</code>. Mih doh drövver schteihd em [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Handbohch].",
index d63b44b..ddf03c9 100644 (file)
        "tooltip-pt-mycontris": "Lîsteya beşdariyên min",
        "tooltip-pt-logout": "Derkeve",
        "tooltip-ca-talk": "Gotûbêj li ser rûpela naverokê",
-       "tooltip-ca-edit": "Vê rûpelê biguherîne! Berê qeydkirinê bişkoka \"Pêşdîtin\"",
+       "tooltip-ca-edit": "Vê rûpelê biguherîne",
        "tooltip-ca-addsection": "Beşekê zêde bike.",
        "tooltip-ca-viewsource": "Ev rûpel tê parastin.\nTu dikarî tenê li çavkaniyê binêrî.",
        "tooltip-ca-history": "Guhertoyên berê yên vê rûpelê",
        "tooltip-n-mainpage": "Here Destpêkê",
        "tooltip-n-mainpage-description": "Here Destpêkê",
        "tooltip-n-portal": "Agahdarî li ser {{SITENAME}}, tu dikarî çi bikî, tu dikarî çi li ku bîbînî",
+       "tooltip-n-currentevents": "Der barê bûyerên dawî de agahîyên nûjen bibîne",
        "tooltip-n-recentchanges": "Lîsteya guherandinên dawî di vê wîkiyê da",
        "tooltip-n-randompage": "Rûpeleka ketober bar bike",
        "tooltip-n-help": "Bersivên ji bo pirsên te.",
index f1bcf12..7784783 100644 (file)
        "newpageletter": "N",
        "boteditletter": "B",
        "number_of_watching_users_pageview": "[$1 Benotzer {{PLURAL:$1|iwwerwaacht|iwwerwaachen}}]",
-       "rc_categories": "Nëmme Säiten aus de Kategorien (getrennt mat \"|\"):",
-       "rc_categories_any": "All",
+       "rc_categories": "Limitéieren op d'Kategorie (getrennt mat \"|\"):",
+       "rc_categories_any": "Aus iergendenger vun den erausgesichten",
        "rc-change-size": "$1 {{PLURAL:$1|Byte|Bytes}}",
        "rc-change-size-new": "$1 {{PLURAL:$1|Byte|Bytes}} no der Ännerung",
        "newsectionsummary": "Neien Abschnitt /* $1 */",
index 5ce7682..6ddab68 100644 (file)
        "actionthrottled": "Veiksmas apribotas",
        "actionthrottledtext": "Kad būtų apsisaugota nuo reklamų, jums neleidžiama daug kartų atlikti šį veiksmą per trumpą laiko tarpą, bet jūs pasiekėte šį limitą. Prašome vėl pamėginti po kelių minučių.",
        "protectedpagetext": "Šis puslapis yra užrakintas, saugant jį nuo redagavimo.",
-       "viewsourcetext": "Jūs galite žiūrėti ir kopijuoti puslapio kodą:",
-       "viewyourtext": "Jūs galite matyti ir kopijuoti '''savo redagavimų''' tekstą į šį puslapį:",
+       "viewsourcetext": "Jūs galite peržiūrėti ir kopijuoti puslapio kodą:",
+       "viewyourtext": "Jūs galite peržiūrėti ir kopijuoti <strong>savo pakeitimų</strong> kodą į šį puslapį:",
        "protectedinterface": "Šiame puslapyje yra apsaugotas nuo piktnaudžiavimo programinės įrangos sąsajos tekstas. Norėdami pridėti ar pakeisti vertimus visose wiki, naudokite [//translatewiki.net/ translatewiki.net] MediaWiki vertimų projektą.",
        "editinginterface": "'''Dėmesio:''' Jūs redaguojate puslapį, kuris yra naudojamas programinės įrangos sąsajos tekste. Pakeitimai šiame puslapyje taip pat pakeis naudotojo sąsajos išvaizdą ir kitiems naudotojams šiame wiki.",
        "translateinterface": "Kad pridėtumėte vertimus visoms wiki, naudokitės  [//translatewiki.net/ translatewiki.net] – projektu, skirtu MediaWiki vertimams į vietines kalbas.",
        "newpageletter": "N",
        "boteditletter": "R",
        "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|stebintis naudotojas|stebintys naudotojai|stebinčių naudotojų}}]",
-       "rc_categories": "Rodyti tik šias kategorijas (atskirkite naudodami „|“)",
-       "rc_categories_any": "Bet kokia",
+       "rc_categories": "Riboti kategorijoms (atskirkite su „|“)",
+       "rc_categories_any": "Bet kuris iš pasirinktųjų",
        "rc-change-size-new": "$1 {{PLURAL:$1|baitas|baitai|baitų}} po pakeitimo",
        "newsectionsummary": "/* $1 */ naujas skyrius",
        "rc-enhanced-expand": "Rodyti detales",
        "special-characters-title-endash": "en brūkšnys",
        "special-characters-title-emdash": "em brūkšnys",
        "special-characters-title-minus": "minuso ženklas",
+       "mw-widgets-dateinput-no-date": "Nepasirinkta data",
        "mw-widgets-titleinput-description-new-page": "puslapis dar neegzistuoja",
        "mw-widgets-titleinput-description-redirect": "nukreipti į $1"
 }
index e5efedb..63d9878 100644 (file)
        "group-sysop": "koán-lí jîn-oân",
        "group-bureaucrat": "Koaⁿ-liâu",
        "group-bot-member": "{{GENDER:$1|Ke-khì-lâng}}",
-       "group-sysop-member": "{{GENDER:$1|goán-lí jîn-oân}}",
+       "group-sysop-member": "{{GENDER:$1|koán-lí jîn-oân}}",
        "group-bureaucrat-member": "{{GENDER:$1|Koaⁿ-liâu}}",
        "grouppage-sysop": "{{ns:project}}:Hêng-chèng jîn-oân",
        "grouppage-bureaucrat": "{{ns:project}}:Koaⁿ-liâu",
index b5d8e11..3437e41 100644 (file)
        "search-category": "(categorie $1)",
        "search-file-match": "(komt overeen met de inhoud van het bestand)",
        "search-suggest": "Bedoelde u: $1",
+       "search-rewritten": "Resultaten voor $1 getoond. Zoek in plaats daarvan naar $2.",
        "search-interwiki-caption": "Zusterprojecten",
        "search-interwiki-default": "Resultaten van $1:",
        "search-interwiki-more": "(meer)",
index abdf905..6701aed 100644 (file)
        "watchlisttools-raw": "Editar a lista de páginas vigiadas em forma de texto",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|discussão]])",
        "duplicate-defaultsort": "<strong>Aviso:</strong> A chave de ordenação padrão \"$2\" sobrepõe-se à anterior \"$1\".",
-       "duplicate-displaytitle": "<strong>Aviso:</strong> Exibir título \"$2\" substituindo o título anteriormente em exibição \"$1\".",
+       "duplicate-displaytitle": "<strong>Aviso:</strong> O título em exibição \"$2\" anula o título anteriormente em exibição \"$1\".",
        "invalid-indicator-name": "<strong>Erro:</strong> O atributo <code>name</code>, da página de estados, não deve estar em branco.",
        "version": "Versão",
        "version-extensions": "Extensões instaladas",
index 53f5828..865f3b8 100644 (file)
        "unpatrolledletter": "{{optional}}\n\nUsed in {{msg-mw|Recentchanges-label-legend}}, meaning \"unpatrolled\".",
        "number_of_watching_users_RCview": "{{notranslate}}\nParameters:\n* $1 - number of users who are watching",
        "number_of_watching_users_pageview": "Used if <code>$wgPageShowWatchingUsers</code> is true.\n* $1 - number of watching user(s)",
-       "rc_categories": "Probably to do with 'recent changes' special page, either in a particular skin, or for a particular user group.\n\nI guess that this should appear before an input box where you can specify that recent changes should be shown for pages belonging to certain categories only. You name the categories in the input box, and separate them by a pipe character. If this is right, then you should be able to use 'restrict' instead of 'limit', or even 'show pages in the following categories only'.",
-       "rc_categories_any": "Used in the CategoryFilter form on [[Special:RecentChanges]], if <code>$wgAllowCategorizedRecentChanges</code> is true.\n{{Identical|Any}}",
+       "rc_categories": "A label of an input box. Appears on Special:RecentChanges if filtering recent changes by category is enable (that is, $wgAllowCategorizedRecentChanges is set to true).",
+       "rc_categories_any": "Appears ''after'' the input box the label of which is {{msg-mw|rc_categories}}, which appears on [[Special:RecentChanges]], if <code>$wgAllowCategorizedRecentChanges</code> is true. \"Chosen\" refers to categories.",
        "rc-change-size": "{{optional}}\nDoes not work under $wgMiserMode ([[mwr:48986|r48986]]).\n\nParameters:\n* $1 - size of diff",
        "rc-change-size-new": "Tooltip when hovering a change list diff size. Parameters:\n* $1 - the resulting new size (in bytes)",
        "newsectionsummary": "Default summary when adding a new section to a page. Parameters:\n* $1 - section title",
        "sunday-at": "Phrase for indicating that something occurred at a particular time on the most recent Sunday.\n\nParameters:\n* $1 - the time (localized)\n{{Related|Day-at}}",
        "today-at": "Phrase for indicating that something occurred at a particular time today.\n\nParameters:\n* $1 - the time (localized)\n{{Related|Day-at}}",
        "yesterday-at": "Phrase for indicating that something occurred at a particular time yesterday.\n\nParameters:\n* $1 - the time (localized)\n{{Related|Day-at}}",
-       "bad_image_list": "箇条信息只出现在引导管理员用正确个格式加链接。弗会徕Mediawiki别荡处出现。",
+       "bad_image_list": "This message only appears to guide administrators to add links with the right format. This will not appear anywhere else in MediaWiki.",
        "variantname-zh-hans": "{{Optional}}\n\nVariant option for wikis with variants conversion enabled.",
        "variantname-zh-hant": "{{Optional}}\n\nVariant option for wikis with variants conversion enabled.",
        "variantname-zh-cn": "{{Optional}}\n\nVariant option for wikis with variants conversion enabled.",
index 2d35fdc..f80d0a7 100644 (file)
        "unpatrolledletter": "!",
        "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|utende|utinde}} ca condrollene]",
        "rc_categories": "Limite de le categorije (separate cu \"|\")",
-       "rc_categories_any": "Tutte",
+       "rc_categories_any": "Qualsiasi de le scacchiate",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|byte}} apprisse 'u cangiamende",
        "newsectionsummary": "/* $1 */ seziona nove",
index f99519f..f611256 100644 (file)
        "newpageletter": "N",
        "boteditletter": "b",
        "number_of_watching_users_pageview": "[temo {{PLURAL:$1|spremlja|spremljata|spremljajo|spremlja|spremlja}} $1 {{PLURAL:$1|uporabnik|uporabnika|uporabniki|uporabnikov|uporabnikov}}]",
-       "rc_categories": "Omejitev na kategorije (ločite jih z »|«)",
-       "rc_categories_any": "Katerokoli",
+       "rc_categories": "Omejitev na kategorije (ločite jih z »|«):",
+       "rc_categories_any": "Katera koli od izbranih",
        "rc-change-size-new": "po spremembi: $1 {{PLURAL:$1|zlog|zloga|zlogi|zlogov}}",
        "newsectionsummary": "/* $1 */ nov razdelek",
        "rc-enhanced-expand": "Pokaži podrobnosti",
index 427e459..0cd1692 100644 (file)
        "stub-threshold": "Праг за обликовање <a href=\"#\" class=\"stub\">везе као клице</a> (у бајтовима):",
        "stub-threshold-disabled": "Онемогућено",
        "recentchangesdays": "Број дана у скорашњим изменама:",
-       "recentchangesdays-max": "(највише $1 {{PLURAL:$1|дан|дана|дана}})",
+       "recentchangesdays-max": "Највише $1 {{PLURAL:$1|дан|дана}}",
        "recentchangescount": "Број измена за приказ:",
        "prefs-help-recentchangescount": "Подразумева скорашње измене, историје страница и дневнике.",
        "prefs-help-watchlist-token2": "Ово је тајни кључ за веб довод вашег списка надгледања.\nСвако ко зна овај кључ биће у могућности да види ваша надгледања стога немојте га одавати никоме.\nАко је потребно можете га [[Special:ResetTokens|ресетовати]].",
index 14a169c..3c225e5 100644 (file)
        "content-model-text": "čist tekst",
        "content-model-javascript": "javaskript",
        "content-model-css": "CSS",
+       "duplicate-args-warning": "<strong>Upozorenje:</strong> [[:$1]] poziva [[:$2]] sa više vrednosti za parametar „$3“. Samo poslednja navedena vrednost će biti korišćena.",
        "expensive-parserfunction-warning": "'''Upozorenje:''' ova stranica sadrži previše poziva za raščlanjivanje.\n\nTrebalo bi da ima manje od $2 {{PLURAL:$2|poziv|poziva|poziva}}, a sada ima $1.",
        "expensive-parserfunction-category": "Stranice s previše poziva za raščlanjivanje",
        "post-expand-template-inclusion-warning": "'''Upozorenje:''' veličina uključenog šablona je prevelika.\nNeki šabloni neće biti uključeni.",
        "search-category": "(kategorija $1)",
        "search-file-match": "(podudara se sadržaj datoteke)",
        "search-suggest": "Da li ste mislili na: $1",
+       "search-rewritten": "Prikazani rezultati za $1. Ipak pretraži $2.",
        "search-interwiki-caption": "Bratski projekti",
        "search-interwiki-default": "Rezultati sa $1:",
        "search-interwiki-more": "(više)",
        "stub-threshold": "Prag za oblikovanje <a href=\"#\" class=\"stub\">veze kao klice</a> (u bajtovima):",
        "stub-threshold-disabled": "Onemogućeno",
        "recentchangesdays": "Broj dana u skorašnjim izmenama:",
-       "recentchangesdays-max": "(najviše $1 {{PLURAL:$1|dan|dana|dana}})",
+       "recentchangesdays-max": "Najviše $1 {{PLURAL:$1|dan|dana}}",
        "recentchangescount": "Broj izmena za prikaz:",
        "prefs-help-recentchangescount": "Podrazumeva skorašnje izmene, istorije stranica i dnevnike.",
        "prefs-help-watchlist-token2": "Ovo je tajni ključ za veb dovod vašeg spiska nadgledanja.\nSvako ko zna ovaj ključ biće u mogućnosti da vidi vaša nadgledanja stoga nemojte ga odavati nikome.\nAko je potrebno možete ga [[Special:ResetTokens|resetovati]].",
        "htmlform-cloner-create": "Dodaj još",
        "htmlform-cloner-delete": "Ukloni",
        "htmlform-cloner-required": "Bar jedna vrednost je potrebna.",
+       "htmlform-user-not-exists": "<strong>$1</strong> ne postoji.",
+       "htmlform-user-not-valid": "<strong>$1</strong> nije ispravno korisničko ime.",
        "sqlite-has-fts": "$1 s podrškom pretrage celog teksta",
        "sqlite-no-fts": "$1 bez podrške pretrage celog teksta",
        "logentry-delete-delete": "$1 je {{GENDER:$2|obrisao|obrisala}} stranicu $3",
index 7d33886..3daefe5 100644 (file)
@@ -95,7 +95,7 @@
        "tog-watchlisthideminor": "Приховати незначні редагування у списку спостереження",
        "tog-watchlisthideliu": "Приховати редагування зареєстрованих дописувачів у списку спостереження",
        "tog-watchlisthideanons": "Приховати редагування анонімних користувачів у списку спостереження",
-       "tog-watchlisthidepatrolled": "Приховати відпатрульовані правки у списку спостереження",
+       "tog-watchlisthidepatrolled": "Приховати відпатрульовані редагування у списку спостереження",
        "tog-ccmeonemails": "Надсилати мені копії листів, які я надсилаю іншим користувачам",
        "tog-diffonly": "Не показувати вміст сторінки під різницею версій",
        "tog-showhiddencats": "Показувати приховані категорії",
        "showpreview": "Попередній перегляд",
        "showdiff": "Показати зміни",
        "blankarticle": "'''Попередження:''' Створена вами сторінка порожня.\nЯкщо Ви знову натиснете «{{int:savearticle}}», сторінку буде створено без вмісту.",
-       "anoneditwarning": "<strong>Увага!</strong> Ð\92и Ð½Ðµ Ð°Ð²Ñ\82оÑ\80изÑ\83валиÑ\81Ñ\8f Ð½Ð° Ñ\81айÑ\82Ñ\96. Ð\92аÑ\88а IP-адÑ\80еÑ\81а Ð±Ñ\83де Ð¿Ñ\83блÑ\96Ñ\87но Ð²Ð¸Ð´Ð¸Ð¼Ð°, Ñ\8fкÑ\89о Ð²Ð¸ Ð±Ñ\83деÑ\82е Ð²Ð½Ð¾Ñ\81иÑ\82и Ð±Ñ\83дÑ\8c\8fкÑ\96 Ð¿Ñ\80авки. Ð¯ÐºÑ\89о Ð²Ð¸ <strong>[$1 Ñ\83вÑ\96йдеÑ\82е]</strong> Ð°Ð±Ð¾ <strong>[$2 Ñ\81Ñ\82воÑ\80иÑ\82е Ð¾Ð±Ð»Ñ\96ковий Ð·Ð°Ð¿Ð¸Ñ\81]</strong>, Ð¿Ñ\80авки Ð·Ð°Ð¼Ñ\96Ñ\81Ñ\82Ñ\8c Ñ\86Ñ\8cого Ð±Ñ\83дÑ\83Ñ\82Ñ\8c Ð¿Ð¾Ð²'Ñ\8fзанÑ\96 Ð· Ð²Ð°Ñ\88им Ñ\96м'Ñ\8fм ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а, Ð° Ñ\82акож Ñ\83 Ð²ас з'являться інші переваги.",
+       "anoneditwarning": "<strong>Увага!</strong> Ð\92и Ð½Ðµ Ð°Ð²Ñ\82оÑ\80изÑ\83валиÑ\81Ñ\8f Ð½Ð° Ñ\81айÑ\82Ñ\96. Ð\92аÑ\88а IP-адÑ\80еÑ\81а Ð±Ñ\83де Ð¿Ñ\83блÑ\96Ñ\87но Ð²Ð¸Ð´Ð¸Ð¼Ð°, Ñ\8fкÑ\89о Ð\92и Ð±Ñ\83деÑ\82е Ð²Ð½Ð¾Ñ\81иÑ\82и Ð±Ñ\83дÑ\8c\8fкÑ\96 Ñ\80едагÑ\83ваннÑ\8f. Ð¯ÐºÑ\89о Ð\92и <strong>[$1 Ñ\83вÑ\96йдеÑ\82е]</strong> Ð°Ð±Ð¾ <strong>[$2 Ñ\81Ñ\82воÑ\80иÑ\82е Ð¾Ð±Ð»Ñ\96ковий Ð·Ð°Ð¿Ð¸Ñ\81]</strong>, Ñ\80едагÑ\83ваннÑ\8f Ð±Ñ\83дÑ\83Ñ\82Ñ\8c Ð½Ð°Ñ\82омÑ\96Ñ\81Ñ\82Ñ\8c Ð¿Ð¾Ð²'Ñ\8fзанÑ\96 Ð· Ð\92аÑ\88им Ñ\96менем ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а, Ð° Ñ\89е Ñ\83 Ð\92ас з'являться інші переваги.",
        "anonpreviewwarning": "''Ви не увійшли в систему. Якщо ви виконаєте збереження, то в історію сторінки буде записана ваша IP-адреса.''",
        "missingsummary": "'''Нагадування''': Ви не дали короткого опису змін.\nНатиснувши кнопку «Зберегти» ще раз, ви збережете зміни без коментаря.",
        "selfredirect": "<strong>Попередження:</strong> Ви створюєте перенаправлення на цю ж сторінку.\nВи могли вказати невірну цільову сторінку, або ж редагуєте хибну сторінку.\nЯкщо Ви натиснете \"{{int:savearticle}}\" ще раз, перенаправлення буде створено.",
        "session_fail_preview": "'''Система не може зберегти ваші редагування, оскільки втрачені дані сеансу. Будь ласка, повторіть вашу спробу.\nЯкщо помилка буде повторюватись, спробуйте [[Special:UserLogout|вийти з системи]] і увійти знову.'''",
        "session_fail_preview_html": "<strong>Вибачте! Неможливо зберегти ваші зміни через втрату даних HTML-сесії.</strong>\n\n''Оскільки {{SITENAME}} дозволяє використовувати чистий HTML, попередній перегляд відключено, щоб попередити JavaScript-атаки.''\n\n<strong>Якщо це легітимна спроба редагування, будь ласка, спробуйте ще раз. Якщо не вийде знову, — спробуйте [[Special:UserLogout|завершити сеанс роботи]] й ще раз ввійти до системи.</strong>",
        "token_suffix_mismatch": "'''Ваше редагування було відхилене, оскільки ваша програма неправильно обробляє знаки пунктуації у вікні редагування. Редагування було скасоване для запобігання спотворенню тексту статті.\nПодібні проблеми можуть виникати при використанні анонімізуючих веб-проксі, що містять помилки.'''",
-       "edit_form_incomplete": "'''Частина даних із форми редагування не досягла сервера. Уважно перевірте, чи не пошкоджені ваші правки і спробуйте ще раз.'''",
+       "edit_form_incomplete": "<strong>Частина даних із форми редагування не досягла сервера. Уважно перевірте, чи не пошкоджені Ваші редагування і спробуйте ще раз.</strong>",
        "editing": "Редагування $1",
        "creating": "Створення $1",
        "editingsection": "Редагування $1 (розділ)",
        "undo-norev": "Редагування не може бути скасоване, бо його не існує або було вилучено.",
        "undo-nochange": "Схоже, редагування вже було скасовано.",
        "undo-summary": "Скасування редагування № $1 користувача [[Special:Contribs/$2|$2]] ([[User talk:$2|обговорення]])",
-       "undo-summary-username-hidden": "СкаÑ\81Ñ\83ваÑ\82и Ð¿Ñ\80авкÑ\83 $1, виконану прихованим користувачем",
+       "undo-summary-username-hidden": "СкаÑ\81Ñ\83ваÑ\82и Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\8e $1, виконану прихованим користувачем",
        "cantcreateaccounttitle": "Неможливо створити обліковий запис",
        "cantcreateaccount-text": "Створення облікових записів із цієї IP-адреси ('''$1''') було заблоковане [[User:$3|користувачем $3]].\n\n$3 зазначив таку причину: ''$2''",
        "cantcreateaccount-range-text": "Створення облікового запису із IP-адрес у діапазоні  '''$1''', який включає вашу IP-адресу ('''$4'''), було заблоковано користувачем [[User:$3|$3]].\n\nКористувач $3 вказав як причину ''$2''",
        "revdelete-selected-text": "{{PLURAL:$1|Вибрана редакція|Вибрані редакції}} із [[:$2]]:",
        "revdelete-selected-file": "{{PLURAL:$1|Вибрана версія файлу|Вибрані версії файлу}} із [[:$2]]:",
        "logdelete-selected": "{{PLURAL:$1|1=Обраний запис|Обрані записи}} журналу:",
-       "revdelete-text-text": "Видалені версії будуть як і раніше, показані в історії сторінки, але частини їх вмісту будуть недоступні для учасників.",
-       "revdelete-text-file": "Видалені версії файлу будуть як і раніше видно в історії сторінки, але їх частини вмісту будуть доступні для учасників.",
-       "logdelete-text": "Видалені події в журналі будуть як і раніше видно в журналах, але частини їх вмісту будуть недоступні для учасників.",
+       "revdelete-text-text": "Видалені версії будуть як і раніше, показані в історії сторінки, але частини їх вмісту будуть недоступні для загалу.",
+       "revdelete-text-file": "Видалені версії файлу будуть як і раніше видно в історії сторінки, але їх частини вмісту будуть доступні для загалу.",
+       "logdelete-text": "Видалені події в журналі будуть як і раніше видно в журналах, але частини їх вмісту будуть недоступні для загалу.",
        "revdelete-text-others": "Інші адміністратори, як і раніше, будуть мати можливість доступу до прихованого вмісту і зможуть відновити його, якщо не встановлено додаткові обмеження.",
        "revdelete-confirm": "Будь ласка, підтвердіть, що ви справді бажаєте це здійснити, що усвідомлюєте наслідки та робите це згідно з [[{{MediaWiki:Policy-url}}|правилами]].",
        "revdelete-suppress-text": "Приховування може відбуватися '''лише''' в таких випадках:\n* Потенційно наклепницькі відомості\n* Недоречна особиста інформація\n*: ''домашні адреси, номери телефонів, номер паспорта тощо.''",
        "showhideselectedversions": "Показати/приховати обрані версії",
        "editundo": "скасувати",
        "diff-empty": "(Немає відмінностей)",
-       "diff-multi-sameuser": "(не {{PLURAL:$1|показано Ð¾Ð´Ð½Ñ\83 Ð¿Ñ\80омÑ\96жнÑ\83 Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\8e|показанÑ\96 $1 Ð¿Ñ\80омÑ\96жнÑ\96 Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\97|показано $1 Ð¿Ñ\80омÑ\96жниÑ\85 Ð²ÐµÑ\80Ñ\81Ñ\96й}} Ñ\86Ñ\8cого Ñ\83Ñ\87аÑ\81ника)",
-       "diff-multi-otherusers": "(не {{PLURAL:$1|показана $1 Ð¿Ñ\80омÑ\96жна Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\8f|показано $1 Ð¿Ñ\80омÑ\96жнÑ\96 Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\97|показанÑ\96 $1 Ð¿Ñ\80омÑ\96жниÑ\85 Ð²ÐµÑ\80Ñ\81Ñ\96й}} {{PLURAL:$2|Ñ\89е Ð¾Ð´Ð½Ð¾Ð³Ð¾ Ñ\83Ñ\87аÑ\81ника|$2 Ñ\83Ñ\87аÑ\81ників}})",
+       "diff-multi-sameuser": "(Ð\9dе {{PLURAL:$1|показано Ð¾Ð´Ð½Ñ\83 Ð¿Ñ\80омÑ\96жнÑ\83 Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\8e|показанÑ\96 $1 Ð¿Ñ\80омÑ\96жнÑ\96 Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\97|показано $1 Ð¿Ñ\80омÑ\96жниÑ\85 Ð²ÐµÑ\80Ñ\81Ñ\96й}} Ñ\86Ñ\8cого ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а)",
+       "diff-multi-otherusers": "(Ð\9dе {{PLURAL:$1|показана $1 Ð¿Ñ\80омÑ\96жна Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\8f|показано $1 Ð¿Ñ\80омÑ\96жнÑ\96 Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\97|показанÑ\96 $1 Ð¿Ñ\80омÑ\96жниÑ\85 Ð²ÐµÑ\80Ñ\81Ñ\96й}} {{PLURAL:$2|Ñ\89е Ð¾Ð´Ð½Ð¾Ð³Ð¾ ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а|$2 ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87ів}})",
        "diff-multi-manyusers": "({{PLURAL:$1|не показана $1 проміжна версія|не показані $1 проміжні версії|не показано $1 проміжних версій}}, зроблених більш, ніж {{PLURAL:$2|1=$1 користувачем|$2 користувачами}})",
        "difference-missing-revision": "{{PLURAL:$2|$2 версія|$2 версії|$2 версій}} для цього порівняння ($1) не {{PLURAL:$2|1=знайдена|знайдені}}.\n\nІмовірно, ви перейшли за застарілим посиланням на порівняння версій вилученої сторінки.\nПодробиці можна дізнатися з [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журналу вилучень].",
        "searchresults": "Результати пошуку",
        "boteditletter": "б",
        "unpatrolledletter": "!",
        "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|користувач спостерігає|користувачі спостерігають|користувачів спостерігають}}]",
-       "rc_categories": "ТÑ\96лÑ\8cки Ð· ÐºÐ°Ñ\82егоÑ\80Ñ\96й (Ñ\80аздÑ\96лÑ\8eваÑ\87 Â«|»)",
-       "rc_categories_any": "Ð\91Ñ\83дÑ\8c\8fкий",
+       "rc_categories": "ТÑ\96лÑ\8cки Ð· ÐºÐ°Ñ\82егоÑ\80Ñ\96й (Ñ\80оздÑ\96лÑ\8eваÑ\87 Â«|»):",
+       "rc_categories_any": "Ð\91Ñ\83дÑ\8c\8fка Ð· Ð¾Ð±Ñ\80аниÑ\85",
        "rc-change-size": "$1",
        "rc-change-size-new": "Розмір після зміни: $1 {{PLURAL:$1|байт|байти|байтів}}",
        "newsectionsummary": "/* $1 */ нова тема",
        "listgrouprights-removegroup-self-all": "може вилучати всі групи зі свого облікового запису",
        "listgrouprights-namespaceprotection-header": "Обмеження простору назв",
        "listgrouprights-namespaceprotection-namespace": "Простір назв",
-       "listgrouprights-namespaceprotection-restrictedto": "Права, що дозволяють учаснику редагувати",
+       "listgrouprights-namespaceprotection-restrictedto": "Права, що дозволяють користувачу редагувати",
        "trackingcategories": "Відстежувані категорії",
        "trackingcategories-summary": "На цій сторінці перераховані відстежують категорії, які заповнюються автоматично програмним забезпеченням MediaWiki. Їх можна перейменувати, змінивши відповідні системні повідомлення в просторі назв {{ns:8}}.",
        "trackingcategories-msg": "Відстежувана категорія",
        "import-error-special": "Сторінку «$1» не було імпортовано, оскільки вона належить до особливого простору назв, що не дозволяє створення сторінок.",
        "import-error-invalid": "Сторінку «$1» не було імпортовано, оскільки назва, у яку вона імпортується, неприпустима у цій вікі.",
        "import-error-unserialize": "Версія $2 сторінки «$1» не може бути деструктурованою (десеріалізованою). Отримано повідомлення, що у цій версії використано модель $3 сериалізована як $4.",
-       "import-error-bad-location": "Ð\9fÑ\80авка $2, що використовує модель вмісту $3, не може бути збережена у «$1» цієї вікі, тому що ця модель не підтримується на цій сторінці.",
+       "import-error-bad-location": "Ð\92еÑ\80Ñ\81Ñ\96Ñ\8f $2, що використовує модель вмісту $3, не може бути збережена у «$1» цієї вікі, тому що ця модель не підтримується на цій сторінці.",
        "import-options-wrong": "{{PLURAL:$2|1=Неправильна опція|Неправильні опції}}: <nowiki>$1</nowiki>",
        "import-rootpage-invalid": "Вказана некоректна назва кореневої сторінки",
        "import-rootpage-nosubpage": "В просторі назв вказаної кореневої сторінки «$1» заборонені підсторінки",
        "pageinfo-firstuser": "Створив сторінку",
        "pageinfo-firsttime": "Дата створення сторінки",
        "pageinfo-lastuser": "Останній редактор",
-       "pageinfo-lasttime": "Дата останньої правки",
+       "pageinfo-lasttime": "Дата останнього редагування",
        "pageinfo-edits": "Загальна кількість редагувань",
        "pageinfo-authors": "Загальна кількість унікальних авторів",
        "pageinfo-recent-edits": "Кількість поточних редагувань в історії (протягом $1)",
        "special-characters-title-endash": "коротке тире",
        "special-characters-title-emdash": "довге тире",
        "special-characters-title-minus": "мінус",
+       "mw-widgets-dateinput-no-date": "Дати не вибрано",
        "mw-widgets-titleinput-description-new-page": "сторінка ще не існує",
        "mw-widgets-titleinput-description-redirect": "перенаправлення на $1"
 }
index 50ba34d..2006ec4 100644 (file)
        "newpageletter": "新",
        "boteditletter": "机",
        "number_of_watching_users_pageview": "[$1个关注用户]",
-       "rc_categories": "分类限制(用“|”分隔)",
-       "rc_categories_any": "任",
+       "rc_categories": "分类限制(用“|”分隔)",
+       "rc_categories_any": "任何选择的",
        "rc-change-size-new": "更改后有$1字节",
        "newsectionsummary": "/* $1 */ 新段落",
        "rc-enhanced-expand": "显示细节",
index da5bcf1..3fad66e 100644 (file)
@@ -1669,14 +1669,6 @@ return array(
 
        /* MediaWiki Legacy */
 
-       'mediawiki.legacy.ajax' => array(
-               'scripts' => 'resources/src/mediawiki.legacy/ajax.js',
-               'dependencies' => array(
-                       'mediawiki.util',
-                       'mediawiki.legacy.wikibits',
-               ),
-               'position' => 'top',
-       ),
        'mediawiki.legacy.commonPrint' => array(
                'position' => 'top',
                'styles' => array(
diff --git a/resources/src/mediawiki.legacy/ajax.js b/resources/src/mediawiki.legacy/ajax.js
deleted file mode 100644 (file)
index 3660c20..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/**
- * Remote Scripting Library
- * Copyright 2005 modernmethod, inc
- * Under the open source BSD license
- * http://www.modernmethod.com/sajax/
- */
-
-/*jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
-/*global alert */
-( function ( mw ) {
-
-       /**
-        * if sajax_debug_mode is true, this function outputs given the message into
-        * the element with id = sajax_debug; if no such element exists in the document,
-        * it is injected.
-        */
-       function debug( text ) {
-               if ( !window.sajax_debug_mode ) {
-                       return false;
-               }
-
-               var b, m,
-                       e = document.getElementById( 'sajax_debug' );
-
-               if ( !e ) {
-                       e = document.createElement( 'p' );
-                       e.className = 'sajax_debug';
-                       e.id = 'sajax_debug';
-
-                       b = document.getElementsByTagName( 'body' )[0];
-
-                       if ( b.firstChild ) {
-                               b.insertBefore( e, b.firstChild );
-                       } else {
-                               b.appendChild( e );
-                       }
-               }
-
-               m = document.createElement( 'div' );
-               m.appendChild( document.createTextNode( text ) );
-
-               e.appendChild( m );
-
-               return true;
-       }
-
-       /**
-        * Compatibility wrapper for creating a new XMLHttpRequest object.
-        */
-       function createXhr() {
-               debug( 'sajax_init_object() called..' );
-               var a;
-               try {
-                       // Try the new style before ActiveX so we don't
-                       // unnecessarily trigger warnings in IE 7 when
-                       // set to prompt about ActiveX usage
-                       a = new XMLHttpRequest();
-               } catch ( xhrE ) {
-                       try {
-                               a = new window.ActiveXObject( 'Msxml2.XMLHTTP' );
-                       } catch ( msXmlE ) {
-                               try {
-                                       a = new window.ActiveXObject( 'Microsoft.XMLHTTP' );
-                               } catch ( msXhrE ) {
-                                       a = null;
-                               }
-                       }
-               }
-               if ( !a ) {
-                       debug( 'Could not create connection object.' );
-               }
-
-               return a;
-       }
-
-       /**
-        * Perform an AJAX call to MediaWiki. Calls are handled by AjaxDispatcher.php
-        *   func_name - the name of the function to call. Must be registered in $wgAjaxExportList
-        *   args - an array of arguments to that function
-        *   target - the target that will handle the result of the call. If this is a function,
-        *            if will be called with the XMLHttpRequest as a parameter; if it's an input
-        *            element, its value will be set to the resultText; if it's another type of
-        *            element, its innerHTML will be set to the resultText.
-        *
-        * Example:
-        *    sajax_do_call( 'doFoo', [1, 2, 3], document.getElementById( 'showFoo' ) );
-        *
-        * This will call the doFoo function via MediaWiki's AjaxDispatcher, with
-        * (1, 2, 3) as the parameter list, and will show the result in the element
-        * with id = showFoo
-        */
-       function doAjaxRequest( func_name, args, target ) {
-               var i, x, uri, post_data;
-               uri = mw.util.wikiScript() + '?action=ajax';
-               if ( window.sajax_request_type === 'GET' ) {
-                       if ( uri.indexOf( '?' ) === -1 ) {
-                               uri = uri + '?rs=' + encodeURIComponent( func_name );
-                       } else {
-                               uri = uri + '&rs=' + encodeURIComponent( func_name );
-                       }
-                       for ( i = 0; i < args.length; i++ ) {
-                               uri = uri + '&rsargs[]=' + encodeURIComponent( args[i] );
-                       }
-                       // uri = uri + '&rsrnd=' + new Date().getTime();
-                       post_data = null;
-               } else {
-                       post_data = 'rs=' + encodeURIComponent( func_name );
-                       for ( i = 0; i < args.length; i++ ) {
-                               post_data = post_data + '&rsargs[]=' + encodeURIComponent( args[i] );
-                       }
-               }
-               x = createXhr();
-               if ( !x ) {
-                       alert( 'AJAX not supported' );
-                       return false;
-               }
-
-               try {
-                       x.open( window.sajax_request_type, uri, true );
-               } catch ( e ) {
-                       if ( location.hostname === 'localhost' ) {
-                               alert( 'Your browser blocks XMLHttpRequest to "localhost", try using a real hostname for development/testing.' );
-                       }
-                       throw e;
-               }
-               if ( window.sajax_request_type === 'POST' ) {
-                       x.setRequestHeader( 'Method', 'POST ' + uri + ' HTTP/1.1' );
-                       x.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
-               }
-               x.setRequestHeader( 'Pragma', 'cache=yes' );
-               x.setRequestHeader( 'Cache-Control', 'no-transform' );
-               x.onreadystatechange = function () {
-                       if ( x.readyState !== 4 ) {
-                               return;
-                       }
-
-                       debug( 'received (' + x.status + ' ' + x.statusText + ') ' + x.responseText );
-
-                       // if ( x.status != 200 )
-                       //   alert( 'Error: ' + x.status + ' ' + x.statusText + ': ' + x.responseText );
-                       // else
-
-                       if ( typeof target === 'function' ) {
-                               target( x );
-                       } else if ( typeof target === 'object' ) {
-                               if ( target.tagName === 'INPUT' ) {
-                                       if ( x.status === 200 ) {
-                                               target.value = x.responseText;
-                                       }
-                                       // else alert( 'Error: ' + x.status + ' ' + x.statusText + ' (' + x.responseText + ')' );
-                               } else {
-                                       if ( x.status === 200 ) {
-                                               target.innerHTML = x.responseText;
-                                       } else {
-                                               target.innerHTML = '<div class="error">Error: ' + x.status +
-                                                       ' ' + x.statusText + ' (' + x.responseText + ')</div>';
-                                       }
-                               }
-                       } else {
-                               alert( 'Bad target for sajax_do_call: not a function or object: ' + target );
-                       }
-               };
-
-               debug( func_name + ' uri = ' + uri + ' / post = ' + post_data );
-               x.send( post_data );
-               debug( func_name + ' waiting..' );
-
-               return true;
-       }
-
-       /**
-        * @return {boolean} Whether the browser supports AJAX
-        */
-       function wfSupportsAjax() {
-               var request = createXhr(),
-                       supportsAjax = request ? true : false;
-
-               request = undefined;
-               return supportsAjax;
-       }
-
-       // Expose + Mark as deprecated
-       var deprecationNotice = 'Sajax is deprecated, use jQuery.ajax or mediawiki.api instead.';
-
-       // Variables
-       mw.log.deprecate( window, 'sajax_debug_mode', false, deprecationNotice );
-       mw.log.deprecate( window, 'sajax_request_type', 'GET', deprecationNotice );
-       // Methods
-       mw.log.deprecate( window, 'sajax_debug', debug, deprecationNotice );
-       mw.log.deprecate( window, 'sajax_init_object', createXhr, deprecationNotice );
-       mw.log.deprecate( window, 'sajax_do_call', doAjaxRequest, deprecationNotice );
-       mw.log.deprecate( window, 'wfSupportsAjax', wfSupportsAjax, deprecationNotice );
-
-}( mediaWiki ) );
index cc72e16..3da1d14 100644 (file)
@@ -17,7 +17,7 @@
                        var $spinner, href, rcid, apiRequest;
 
                        // Start preloading the notification module (normally loaded by mw.notify())
-                       mw.loader.load( ['mediawiki.notification'], null, true );
+                       mw.loader.load( 'mediawiki.notification' );
 
                        // Hide the link and create a spinner to show it inside the brackets.
                        $spinner = $.createSpinner( {
index ddd4f0c..708dcb5 100644 (file)
@@ -1,12 +1,11 @@
 ( function ( mw, $ ) {
 
-       mw.page = {};
+       // Support: MediaWiki < 1.26
+       // Cached HTML will not yet have this from OutputPage::getHeadScripts.
+       document.documentElement.className = document.documentElement.className
+               .replace( /(^|\s)client-nojs(\s|$)/, '$1client-js$2' );
 
-       // Client profile classes for <html>
-       // Allows for easy hiding/showing of JS or no-JS-specific UI elements
-       $( document.documentElement )
-               .addClass( 'client-js' )
-               .removeClass( 'client-nojs' );
+       mw.page = {};
 
        $( function () {
                mw.util.init();
index 50f280a..cc1ffb7 100644 (file)
                        var action, api, $link;
 
                        // Start preloading the notification module (normally loaded by mw.notify())
-                       mw.loader.load( ['mediawiki.notification'], null, true );
+                       mw.loader.load( 'mediawiki.notification' );
 
                        action = mwUriGetAction( this.href );
 
index 9016e89..f1a08a3 100644 (file)
@@ -10,6 +10,8 @@
        /**
         * Creates an mw.widgets.CalendarWidget object.
         *
+        * You will most likely want to use mw.widgets.DateInputWidget instead of CalendarWidget directly.
+        *
         * @class
         * @extends OO.ui.Widget
         * @mixins OO.ui.mixin.TabIndexedElement
@@ -17,8 +19,9 @@
         * @constructor
         * @param {Object} [config] Configuration options
         * @cfg {string} [precision='day'] Date precision to use, 'day' or 'month'
-        * @cfg {string|null} [date=null] Day or month date (depending on `precision`), in the
-        *     format 'YYYY-MM-DD' or 'YYYY-MM'. When null, defaults to current date.
+        * @cfg {string|null} [date=null] Day or month date (depending on `precision`), in the format
+        *     'YYYY-MM-DD' or 'YYYY-MM'. When null, the calendar will show today's date, but not select
+        *     it.
         */
        mw.widgets.CalendarWidget = function MWWCalendarWidget( config ) {
                // Config initialization
 
                if (
                        this.displayLayer === this.previousDisplayLayer &&
+                       this.date === this.previousDate &&
                        this.previousMoment &&
                        this.previousMoment.isSame( this.moment, this.precision === 'month' ? 'month' : 'day' )
                ) {
 
                this.previousMoment = moment( this.moment );
                this.previousDisplayLayer = this.displayLayer;
+               this.previousDate = this.date;
 
                this.$body.on( 'click', this.onBodyClick.bind( this ) );
        };
         * Set the date.
         *
         * @param {string|null} [date=null] Day or month date, in the format 'YYYY-MM-DD' or 'YYYY-MM'.
-        *     When null, defaults to current date. When invalid, the date is not changed.
+        *     When null, the calendar will show today's date, but not select it. When invalid, the date
+        *     is not changed.
         */
        mw.widgets.CalendarWidget.prototype.setDate = function ( date ) {
                var mom = date !== null ? moment( date, this.getDateFormat() ) : moment();
                if ( mom.isValid() ) {
                        this.moment = mom;
-                       this.setDateFromMoment();
+                       if ( date !== null ) {
+                               this.setDateFromMoment();
+                       } else if ( this.date !== null ) {
+                               this.date = null;
+                               this.emit( 'change', this.date );
+                       }
                        this.displayLayer = this.getDisplayLayers()[ 0 ];
                        this.updateUI();
                }
         * Get current date, in the format 'YYYY-MM-DD' or 'YYYY-MM', depending on precision. Digits will
         * not be localised.
         *
-        * @returns {string} Date string
+        * @returns {string|null} Date string
         */
        mw.widgets.CalendarWidget.prototype.getDate = function () {
                return this.date;
index 582a316..21a9019 100644 (file)
 }
 
 .mw-widget-calendarWidget-day-today {
-       border: 1px solid #3787fb;
+       box-shadow: inset 0 0 0 1px #3787fb;
        border-radius: ((@calendarHeight / 7) / 2);
-       margin: -1px;
 }
 
 .mw-widget-calendarWidget-item-selected {
        &.mw-widget-calendarWidget-day-heading {
                border-radius: ((@calendarHeight / 7) / 4);
                // Hide the border from .mw-widget-calendarWidget-day-today
-               border: 0;
-               margin: 0;
+               box-shadow: none;
        }
 
        &.mw-widget-calendarWidget-month {
index 3888fc7..9771e02 100644 (file)
        /**
         * Creates an mw.widgets.DateInputWidget object.
         *
+        *     @example
+        *     // Date input widget showcase
+        *     var fieldset = new OO.ui.FieldsetLayout( {
+        *       items: [
+        *         new OO.ui.FieldLayout(
+        *           new mw.widgets.DateInputWidget(),
+        *           {
+        *             align: 'top',
+        *             label: 'Select date'
+        *           }
+        *         ),
+        *         new OO.ui.FieldLayout(
+        *           new mw.widgets.DateInputWidget( { precision: 'month' } ),
+        *           {
+        *             align: 'top',
+        *             label: 'Select month'
+        *           }
+        *         ),
+        *         new OO.ui.FieldLayout(
+        *           new mw.widgets.DateInputWidget( {
+        *             inputFormat: 'DD.MM.YYYY',
+        *             displayFormat: 'Do [of] MMMM [anno Domini] YYYY'
+        *           } ),
+        *           {
+        *             align: 'top',
+        *             label: 'Select date (custom formats)'
+        *           }
+        *         )
+        *       ]
+        *     } );
+        *     $( 'body' ).append( fieldset.$element );
+        *
+        * The value is stored in 'YYYY-MM-DD' or 'YYYY-MM' format:
+        *
+        *     @example
+        *     // Accessing values in a date input widget
+        *     var dateInput = new mw.widgets.DateInputWidget();
+        *     var $label = $( '<p>' );
+        *     $( 'body' ).append( $label, dateInput.$element );
+        *     dateInput.on( 'change', function () {
+        *       // The value will always be a valid date or empty string, malformed input is ignored
+        *       var date = dateInput.getValue();
+        *       $label.text( 'Selected date: ' + ( date || '(none)' ) );
+        *     } );
+        *
         * @class
         * @extends OO.ui.InputWidget
         *
         * @private
         */
        mw.widgets.DateInputWidget.prototype.activate = function () {
-               if ( this.getValue() === '' ) {
-                       // Setting today's date is probably more helpful than leaving the widget empty? We could just
-                       // display the placeholder and leave it there, but it's likely that at least the year will be
-                       // the same as today's.
-
-                       // Use English locale to avoid number formatting
-                       this.setValue( moment().locale( 'en' ).format( this.getInternalFormat() ) );
-               }
-
                this.$element.addClass( 'mw-widget-dateInputWidget-active' );
                this.handle.toggle( false );
                this.textInput.toggle( true );
index f87869c..1feb8f0 100644 (file)
@@ -59,6 +59,7 @@
                border: 1px solid #ccc;
                border-radius: 0.1em;
                line-height: 1.275em;
+               background-color: white;
        }
 
        > .oo-ui-textInputWidget input {
index 7825f22..3c5a5f5 100644 (file)
                        }
 
                        /**
-                        * Adds a script tag to the DOM, either using document.write or low-level DOM manipulation,
-                        * depending on whether document-ready has occurred yet and whether we are in async mode.
+                        * Load and execute a script with callback.
                         *
                         * @private
                         * @param {string} src URL to script, will be used as the src attribute in the script tag
                         * @param {Function} [callback] Callback which will be run when the script is done
-                        * @param {boolean} [async=false] Whether to load modules asynchronously.
-                        *  Ignored (and defaulted to `true`) if the document-ready event has already occurred.
                         */
-                       function addScript( src, callback, async ) {
-                               // Using isReady directly instead of storing it locally from a $().ready callback (bug 31895)
-                               if ( $.isReady || async ) {
-                                       $.ajax( {
-                                               url: src,
-                                               dataType: 'script',
-                                               // Force jQuery behaviour to be for crossDomain. Otherwise jQuery would use
-                                               // XHR for a same domain request instead of <script>, which changes the request
-                                               // headers (potentially missing a cache hit), and reduces caching in general
-                                               // since browsers cache XHR much less (if at all). And XHR means we retreive
-                                               // text, so we'd need to $.globalEval, which then messes up line numbers.
-                                               crossDomain: true,
-                                               cache: true,
-                                               async: true
-                                       } ).always( callback );
-                               } else {
-                                       /*jshint evil:true */
-                                       document.write( mw.html.element( 'script', { 'src': src }, '' ) );
-                                       if ( callback ) {
-                                               // Document.write is synchronous, so this is called when it's done.
-                                               // FIXME: That's a lie. doc.write isn't actually synchronous.
-                                               callback();
-                                       }
-                               }
+                       function addScript( src, callback ) {
+                               $.ajax( {
+                                       url: src,
+                                       dataType: 'script',
+                                       // Force jQuery behaviour to be for crossDomain. Otherwise jQuery would use
+                                       // XHR for a same domain request instead of <script>, which changes the request
+                                       // headers (potentially missing a cache hit), and reduces caching in general
+                                       // since browsers cache XHR much less (if at all). And XHR means we retreive
+                                       // text, so we'd need to $.globalEval, which then messes up line numbers.
+                                       crossDomain: true,
+                                       cache: true
+                               } ).always( callback );
                        }
 
                        /**
                                                        registry[module].state = 'ready';
                                                        handlePending( module );
                                                };
-                                               nestedAddScript = function ( arr, callback, async, i ) {
+                                               nestedAddScript = function ( arr, callback, i ) {
                                                        // Recursively call addScript() in its own callback
                                                        // for each element of arr.
                                                        if ( i >= arr.length ) {
                                                        }
 
                                                        addScript( arr[i], function () {
-                                                               nestedAddScript( arr, callback, async, i + 1 );
-                                                       }, async );
+                                                               nestedAddScript( arr, callback, i + 1 );
+                                                       } );
                                                };
 
                                                if ( $.isArray( script ) ) {
-                                                       nestedAddScript( script, markModuleReady, registry[module].async, 0 );
+                                                       nestedAddScript( script, markModuleReady, 0 );
                                                } else if ( $.isFunction( script ) ) {
                                                        // Pass jQuery twice so that the signature of the closure which wraps
                                                        // the script can bind both '$' and 'jQuery'.
                                        mw.templates.set( module, registry[module].templates );
                                }
 
-                               if ( $.isReady || registry[module].async ) {
-                                       // Make sure we don't run the scripts until all (potentially asynchronous)
-                                       // stylesheet insertions have completed.
-                                       ( function () {
-                                               var pending = 0;
-                                               checkCssHandles = function () {
-                                                       // cssHandlesRegistered ensures we don't take off too soon, e.g. when
-                                                       // one of the cssHandles is fired while we're still creating more handles.
-                                                       if ( cssHandlesRegistered && pending === 0 && runScript ) {
-                                                               runScript();
-                                                               runScript = undefined; // Revoke
+                               // Make sure we don't run the scripts until all stylesheet insertions have completed.
+                               ( function () {
+                                       var pending = 0;
+                                       checkCssHandles = function () {
+                                               // cssHandlesRegistered ensures we don't take off too soon, e.g. when
+                                               // one of the cssHandles is fired while we're still creating more handles.
+                                               if ( cssHandlesRegistered && pending === 0 && runScript ) {
+                                                       runScript();
+                                                       runScript = undefined; // Revoke
+                                               }
+                                       };
+                                       cssHandle = function () {
+                                               var check = checkCssHandles;
+                                               pending++;
+                                               return function () {
+                                                       if ( check ) {
+                                                               pending--;
+                                                               check();
+                                                               check = undefined; // Revoke
                                                        }
                                                };
-                                               cssHandle = function () {
-                                                       var check = checkCssHandles;
-                                                       pending++;
-                                                       return function () {
-                                                               if ( check ) {
-                                                                       pending--;
-                                                                       check();
-                                                                       check = undefined; // Revoke
-                                                               }
-                                                       };
-                                               };
-                                       }() );
-                               } else {
-                                       // We are in blocking mode, and so we can't afford to wait for CSS
-                                       cssHandle = function () {};
-                                       // Run immediately
-                                       checkCssHandles = runScript;
-                               }
+                                       };
+                               }() );
 
                                // Process styles (see also mw.loader.implement)
                                // * back-compat: { <media>: css }
                         * @param {string|string[]} dependencies Module name or array of string module names
                         * @param {Function} [ready] Callback to execute when all dependencies are ready
                         * @param {Function} [error] Callback to execute when any dependency fails
-                        * @param {boolean} [async=false] Whether to load modules asynchronously.
-                        *  Ignored (and defaulted to `true`) if the document-ready event has already occurred.
                         */
-                       function request( dependencies, ready, error, async ) {
+                       function request( dependencies, ready, error ) {
                                // Allow calling by single module name
                                if ( typeof dependencies === 'string' ) {
                                        dependencies = [dependencies];
                                                        return;
                                                }
                                                queue.push( module );
-                                               if ( async ) {
-                                                       registry[module].async = true;
-                                               }
                                        }
                                } );
 
                        }
 
                        /**
-                        * Asynchronously append a script tag to the end of the body
-                        * that invokes load.php
+                        * Load modules from load.php
                         * @private
                         * @param {Object} moduleMap Module map, see #buildModulesString
                         * @param {Object} currReqBase Object with other parameters (other than 'modules') to use in the request
                         * @param {string} sourceLoadScript URL of load.php
-                        * @param {boolean} async Whether to load modules asynchronously.
-                        *  Ignored (and defaulted to `true`) if the document-ready event has already occurred.
                         */
-                       function doRequest( moduleMap, currReqBase, sourceLoadScript, async ) {
+                       function doRequest( moduleMap, currReqBase, sourceLoadScript ) {
                                var request = $.extend(
                                        { modules: buildModulesString( moduleMap ) },
                                        currReqBase
                                );
                                request = sortQuery( request );
                                // Support: IE6
-                               // Append &* to satisfy load.php's WebRequest::checkUrlExtension test. This script
-                               // isn't actually used in IE6, but MediaWiki enforces it in general.
-                               addScript( sourceLoadScript + '?' + $.param( request ) + '&*', null, async );
+                               // Append &* to satisfy load.php's WebRequest::checkUrlExtension test.
+                               // This script isn't actually used in IE6, but MediaWiki enforces it in general.
+                               addScript( sourceLoadScript + '?' + $.param( request ) + '&*' );
                        }
 
                        /**
                                        var     reqBase, splits, maxQueryLength, q, b, bSource, bGroup, bSourceGroup,
                                                source, concatSource, origBatch, group, i, modules, sourceLoadScript,
                                                currReqBase, currReqBaseLength, moduleMap, l,
-                                               lastDotIndex, prefix, suffix, bytesAdded, async;
+                                               lastDotIndex, prefix, suffix, bytesAdded;
 
                                        // Build a list of request parameters common to all requests.
                                        reqBase = {
                                                                currReqBase.user = mw.config.get( 'wgUserName' );
                                                        }
                                                        currReqBaseLength = $.param( currReqBase ).length;
-                                                       async = true;
                                                        // We may need to split up the request to honor the query string length limit,
                                                        // so build it piece by piece.
                                                        l = currReqBaseLength + 9; // '&modules='.length == 9
                                                                if ( maxQueryLength > 0 && !$.isEmptyObject( moduleMap ) && l + bytesAdded > maxQueryLength ) {
                                                                        // This request would become too long, create a new one
                                                                        // and fire off the old one
-                                                                       doRequest( moduleMap, currReqBase, sourceLoadScript, async );
+                                                                       doRequest( moduleMap, currReqBase, sourceLoadScript );
                                                                        moduleMap = {};
-                                                                       async = true;
                                                                        l = currReqBaseLength + 9;
                                                                        mw.track( 'resourceloader.splitRequest', { maxQueryLength: maxQueryLength } );
                                                                }
                                                                        moduleMap[prefix] = [];
                                                                }
                                                                moduleMap[prefix].push( suffix );
-                                                               if ( !registry[modules[i]].async ) {
-                                                                       // If this module is blocking, make the entire request blocking
-                                                                       // This is slightly suboptimal, but in practice mixing of blocking
-                                                                       // and async modules will only occur in debug mode.
-                                                                       async = false;
-                                                               }
                                                                l += bytesAdded;
                                                        }
                                                        // If there's anything left in moduleMap, request that too
                                                        if ( !$.isEmptyObject( moduleMap ) ) {
-                                                               doRequest( moduleMap, currReqBase, sourceLoadScript, async );
+                                                               doRequest( moduleMap, currReqBase, sourceLoadScript );
                                                        }
                                                }
                                        }
                                 * @param {string} [type='text/javascript'] MIME type to use if calling with a URL of an
                                 *  external script or style; acceptable values are "text/css" and
                                 *  "text/javascript"; if no type is provided, text/javascript is assumed.
-                                * @param {boolean} [async] Whether to load modules asynchronously.
-                                *  Ignored (and defaulted to `true`) if the document-ready event has already occurred.
-                                *  Defaults to `true` if loading a URL, `false` otherwise.
                                 */
-                               load: function ( modules, type, async ) {
+                               load: function ( modules, type ) {
                                        var filtered, l;
 
                                        // Validate input
                                        // Allow calling with an external url or single dependency as a string
                                        if ( typeof modules === 'string' ) {
                                                if ( /^(https?:)?\/\//.test( modules ) ) {
-                                                       if ( async === undefined ) {
-                                                               // Assume async for bug 34542
-                                                               async = true;
-                                                       }
                                                        if ( type === 'text/css' ) {
                                                                // Support: IE 7-8
                                                                // Use properties instead of attributes as IE throws security
                                                                return;
                                                        }
                                                        if ( type === 'text/javascript' || type === undefined ) {
-                                                               addScript( modules, null, async );
+                                                               addScript( modules );
                                                                return;
                                                        }
                                                        // Unknown type
                                                return;
                                        }
                                        // Since some modules are not yet ready, queue up a request.
-                                       request( filtered, undefined, undefined, async );
+                                       request( filtered, undefined, undefined );
                                },
 
                                /**
index 1332459..d4cfa02 100644 (file)
@@ -76,6 +76,10 @@ function startUp() {
 
        $CODE.registrations();
 
+       mw.config.set( $VARS.configuration );
+
+       // Must be after mw.config.set because these callbacks may use mw.loader which
+       // needs to have values 'skin', 'debug' etc. from mw.config.
        window.RLQ = window.RLQ || [];
        while ( RLQ.length ) {
                RLQ.shift()();
@@ -85,11 +89,18 @@ function startUp() {
                        fn();
                }
        };
-
-       mw.config.set( $VARS.configuration );
 }
 
 // Conditional script injection
 if ( isCompatible() ) {
-       document.write( $VARS.baseModulesScript );
+       ( function () {
+               var script = document.createElement( 'script' );
+               script.src = $VARS.baseModulesUri;
+               document.getElementsByTagName( 'head' )[0].appendChild( script );
+       }() );
+} else {
+       // Undo class swapping in case of an unsupported browser.
+       // See OutputPage::getHeadScripts().
+       document.documentElement.className = document.documentElement.className
+               .replace( /(^|\s)client-js(\s|$)/, '$1client-nojs$2' );
 }
index ab33d89..b9ff013 100644 (file)
@@ -160,6 +160,22 @@ Template:table_attribs_5
 |</noinclude>style="color:red;"||Bar
 !! endarticle
 
+!! article
+Template:table_attribs_6
+!! text
+style="background: <nowiki>
+
+
+red;</nowiki>" |
+!! endarticle
+
+!! article
+Template:table_attribs_7
+!! text
+<noinclude>
+|</noinclude>style{{=}}"background:&#35;f9f9f9;"|Foo<ref>foo</ref>
+!! endarticle
+
 !! article
 Template:table_header_cells
 !! text
@@ -1314,7 +1330,7 @@ Non-word characters don't terminate tag names + tidy
 Non-word characters are valid in extension tags (T19663)
 !! wikitext
 <tåg>tåg</tåg>
-!! html
+!! html/php
 <pre>
 'tåg'
 array (
@@ -1325,11 +1341,15 @@ array (
 
 !! test
 Isolated close tags should be treated as literal text (bug 52760)
+!! options
+parsoid=wt2html
 !! wikitext
 </b>
 
 <s.foo>s</s>
-!! html+tidy
+!! html/php+tidy
+<p>&lt;s.foo&gt;s</p>
+!! html/parsoid
 <p>&lt;s.foo&gt;s</p>
 !! end
 
@@ -1363,9 +1383,11 @@ Bare pipe character from a template (bug 52363)
 <nowiki> unordered list
 !! wikitext
 <nowiki>* This is not an unordered list item.</nowiki>
-!! html
+!! html/php
 <p>* This is not an unordered list item.
 </p>
+!! html/parsoid
+<p><span typeof="mw:Nowiki">* This is not an unordered list item.</span></p>
 !! end
 
 !! test
@@ -1378,7 +1400,7 @@ sed abit.
 
 :and a colon
 </nowiki>
-!! html
+!! html/php
 <p>Lorem ipsum dolor
 
 sed abit.
@@ -1387,6 +1409,14 @@ sed abit.
 :and a colon
 
 </p>
+!! html/parsoid
+<p><span typeof="mw:Nowiki">Lorem ipsum dolor
+
+sed abit.
+  sed nullum.
+
+:and a colon
+</span></p>
 !! end
 
 !! test
@@ -1400,7 +1430,7 @@ nowiki 3
 
 *There is not nowiki.
 *There is <nowiki>nowiki</nowiki>.
-!! html
+!! html/php
 <dl><dd>There is not nowiki.</dd>
 <dd>There is nowiki.</dd></dl>
 <ol><li>There is not nowiki.</li>
@@ -1408,6 +1438,15 @@ nowiki 3
 <ul><li>There is not nowiki.</li>
 <li>There is nowiki.</li></ul>
 
+!! html/parsoid
+<dl><dd data-parsoid='{}'>There is not nowiki.</dd>
+<dd data-parsoid='{}'>There is <span typeof="mw:Nowiki">nowiki</span>.</dd></dl>
+
+<ol><li data-parsoid='{}'>There is not nowiki.</li>
+<li data-parsoid='{}'>There is <span typeof="mw:Nowiki">nowiki</span>.</li></ol>
+
+<ul><li data-parsoid='{}'>There is not nowiki.</li>
+<li data-parsoid='{}'>There is <span typeof="mw:Nowiki">nowiki</span>.</li></ul>
 !! end
 
 !! test
@@ -1436,7 +1475,7 @@ parsoid=html2wt
 !! html
 <p>* &lt;/nowiki&gt; tag</p>
 !! wikitext
-<nowiki>* &lt;/nowiki&gt;</nowiki> tag
+<nowiki>*</nowiki> <nowiki>&lt;/nowiki&gt;</nowiki> tag
 !! end
 
 !! test
@@ -2223,7 +2262,7 @@ Entities inside <pre>
 </nowiki>
 </pre>
 
-!! html
+!! html/php
 <pre>
 &lt;nowiki&gt;
 </pre>
@@ -2236,6 +2275,18 @@ Entities inside <pre>
 
 &lt;/pre&gt;
 </p>
+!! html/parsoid
+<pre data-parsoid='{"stx":"html","strippedNL":true}'>&lt;nowiki>
+</pre>
+<p><span typeof="mw:Placeholder" data-parsoid='{"src":"&lt;/nowiki>"}'>&lt;/nowiki></span>
+&lt;/pre></p>
+
+<p><span typeof="mw:Nowiki">
+&lt;pre>
+&lt;nowiki>
+&lt;/pre>
+</span>
+&lt;/pre></p>
 !! end
 
 !! test
@@ -3397,7 +3448,7 @@ HTML-pre: 3: other wikitext
 '' no-italic ''
 [[ NoLink ]]
 </pre>
-!! html
+!! html/php
 <pre>
 * foo
 # bar
@@ -3406,6 +3457,13 @@ HTML-pre: 3: other wikitext
 [[ NoLink ]]
 </pre>
 
+!! html/parsoid
+<pre data-parsoid='{"stx":"html","strippedNL":true}'>* foo
+# bar
+= no-h =
+'' no-italic ''
+[[ NoLink ]]
+</pre>
 !!end
 
 ###
@@ -4236,6 +4294,17 @@ Definition Lists: colons occurring in tags
 </dl>
 </dd>
 </dl>
+!! html/parsoid
+<dl><dt>a</dt><dd data-parsoid='{"stx":"row"}'>b</dd>
+<dt><b>a:b</b></dt>
+<dt><i data-parsoid='{"stx":"html"}'>a:b</i></dt>
+<dt><span data-parsoid='{"stx":"html"}'>a:b</span></dt>
+<dt><div data-parsoid='{"stx":"html"}'>a:b</div></dt>
+<dt><div data-parsoid='{"stx":"html","autoInsertedEnd":true}'>a</div></dt>
+<dd>b</dd>
+<dt><span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a:b"}},"i":0}}]}'>a:b</span></dt>
+<dt><i about="#mwt2" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&#39;&#39;a:b&#39;&#39;"}},"i":0}}]}'>a:b</i>
+<dl><dt><dl><dt><i>a:b</i></dt></dl></dt></dl></dt></dl>
 !! end
 
 !! test
@@ -6163,6 +6232,21 @@ Indented table markup mixed with indented pre content (proposed in bug 6200)
 </tbody></table>
 !! end
 
+## Edge case fix to prevent future regressions
+!! test
+T107652: <ref>s in templates that also generate table cell attributes should be rendered properly
+!! wikitext
+{|
+|{{table_attribs_7}}
+|}
+<references />
+!! html/parsoid
+<table>
+<tbody><tr><td style="background:#f9f9f9;" typeof="mw:Transclusion" about="#mwt1" data-mw='{"parts":["|",{"template":{"target":{"wt":"table_attribs_7","href":"./Template:Table_attribs_7"},"params":{},"i":0}}]}'>Foo<span class="mw-ref" id="cite_ref-1" rel="dc:references" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1" style="counter-reset: mw-Ref 1;"><span class="mw-reflink-text">[1]</span></a></span></td></tr>
+</tbody></table>
+<ol class="mw-references" typeof="mw:Extension/references" about="#mwt5" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><a href="#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text" data-parsoid="{}">foo</span></li></ol>
+!! end
+
 !! test
 Table with row followed by newlines and table heading
 !! wikitext
@@ -8273,8 +8357,8 @@ Handling html with a br self-closing tag
 <br title=bar/>
 <br title=bar/ >
 !! html/php
-<p><br title="title" />
-<br title="title" />
+<p><br title="" />
+<br title="" />
 <br />
 <br title="bar" />
 <br title="bar" />
@@ -9632,6 +9716,15 @@ __NOEDITSECTION__
 <meta property="mw:PageProp/noeditsection" data-parsoid='{"magicSrc":"__NOEDITSECTION__"}'/>
 !! end
 
+!!test
+__proto__ is treated as normal wikitext (T105997)
+!!wikitext
+__proto__
+!!html
+<p>__proto__
+</p>
+!!end
+
 ###
 ### Magic links
 ###
@@ -10216,7 +10309,7 @@ File:Foobar.jpg
 msgnw keyword
 !! wikitext
 {{msgnw:MSGNW test}}
-!! html
+!! html/php
 <p>&#39;&#39;None&#39;&#39; of &#39;&#39;&#39;this&#39;&#39;&#39; should be 
 &#42; interpreted
 &#32;but rather passed unmodified
@@ -11004,6 +11097,25 @@ Templates: Support for templates generating attributes and content
 </tbody></table>
 !! end
 
+# T107622
+!! test
+4. Entities and nowikis inside templated attributes should be handled correctly inside templated tables
+!! wikitext
+{|
+| {{table_attribs_6}} hi
+|}
+!! html/php
+<table>
+<tr>
+<td style="background: red;"> hi
+</td></tr></table>
+
+!! html/parsoid
+<table>
+<tbody><tr><td style="background:  red;" typeof="mw:Transclusion" about="#mwt1" data-parsoid='{"autoInsertedEnd":true,"pi":[[]]}' data-mw='{"parts":["| ",{"template":{"target":{"wt":"table_attribs_6","href":"./Template:Table_attribs_6"},"params":{},"i":0}}," hi"]}'> hi</td></tr>
+</tbody></table>
+!! end
+
 !!test
 Templates: HTML Tables: 1. Generating start of a HTML table
 !! wikitext
@@ -11468,41 +11580,40 @@ Parser Functions: 2. Nested use (only outermost should be marked up)
 !! test
 pre-save transform: subst:
 !! options
-PST
+pst
 !! wikitext
 {{subst:test}}
-!! html
+!! html/php
 This is a test template
 !! end
 
 !! test
 pre-save transform: normal template
 !! options
-PST
+pst
 !! wikitext
 {{test}}
-!! html
+!! html/php
 {{test}}
 !! end
 
 !! test
 pre-save transform: nonexistent template
 !! options
-PST
+pst
 !! wikitext
 {{thistemplatedoesnotexist}}
-!! html
+!! html/php
 {{thistemplatedoesnotexist}}
 !! end
 
-
 !! test
 pre-save transform: subst magic variables
 !! options
-PST
+pst
 !! wikitext
 {{subst:SITENAME}}
-!! html
+!! html/php
 MediaWiki
 !! end
 
@@ -11513,7 +11624,7 @@ pre-save transform: subst: templates with parameters
 pst
 !! wikitext
 {{subst:paramtest|param="something else"}}
-!! html
+!! html/php
 This is a test template with parameter "something else"
 !! end
 
@@ -11529,11 +11640,10 @@ pre-save transform: nowiki in subst (bug 1188)
 pst
 !! wikitext
 {{subst:nowikitest}}
-!! html
+!! html/php
 <nowiki>'''not wiki'''</nowiki>
 !! end
 
-
 !! article
 Template:commenttest
 !! text
@@ -11546,7 +11656,7 @@ pre-save transform: comment in subst (bug 1936)
 pst
 !! wikitext
 {{subst:commenttest}}
-!! html
+!! html/php
 This template has <!-- a comment --> in it.
 !! end
 
@@ -11556,7 +11666,7 @@ pre-save transform: unclosed tag
 pst noxml
 !! wikitext
 <nowiki>'''not wiki'''
-!! html
+!! html/php
 <nowiki>'''not wiki'''
 !! end
 
@@ -11566,7 +11676,7 @@ pre-save transform: mixed tag case
 pst noxml
 !! wikitext
 <NOwiki>'''not wiki'''</noWIKI>
-!! html
+!! html/php
 <NOwiki>'''not wiki'''</noWIKI>
 !! end
 
@@ -11576,7 +11686,7 @@ pre-save transform: unclosed comment in <nowiki>
 pst noxml
 !! wikitext
 wiki<nowiki>nowiki<!--nowiki</nowiki>wiki
-!! html
+!! html/php
 wiki<nowiki>nowiki<!--nowiki</nowiki>wiki
 !!end
 
@@ -11604,7 +11714,7 @@ pre-save transform: comment containing gallery (bug 5024)
 pst
 !! wikitext
 <!-- <gallery>data</gallery> -->
-!! html
+!! html/php
 <!-- <gallery>data</gallery> -->
 !!end
 
@@ -11614,7 +11724,7 @@ pre-save transform: comment containing extension
 pst
 !! wikitext
 <!-- <tag>data</tag> -->
-!! html
+!! html/php
 <!-- <tag>data</tag> -->
 !!end
 
@@ -11624,7 +11734,7 @@ pre-save transform: comment containing nowiki
 pst
 !! wikitext
 <!-- <nowiki>data</nowiki> -->
-!! html
+!! html/php
 <!-- <nowiki>data</nowiki> -->
 !!end
 
@@ -11634,7 +11744,7 @@ pre-save transform: <noinclude> in subst (bug 3298)
 pst
 !! wikitext
 {{subst:Includes}}
-!! html
+!! html/php
 Foobar
 !! end
 
@@ -11644,7 +11754,7 @@ pre-save transform: <onlyinclude> in subst (bug 3298)
 pst
 !! wikitext
 {{subst:Includes2}}
-!! html
+!! html/php
 Foo
 !! end
 
@@ -11666,7 +11776,7 @@ bug 22297: safesubst: works during PST
 pst
 !! wikitext
 {{subst:SafeSubstTest}}{{safesubst:SubstTest}}
-!! html
+!! html/php
 FoobarFoobar
 !! end
 
@@ -11702,7 +11812,7 @@ pst
 [[|Article (context)]]
 [[Bar:X (Y) Z|]]
 [[:Bar:X (Y) Z|]]
-!! html
+!! html/php
 [[Article (context)|Article]]
 [[Bar:Article|Article]]
 [[:Bar:Article|Article]]
@@ -11723,7 +11833,7 @@ pst
 [[:interwiki:Article|]]
 [[interwiki:Bar:Article|]]
 [[:interwiki:Bar:Article|]]
-!! html
+!! html/php
 [[interwiki:Article|Article]]
 [[:interwiki:Article|Article]]
 [[interwiki:Bar:Article|Bar:Article]]
@@ -11736,7 +11846,7 @@ pre-save transform: context links ("pipe trick") with parens in title
 pst title=[[Somearticle (context)]]
 !! wikitext
 [[|Article]]
-!! html
+!! html/php
 [[Article (context)|Article]]
 !! end
 
@@ -11748,7 +11858,7 @@ pst title=[[Someplace, Somewhere]]
 [[|Otherplace]]
 [[Otherplace, Elsewhere|]]
 [[Otherplace, Elsewhere, Anywhere|]]
-!! html
+!! html/php
 [[Otherplace, Somewhere|Otherplace]]
 [[Otherplace, Elsewhere|Otherplace]]
 [[Otherplace, Elsewhere, Anywhere|Otherplace]]
@@ -11761,7 +11871,7 @@ pst title=[[Someplace (IGNORED), Somewhere]]
 !! wikitext
 [[|Otherplace]]
 [[Otherplace (place), Elsewhere|]]
-!! html
+!! html/php
 [[Otherplace, Somewhere|Otherplace]]
 [[Otherplace (place), Elsewhere|Otherplace]]
 !! end
@@ -11773,7 +11883,7 @@ pst title=[[Who, me? (context)]]
 !! wikitext
 [[|Yes, you.]]
 [[Me, Myself, and I (1937 song)|]]
-!! html
+!! html/php
 [[Yes, you. (context)|Yes, you.]]
 [[Me, Myself, and I (1937 song)|Me, Myself, and I]]
 !! end
@@ -11784,7 +11894,7 @@ pre-save transform: context links ("pipe trick") with namespace
 pst title=[[Ns:Somearticle]]
 !! wikitext
 [[|Article]]
-!! html
+!! html/php
 [[Ns:Article|Article]]
 !! end
 
@@ -11794,7 +11904,7 @@ pre-save transform: context links ("pipe trick") with namespace and parens
 pst title=[[Ns:Somearticle (context)]]
 !! wikitext
 [[|Article]]
-!! html
+!! html/php
 [[Ns:Article (context)|Article]]
 !! end
 
@@ -11804,7 +11914,7 @@ pre-save transform: context links ("pipe trick") with namespace and comma
 pst title=[[Ns:Somearticle, Context, Whatever]]
 !! wikitext
 [[|Article]]
-!! html
+!! html/php
 [[Ns:Article, Context, Whatever|Article]]
 !! end
 
@@ -11814,7 +11924,7 @@ pre-save transform: context links ("pipe trick") with namespace, comma and paren
 pst title=[[Ns:Somearticle, Context (context)]]
 !! wikitext
 [[|Article]]
-!! html
+!! html/php
 [[Ns:Article (context)|Article]]
 !! end
 
@@ -11824,7 +11934,7 @@ pre-save transform: context links ("pipe trick") with namespace, parens and comm
 pst title=[[Ns:Somearticle (IGNORED), Context]]
 !! wikitext
 [[|Article]]
-!! html
+!! html/php
 [[Ns:Article, Context|Article]]
 !! end
 
@@ -11839,7 +11949,7 @@ pst
 [[|Article(context)]]
 [[Bar:X(Y)Z|]]
 [[:Bar:X(Y)Z|]]
-!! html
+!! html/php
 [[Article(context)|Article]]
 [[Bar:Article(context)|Article]]
 [[:Bar:Article(context)|Article]]
@@ -11859,7 +11969,7 @@ pst
 [[|Article (context)]]
 [[Bar:X (Y) Z|]]
 [[:Bar:X (Y) Z|]]
-!! html
+!! html/php
 [[Article (context)|Article]]
 [[Bar:Article (context)|Article]]
 [[:Bar:Article (context)|Article]]
@@ -11879,7 +11989,7 @@ pst
 [[|Article(context)]]
 [[Bar:X(Y)Z|]]
 [[:Bar:X(Y)Z|]]
-!! html
+!! html/php
 [[Article(context)|Article]]
 [[Bar:Article(context)|Article]]
 [[:Bar:Article(context)|Article]]
@@ -11899,7 +12009,7 @@ pst
 [[Bar:Article (context),context|]]
 [[:Bar:Article (context), context|]]
 [[:Bar:Article (context),context|]]
-!! html
+!! html/php
 [[Article (context), context|Article]]
 [[Article (context),context|Article]]
 [[Bar:Article (context), context|Article]]
@@ -11918,7 +12028,7 @@ Empty lines are trimmed
 
 
 
-!! html
+!! html/php
 Empty lines are trimmed
 !! end
 
@@ -11931,7 +12041,7 @@ pst
 * <noinclude>~~~</noinclude>
 * <includeonly>~~~</includeonly>
 * <onlyinclude>~~~</onlyinclude>
-!! html
+!! html/php
 * [[Special:Contributions/127.0.0.1|127.0.0.1]]
 * <noinclude>[[Special:Contributions/127.0.0.1|127.0.0.1]]</noinclude>
 * <includeonly>[[Special:Contributions/127.0.0.1|127.0.0.1]]</includeonly>
@@ -11962,7 +12072,7 @@ As well as inside noinclude/onlyinclude
 
 But not inside includeonly
 <includeonly>{{subst:Foo}}</includeonly>
-!! html
+!! html/php
 Shall not expand:
 
 <nowiki>~~~~</nowiki>
@@ -15171,13 +15281,19 @@ Attribute test: unquoted but illegal value (hash)
 </p>
 !! end
 
+# Parsoid does not serialize to empty attribute syntax,
+# so wt2wt and html2wt cases are skipped
 !! test
-Attribute test: no value
+Attribute test: no value (T54330)
+!! options
+parsoid=wt2html,html2html
 !! wikitext
 <font color>foo</font>
-!! html
-<p><font color="color">foo</font>
+!! html/php
+<p><font color="">foo</font>
 </p>
+!! html/parsoid
+<p><font color="">foo</font></p>
 !! end
 
 !! test
@@ -15606,7 +15722,7 @@ evil <math>-wiki-tags without Extension:Math enabled
 Parser hook: empty input
 !! wikitext
 <tag></tag>
-!! html
+!! html/php
 <pre>
 ''
 array (
@@ -15619,7 +15735,7 @@ array (
 Parser hook: empty input using terminated empty elements
 !! wikitext
 <tag/>
-!! html
+!! html/php
 <pre>
 NULL
 array (
@@ -15632,7 +15748,7 @@ array (
 Parser hook: empty input using terminated empty elements (space before)
 !! wikitext
 <tag />
-!! html
+!! html/php
 <pre>
 NULL
 array (
@@ -15645,7 +15761,7 @@ array (
 Parser hook: basic input
 !! wikitext
 <tag>input</tag>
-!! html
+!! html/php
 <pre>
 'input'
 array (
@@ -15659,7 +15775,7 @@ array (
 Parser hook: case insensitive
 !! wikitext
 <TAG>input</TAG>
-!! html
+!! html/php
 <pre>
 'input'
 array (
@@ -15673,7 +15789,7 @@ array (
 Parser hook: case insensitive, redux
 !! wikitext
 <TaG>input</TAg>
-!! html
+!! html/php
 <pre>
 'input'
 array (
@@ -15688,7 +15804,7 @@ Parser hook: nested tags
 noxml
 !! wikitext
 <tag><tag></tag></tag>
-!! html
+!! html/php
 <pre>
 '<tag>'
 array (
@@ -15701,14 +15817,14 @@ array (
 Parser hook: basic arguments
 !! wikitext
 <tag width=200 height = "100" depth = '50' square></tag>
-!! html
+!! html/php
 <pre>
 ''
 array (
   'width' => '200',
   'height' => '100',
   'depth' => '50',
-  'square' => 'square',
+  'square' => '',
 )
 </pre>
 
@@ -15718,7 +15834,7 @@ array (
 Parser hook: argument containing a forward slash (bug 5344)
 !! wikitext
 <tag filename='/tmp/bla'></tag>
-!! html
+!! html/php
 <pre>
 ''
 array (
@@ -15732,7 +15848,7 @@ array (
 Parser hook: empty input using terminated empty elements (bug 2374)
 !! wikitext
 <tag foo=bar/>text
-!! html
+!! html/php
 <pre>
 NULL
 array (
@@ -15749,14 +15865,14 @@ Parser hook: basic arguments using terminated empty elements (bug 2374)
 <tag width=200 height = "100" depth = '50' square/>
 other stuff
 </tag>
-!! html
+!! html/php
 <pre>
 NULL
 array (
   'width' => '200',
   'height' => '100',
   'depth' => '50',
-  'square' => 'square',
+  'square' => '',
 )
 </pre>
 <p>other stuff
@@ -15773,7 +15889,7 @@ Parser hook: static parser hook not inside a comment
 !! wikitext
 <statictag>hello, world</statictag>
 <statictag action=flush/>
-!! html
+!! html/php
 <p>hello, world
 </p>
 !! end
@@ -15784,7 +15900,7 @@ Parser hook: static parser hook inside a comment
 !! wikitext
 <!-- <statictag>hello, world</statictag> -->
 <statictag action=flush/>
-!! html
+!! html/php
 <p><br />
 </p>
 !! end
@@ -15843,20 +15959,24 @@ Sanitizer: Closing of open but not closed tags
 
 !! test
 Sanitizer: Closing of closed but not open tags
+!! options
+parsoid=wt2html
 !! wikitext
 </s>
-!! html
-<p>&lt;/s&gt;
-</p>
+!! html/php+tidy
+!! html/parsoid
 !! end
 
 !! test
 Sanitizer: Closing of closed but not open table tags
+!! options
+parsoid=wt2html
 !! wikitext
 Table not started</td></tr></table>
-!! html
-<p>Table not started&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
-</p>
+!! html/php+tidy
+<p>Table not started</p>
+!! html/parsoid
+<p>Table not started</p>
 !! end
 
 !! test
@@ -15903,7 +16023,7 @@ Sanitizer: Validating that <meta> and <link> work, but only for Microdata
        <link rel="stylesheet" itemprop="hello" href="{{SERVER}}">
 </div>
 !! html
-<div itemscope="itemscope">
+<div itemscope="">
 <p>    <meta itemprop="hello" content="world" />
        &lt;meta http-equiv="refresh" content="5"&gt;
        <meta itemprop="hello" content="5" />
@@ -16655,7 +16775,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 !! end
 
@@ -16675,7 +16795,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 ==a==
 ===aa===
 ====aaa====
@@ -16697,7 +16817,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 ===aa===
 ====aaa====
 !! end
@@ -16718,7 +16838,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 ====aaa====
 !! end
 
@@ -16738,7 +16858,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 ==b==
 ===ba===
 ===bb===
@@ -16762,7 +16882,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 ===ba===
 !! end
 
@@ -16782,7 +16902,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 ===bb===
 ====bba====
 !! end
@@ -16803,7 +16923,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 ====bba====
 !! end
 
@@ -16823,7 +16943,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 ===bc===
 !! end
 
@@ -16843,7 +16963,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 ==c==
 ===ca===
 !! end
@@ -16864,7 +16984,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 ===ca===
 !! end
 
@@ -16884,7 +17004,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 !! end
 
 !! test
@@ -16895,7 +17015,7 @@ section=1
 ==a==
 ==bogus== not a legal section
 ==b==
-!! html
+!! html/php
 ==a==
 ==bogus== not a legal section
 !! end
@@ -16908,7 +17028,7 @@ section=2
 ==a==
 ==bogus== not a legal section
 ==b==
-!! html
+!! html/php
 ==b==
 !! end
 
@@ -16920,7 +17040,7 @@ section=1
 ==a==
 ==b== <!-- -->
 ==c==
-!! html
+!! html/php
 ==a==
 !! end
 
@@ -16932,7 +17052,7 @@ section=2
 ==a==
 ==b== <!-- -->
 ==c==
-!! html
+!! html/php
 ==b== <!-- -->
 !! end
 
@@ -16944,7 +17064,7 @@ section=1
 ==a==
 ==bogus== <nowiki>not a legal section</nowiki>
 ==b==
-!! html
+!! html/php
 ==a==
 ==bogus== <nowiki>not a legal section</nowiki>
 !! end
@@ -16957,11 +17077,10 @@ section=2
 ==a==
 ==bogus== <nowiki>not a legal section</nowiki>
 ==b==
-!! html
+!! html/php
 ==b==
 !! end
 
-
 # Formerly testing for bug 2587, now resolved by the use of unmarked sections
 # instead of respecting commented sections
 !! test
@@ -16971,7 +17090,7 @@ section=1
 !! wikitext
 <!-- -->==sec1==
 ==sec2==
-!! html
+!! html/php
 ==sec2==
 !!end
 
@@ -16982,11 +17101,10 @@ section=2
 !! wikitext
 <!-- -->==sec1==
 ==sec2==
-!! html
+!! html/php
 
 !!end
 
-
 # Formerly testing for bug 2607, now resolved by the use of unmarked sections
 # instead of respecting HTML-style headings
 !! test
@@ -17000,7 +17118,7 @@ unmarked
 one
 ==2==
 two
-!! html
+!! html/php
 ==1==
 one
 !! end
@@ -17016,7 +17134,7 @@ unmarked
 one
 ==2==
 two
-!! html
+!! html/php
 ==2==
 two
 !! end
@@ -17030,7 +17148,7 @@ section=1
 !! wikitext
 <noinclude>==unmarked==</noinclude>
 ==marked==
-!! html
+!! html/php
 ==marked==
 !!end
 
@@ -17045,7 +17163,7 @@ The line above must have a trailing space
 === <!--
 --> <!-- -->
 But just in case it doesn't...
-!! html
+!! html/php
 === <!--
 --> <!-- -->
 But just in case it doesn't...
@@ -17067,7 +17185,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 xxx
 
 ==a==
@@ -17098,7 +17216,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 xxx
 
@@ -17127,7 +17245,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 ==a==
 xxx
@@ -17157,7 +17275,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 ==a==
 ===aa===
@@ -17188,7 +17306,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 ==a==
 ===aa===
@@ -17215,7 +17333,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 ==a==
 ===aa===
@@ -17246,7 +17364,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 ==a==
 ===aa===
@@ -17276,7 +17394,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 ==a==
 ===aa===
@@ -17307,7 +17425,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 ==a==
 ===aa===
@@ -17338,7 +17456,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 ==a==
 ===aa===
@@ -17367,7 +17485,7 @@ start
 ===bc===
 ==c==
 ===ca===
-!! html
+!! html/php
 start
 ==a==
 ===aa===
@@ -17389,7 +17507,7 @@ replace=2,"xxx"
  Preformatted initial line
 ==a==
 ===a===
-!! html
+!! html/php
  Preformatted initial line
 ==a==
 xxx
@@ -17403,7 +17521,7 @@ section=1
 !! wikitext
 ==a==
                     a
-!! html
+!! html/php
 ==a==
                     a
 !! end
@@ -17415,7 +17533,7 @@ section=1
 !! wikitext
 ==a==
                    a
-!! html
+!! html/php
 ==a==
                    a
 !! end
@@ -17433,7 +17551,7 @@ noxml section=2
 
 == Section Two ==
 stuff
-!! html
+!! html/php
 == Section Two ==
 stuff
 !! end
@@ -17450,7 +17568,7 @@ noxml replace=2,"xxx"
 
 == Section Two ==
 stuff
-!! html
+!! html/php
 == Section One ==
 <pre>
 =======
@@ -17460,7 +17578,6 @@ xxx
 !! end
 
 
-
 !! test
 Handling of &#x0A; in URLs
 !! wikitext
@@ -18247,7 +18364,7 @@ Don't fall for the self-closing div
 MSGNW magic word
 !! wikitext
 {{MSGNW:msg}}
-!! html
+!! html/php
 <p>&#91;&#91;:Template:Msg&#93;&#93;
 </p>
 !! end
@@ -19680,7 +19797,7 @@ wgAllowDisplayTitle=true
 wgRestrictDisplayTitle=false
 !! wikitext
 this is not the the title
-!! html
+!! html/php
 Parser test
 <p>this is not the the title
 </p>
@@ -19697,7 +19814,7 @@ wgRestrictDisplayTitle=false
 !! wikitext
 this is not the the title
 {{DISPLAYTITLE:whatever}}
-!! html
+!! html/php
 whatever
 <p>this is not the the title
 </p>
@@ -19714,7 +19831,7 @@ wgRestrictDisplayTitle=true
 !! wikitext
 this is not the the title
 {{DISPLAYTITLE:whatever}}
-!! html
+!! html/php
 Screen
 <p>this is not the the title
 </p>
@@ -19731,7 +19848,7 @@ wgRestrictDisplayTitle=true
 !! wikitext
 this is not the the title
 {{DISPLAYTITLE:screen}}
-!! html
+!! html/php
 screen
 <p>this is not the the title
 </p>
@@ -19747,7 +19864,7 @@ wgAllowDisplayTitle=false
 !! wikitext
 this is not the the title
 {{DISPLAYTITLE:screen}}
-!! html
+!! html/php
 Screen
 <p>this is not the the title
 <a href="/index.php?title=Template:DISPLAYTITLE:screen&amp;action=edit&amp;redlink=1" class="new" title="Template:DISPLAYTITLE:screen (page does not exist)">Template:DISPLAYTITLE:screen</a>
@@ -19763,7 +19880,7 @@ title=[[Screen]]
 wgAllowDisplayTitle=false
 !! wikitext
 this is not the the title
-!! html
+!! html/php
 Screen
 <p>this is not the the title
 </p>
@@ -19780,7 +19897,7 @@ wgRestrictDisplayTitle=true
 !! wikitext
 this is not the the title
 {{DISPLAYTITLE:<span style="display: none;">s</span>creen}}
-!! html
+!! html/php
 <span style="/* attempt to bypass $wgRestrictDisplayTitle */">s</span>creen
 <p>this is not the the title
 </p>
@@ -19797,7 +19914,7 @@ wgRestrictDisplayTitle=true
 !! wikitext
 this is not the the title
 {{DISPLAYTITLE:<span style="color: red;">s</span>creen}}
-!! html
+!! html/php
 <span style="color: red;">s</span>creen
 <p>this is not the the title
 </p>
@@ -19822,7 +19939,7 @@ Page status indicators: Weird syntaxes that are okay
 showindicators
 !! wikitext
 <indicator name="empty" />
-<indicator name></indicator>
+<indicator name="name"></indicator>
 !! html
 empty=
 name=
@@ -19885,7 +20002,7 @@ preload: check <noinclude> and <includeonly>
 preload
 !! wikitext
 Hello <noinclude>cruel</noinclude><includeonly>kind</includeonly> world.
-!! html
+!! html/php
 Hello kind world.
 !! end
 
@@ -19895,7 +20012,7 @@ preload: check <onlyinclude>
 preload
 !! wikitext
 Goodbye <onlyinclude>Hello world</onlyinclude>
-!! html
+!! html/php
 Hello world
 !! end
 
@@ -19905,7 +20022,7 @@ preload: can pass tags through if we want to
 preload
 !! wikitext
 <includeonly><</includeonly>includeonly>Hello world<includeonly><</includeonly>/includeonly>
-!! html
+!! html/php
 <includeonly>Hello world</includeonly>
 !! end
 
@@ -19915,7 +20032,7 @@ preload: check that it doesn't try to do tricks
 preload
 !! wikitext
 * <!-- Hello --> ''{{world}}'' {{<includeonly>subst:</includeonly>How are you}}{{ {{{|safesubst:}}} #if:1|2|3}}
-!! html
+!! html/php
 * <!-- Hello --> ''{{world}}'' {{subst:How are you}}{{ {{{|safesubst:}}} #if:1|2|3}}
 !! end
 
@@ -20747,6 +20864,30 @@ parsoid=wt2html,wt2wt
 <small><figure class="mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="34" width="300"/></a></figure></small>
 !! end
 
+!! test
+3. Bad treebuilder fixup of formatting elt is cleaned up
+!! options
+parsoid=wt2html,wt2wt
+!! wikitext
+<small>'''foo[[File:Foobar.jpg|thumb|caption]]bar'''</small>
+!! html/parsoid
+<p><small><b>foo</b></small></p>
+<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><small><b>caption</b></small></figcaption></figure>
+<p><small><b>bar</b></small></p>
+!! end
+
+!! test
+4. Bad treebuilder fixup of formatting elt is cleaned up: formatting tags around captionless images are ignored
+!! options
+parsoid=wt2html,wt2wt
+!! wikitext
+'''<small>[[Image:Foobar.jpg|right|300px]]</small>'''
+!! html/parsoid
+<p><b><small></small></b></p>
+<figure class="mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="34" width="300"/></a></figure>
+<p></p>
+!! end
+
 #### ----------------------------------------------------------------
 #### Parsoid-only testing of Parsoid's impl of <ref> and <references>
 #### tags. Parsoid's output for these tags differs from that of the
@@ -21600,8 +21741,6 @@ Headings: 5. Empty headings
 
 !! test
 Headings: 6a. Heading chars in SOL context (with trailing spaces)
-!! options
-parsoid
 !! wikitext
 <nowiki>=a=</nowiki>
 
@@ -21610,17 +21749,24 @@ parsoid
 <nowiki>=a=</nowiki>   
 
 <nowiki>=a=</nowiki>   
-!! html
-<p>=a=</p>
-<p>=a= </p>
-<p>=a= </p>
-<p>=a=         </p>
+!! html/php
+<p>=a=
+</p><p>=a= 
+</p><p>=a=     
+</p><p>=a=     
+</p>
+!! html/parsoid
+<p><span typeof="mw:Nowiki">=a=</span></p>
+
+<p><span typeof="mw:Nowiki">=a=</span></p> 
+
+<p><span typeof="mw:Nowiki">=a=</span></p>     
+
+<p><span typeof="mw:Nowiki">=a=</span></p>     
 !!end
 
 !! test
 Headings: 6b. Heading chars in SOL context (with trailing newlines)
-!! options
-parsoid
 !! wikitext
 <nowiki>=a=
 b</nowiki>
@@ -21633,48 +21779,65 @@ b</nowiki>
 
 <nowiki>=a=     
 b</nowiki>
-!! html
+!! html/php
 <p>=a=
-b</p>
-<p>=a= 
-b</p>
-<p>=a= 
-b</p>
-<p>=a=  
-b</p>
+b
+</p><p>=a= 
+b
+</p><p>=a=     
+b
+</p><p>=a=      
+b
 </p>
+!! html/parsoid
+<p><span typeof="mw:Nowiki">=a=
+b</span></p>
+
+<p><span typeof="mw:Nowiki">=a= 
+b</span></p>
+
+<p><span typeof="mw:Nowiki">=a=        
+b</span></p>
+
+<p><span typeof="mw:Nowiki">=a=         
+b</span></p>
 !!end
 
 !! test
 Headings: 6c. Heading chars in SOL context (leading newline break)
-!! options
-parsoid
 !! wikitext
 a
 <nowiki>=b=</nowiki>
-!! html
+!! html/php
 <p>a
-=b=</p>
+=b=
+</p>
+!! html/parsoid
+<p>a
+<span typeof="mw:Nowiki">=b=</span>
 !!end
 
 !! test
 Headings: 6d. Heading chars in SOL context (with interspersed comments)
-!! options
-parsoid
 !! wikitext
 <!--c0--><nowiki>=a=</nowiki>
 
 <!--c1--><nowiki>=a=</nowiki> <!--c2-->         <!--c3-->
-!! html
-<p><!--c0-->=a=</p>
-<p><!--c1-->=a= <!--c2-->       <!--c3--></p>
+!! html/php
+<p>=a=
+</p><p>=a=      
+</p>
+!! html/parsoid
+<!--c0--><p><span typeof="mw:Nowiki">=a=</span></p>
+
+<!--c1--><p><span typeof="mw:Nowiki">=a=</span></p> <!--c2-->   <!--c3-->
 !!end
 
 !! test
 Headings: 6d. Heading chars in SOL context (No escaping needed)
 !! options
 parsoid=html2wt
-!! html
+!! html/parsoid
 =a=<div>b</div>
 !! wikitext
 =a=<div>b</div>
@@ -21684,11 +21847,11 @@ parsoid=html2wt
 Headings: 7. Insert a newline between new content and headings
 !! options
 parsoid=html2wt
-!! html
+!! html/parsoid
 <h2>NEW</h2>
 <p>new</p>
-<h2 data-parsoid='{"dsr":[0,5,2,2]}'>A</h2>
-<p data-parsoid='{"dsr":[6,7,0,0]}'>a</p>
+<h2 data-parsoid='{}'>A</h2>
+<p data-parsoid='{}'>a</p>
 !! wikitext
 == NEW ==
 new
@@ -21717,11 +21880,17 @@ Lists: 0. Outside nests
 <nowiki>#</nowiki>foo
 
 <nowiki>;Foo:</nowiki>bar
-!! html
+!! html/php
 <p>*foo
 </p><p>#foo
 </p><p>;Foo:bar
 </p>
+!! html/parsoid
+<p><span typeof="mw:Nowiki">*</span>foo</p>
+
+<p><span typeof="mw:Nowiki">#</span>foo</p>
+
+<p><span typeof="mw:Nowiki">;Foo:</span>bar</p>
 !!end
 
 !! test
@@ -23392,9 +23561,9 @@ Improperly nested inline or quotes tags with whitespace in between
 !!test
 Encapsulate protected attributes from wt
 !! wikitext
-<div typeof="mw:placeholder stuff" data-parsoid="weird" data-parsoid-other="no" about="time" rel="mw:true">foo</div>
+<div typeof="mw:placeholder stuff" data-mw="whoo" data-parsoid="weird" data-parsoid-other="no" about="time" rel="mw:true">foo</div>
 !! html/parsoid
-<body><div data-x-typeof="mw:placeholder stuff" data-x-data-parsoid="weird" data-x-data-parsoid-other="no" data-x-about="time" data-x-rel="mw:true">foo</div>
+<body><div data-x-typeof="mw:placeholder stuff" data-x-data-mw="whoo" data-x-data-parsoid="weird" data-x-data-parsoid-other="no" data-x-about="time" data-x-rel="mw:true">foo</div>
 </body>
 !!end
 
@@ -24109,9 +24278,43 @@ parsoid=html2wt
 !! end
 
 !! test
-Headings: Force sol-transparent links and behavior switches to serialize before/after
+1. Headings: Force sol-transparent links and behavior switches to serialize before/after
 !! options
-parsoid=html2wt
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": false
+}
+!! html
+<h2>hello there<link href="Category:A1" rel="mw:PageProp/Category" /></h2>
+<h2><link href="Category:A2" rel="mw:PageProp/Category" />hi pal</h2>
+
+<h2><!--foo-->  <link href="Category:A3" rel="mw:PageProp/Category" />   how goes it</h2>
+<h2>it goes well   <link href="Category:A4" rel="mw:PageProp/Category" />  <!--bar--></h2>
+
+<h2 data-parsoid='{}'>howdy<link href="Category:A5" rel="mw:PageProp/Category" /></h2>
+
+<h2><meta property="mw:PageProp/toc" /> ok</h2>
+!! wikitext
+== hello there [[Category:A1]]  ==
+
+==  [[Category:A2]] hi pal ==
+
+== <!--foo-->   [[Category:A3]]    how goes it ==
+
+== it goes well    [[Category:A4]]  <!--bar-->  ==
+
+==howdy [[Category:A5]] ==
+
+==  __TOC__  ok ==
+!! end
+
+!! test
+2. Headings: Force sol-transparent links and behavior switches to serialize before/after
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
 !! html
 <h2>hello there<link href="Category:A1" rel="mw:PageProp/Category" /></h2>
 <h2><link href="Category:A2" rel="mw:PageProp/Category" />hi pal</h2>
@@ -24146,7 +24349,10 @@ __TOC__
 !! test
 Headings: Don't hoist metas that come from templates
 !! options
-parsoid=html2wt
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
 !! html
 <h2><span about="#mwt1" typeof="mw:Transclusion" data-parsoid="{}" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo [[Category:Foo]]"}},"i":0}}]}'>foo </span><link rel="mw:PageProp/Category" href="./Category:Foo" about="#mwt1" data-parsoid="{}" /></h2>
 !! wikitext
@@ -24156,7 +24362,10 @@ parsoid=html2wt
 !! test
 Headings: Category in ref isn't hoisted
 !! options
-parsoid=html2wt
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
 !! html
 <h2> foo <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> </h2>
 
@@ -24261,6 +24470,16 @@ bar
 baz</li>
 <li>foo <b>bar</b>
 baz</li></ul>
+
+<dl><dt>hi
+ho </dt><dd data-parsoid='{"stx":"row"}'> hi
+ho</dd></dl>
+
+<dl><dd> <table>
+<tbody><tr><td> ha
+ha
+ha</td></tr>
+</tbody></table></dd></dl>
 !! wikitext
 == testing 123 ==
 
@@ -24276,6 +24495,14 @@ there</ref> ==
 
 * foo bar baz
 * foo '''bar''' baz
+
+; hi ho : hi ho
+
+: {|
+| ha
+ha
+ha
+|}
 !! end
 
 !! test
@@ -24603,6 +24830,31 @@ x<nowiki/>http://cscott.net<nowiki/>x
 x<nowiki/>http://cscott.net<nowiki/>x
 !! end
 
+!! test
+WTS of edited autolink-like text (T103364)
+!! options
+parsoid={
+  "modes": ["wt2wt"],
+  "changes": [
+    [ "span[typeof]", "removeAttr", "typeof" ]
+  ]
+}
+!! wikitext
+Not a link: <nowiki>http://example.com</nowiki>.
+!! wikitext/edited
+Not a link: <span><nowiki>http://example.com</nowiki></span>.
+!! end
+
+!! test
+WTS of newly-authored autolink-like text (T103364)
+!! options
+parsoid=html2wt
+!! html/parsoid
+<p>http://example.com is not a link.</p>
+!! wikitext
+<nowiki>http://example.com is not a link.</nowiki>
+!! end
+
 !! test
 Edited Redirect link should emit a non-piped wikitext link
 !! options
@@ -24761,7 +25013,7 @@ parsoid=html2wt
 !! end
 
 !! test
-Headings: Add space before/after == (T53744)
+1. Headings: Add space before/after == (T53744)
 !! options
 parsoid=html2wt
 !! html
@@ -24769,9 +25021,6 @@ parsoid=html2wt
 <h2> bar</h2>
 <h2>baz </h2>
 <h2><span> baz</span></h2>
-
-<!-- Even after hoisted content -->
-<h2> <link href="Category:A2" rel="mw:PageProp/Category" />ok</h2>
 !! wikitext
 == foo ==
 
@@ -24780,8 +25029,18 @@ parsoid=html2wt
 == baz ==
 
 == <span> baz</span> ==
+!! end
 
-<!-- Even after hoisted content -->
+!! test
+2. Headings: Add space before/after == even after hoisted content
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
+!! html
+<h2> <link href="Category:A2" rel="mw:PageProp/Category" />ok</h2>
+!! wikitext
  [[Category:A2]]
 
 == ok ==
@@ -24853,8 +25112,11 @@ parsoid={
 }
 !! html
 <p> hi</p>
+<p>    hello</p>
 !! wikitext
 hi
+
+hello
 !! end
 
 !! test
 parsoid=html2wt
 !! html
 <p> hi</p>
+<p>    hello</p>
 !! wikitext
 <nowiki> </nowiki>hi
+
+<nowiki> </nowiki>   hello
+!! end
+
+!! test
+3. Indent Pre Nowiki: suppress whitespace after newlines in new paragraph or table cell
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
+!! html/parsoid
+<p>Foo
+ bar
+baz</p>
+
+<table><tr><td>Foo
+ bar
+ baz bang</td></tr></table>
+
+<p><!--boo--> foo
+ bar</p>
+
+<p> foo
+ bar<span>boo</span></p>
+!! wikitext
+Foo
+bar
+baz
+
+{|
+|Foo
+bar
+baz bang
+|}
+
+<!--boo-->foo
+bar
+
+foo
+bar<span>boo</span>
+!! end
+
+!! test
+1. New links that end in spaces
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": false
+}
+!! html
+<p><a rel="mw:WikiLink" href="./Berlin" title="Berlin">Berlin </a>is the capital of Germany.</p>
+<p><a rel="mw:WikiLink" href="./Foo" title="Foo">Foo </a><b>bar</b></p>
+!! wikitext
+[[Berlin ]]<nowiki/>is the capital of Germany.
+
+[[Foo ]]'''bar'''
+!! end
+
+!! test
+2. New links that end in spaces
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
+!! html
+<p><a rel="mw:WikiLink" href="./Berlin" title="Berlin">Berlin </a>is the capital of Germany.</p>
+<p><a rel="mw:WikiLink" href="./Foo" title="Foo">Foo </a><b>bar</b></p>
+!! wikitext
+[[Berlin]] is the capital of Germany.
+
+[[Foo]] '''bar'''
+!! end
+
+!! test
+3. Existing links that end in spaces
+!! options
+parsoid={
+  "modes": ["html2wt"],
+  "scrubWikitext": true
+}
+!! html
+<p><a rel="mw:WikiLink" href="./Berlin" title="Berlin" data-parsoid='{"stx":"simple","a":{"href":"./Berlin"},"sa":{"href":"Berlin "}}'>Berlin </a>is the capital of Germany.</p>
+
+<p><a rel="mw:WikiLink" href="./Foo" title="Foo" data-parsoid='{"stx":"simple","a":{"href":"./Foo"},"sa":{"href":"Foo "}}'>Foo </a><b>bar</b></p>
+!! wikitext
+[[Berlin ]]<nowiki/>is the capital of Germany.
+
+[[Foo ]]'''bar'''
 !! end
 
 # ---------------------------------------------------
index 69f55c3..6a25d8b 100644 (file)
@@ -142,15 +142,13 @@ class OutputPageTest extends MediaWikiTestCase {
                        array(
                                array( 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS ),
                                "<script>var RLQ = RLQ || []; RLQ.push( function () {\n"
-                                       . 'document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?'
-                                       . 'debug=false\u0026amp;lang=en\u0026amp;modules=test.foo\u0026amp;only'
-                                       . '=scripts\u0026amp;skin=fallback\u0026amp;*\"\u003E\u003C/script\u003E");'
+                                       . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.foo\u0026only=scripts\u0026skin=fallback\u0026*");'
                                        . "\n} );</script>"
                        ),
                        array(
                                // Don't condition wrap raw modules (like the startup module)
                                array( 'test.raw', ResourceLoaderModule::TYPE_SCRIPTS ),
-                               '<script src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.raw&amp;only=scripts&amp;skin=fallback&amp;*"></script>'
+                               '<script async src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.raw&amp;only=scripts&amp;skin=fallback&amp;*"></script>'
                        ),
                        // Load module styles only
                        // This also tests the order the modules are put into the url
@@ -188,10 +186,10 @@ class OutputPageTest extends MediaWikiTestCase {
                        array(
                                array( array( 'test.group.foo', 'test.group.bar' ), ResourceLoaderModule::TYPE_COMBINED ),
                                "<script>var RLQ = RLQ || []; RLQ.push( function () {\n"
-                                       . 'document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?debug=false\u0026amp;lang=en\u0026amp;modules=test.group.bar\u0026amp;skin=fallback\u0026amp;*\"\u003E\u003C/script\u003E");'
+                                       . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.bar\u0026skin=fallback\u0026*");'
                                        . "\n} );</script>\n"
                                        . "<script>var RLQ = RLQ || []; RLQ.push( function () {\n"
-                                       . 'document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?debug=false\u0026amp;lang=en\u0026amp;modules=test.group.foo\u0026amp;skin=fallback\u0026amp;*\"\u003E\u003C/script\u003E");'
+                                       . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.foo\u0026skin=fallback\u0026*");'
                                        . "\n} );</script>"
                        ),
                );
diff --git a/tests/phpunit/includes/libs/SamplingStatsdClientTest.php b/tests/phpunit/includes/libs/SamplingStatsdClientTest.php
new file mode 100644 (file)
index 0000000..be6732d
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+use Liuggio\StatsdClient\Entity\StatsdData;
+
+class SamplingStatsdClientTest extends PHPUnit_Framework_TestCase {
+       /**
+        * @dataProvider samplingDataProvider
+        */
+       public function testSampling( $data, $sampleRate, $seed, $expectWrite ) {
+               $sender = $this->getMock( 'Liuggio\StatsdClient\Sender\SenderInterface' );
+               $sender->expects( $this->any() )->method( 'open' )->will( $this->returnValue( true ) );
+               if ( $expectWrite ) {
+                       $sender->expects( $this->once() )->method( 'write' )
+                               ->with( $this->anything(), $this->equalTo( $data ) );
+               } else {
+                       $sender->expects( $this->never() )->method( 'write' );
+               }
+               mt_srand( $seed );
+               $client = new SamplingStatsdClient( $sender );
+               $client->send( $data, $sampleRate );
+       }
+
+       public function samplingDataProvider() {
+               $unsampled = new StatsdData();
+               $unsampled->setKey( 'foo' );
+               $unsampled->setValue( 1 );
+
+               $sampled = new StatsdData();
+               $sampled->setKey( 'foo' );
+               $sampled->setValue( 1 );
+               $sampled->setSampleRate( '0.1' );
+
+               return array(
+                       // $data, $sampleRate, $seed, $expectWrite
+                       array( $unsampled, 1, 0 /*0.44*/, $unsampled ),
+                       array( $sampled, 1, 0 /*0.44*/, null ),
+                       array( $sampled, 1, 4 /*0.03*/, $sampled ),
+                       array( $unsampled, 0.1, 4 /*0.03*/, $sampled ),
+                       array( $sampled, 0.5, 0 /*0.44*/, null ),
+                       array( $sampled, 0.5, 4 /*0.03*/, $sampled ),
+               );
+       }
+}