Merge "Remove old "bulletin board style toolbar" from core"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 24 Oct 2018 05:30:14 +0000 (05:30 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 24 Oct 2018 05:30:14 +0000 (05:30 +0000)
1  2 
RELEASE-NOTES-1.32
autoload.php
docs/hooks.txt
includes/DefaultSettings.php
includes/EditPage.php
languages/Language.php
languages/i18n/en.json
languages/i18n/qqq.json
resources/Resources.php

diff --combined RELEASE-NOTES-1.32
@@@ -27,15 -27,6 +27,15 @@@ production
    by default.
  * $wgGrantPermissions – A new grant group, 'editsiteconfig', is added for
    granting the above rights.
 +* $wgDBDefaultGroup – A default database group for use by maintenance scripts.
 +* $wgResourceLoaderEnableJSProfiler – This new configuration setting lets you
 +  enable client-side profiling of JavaScript modules; it is off by default.
 +* (T193868) $wgChangeTagsSchemaMigrationStage — This temporary configuration
 +  setting allows sysadmins to gradually migrate the database table schema for
 +  how change tags are stored.
 +* (T199334) $wgTagStatisticsNewTable — This temporary configuration setting
 +  allows sysadmins to enable the caching of Special:Tags via the new
 +  change_tag_def table.
  
  ==== Changed configuration ====
  * $wgUseAjax – This setting, deprecated in 1.31, is now ignored.
    MIGRATION_WRITE_NEW. It instead uses SCHEMA_COMPAT_WRITE_BOTH |
    SCHEMA_COMPAT_READ_OLD and SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW
    for intermediate stages of migration.
 +* $wgDBTableOptions – The default table options now use the binary charset. The
 +  default was already overridden in the installer-generated LocalSettings.php,
 +  and so is always set to binary after the installer UI option was removed. The
 +  default value is only used when the installer installs an extension.
 +* $wgPopularPasswordFile — The location of the default popular passwords file
 +  has been moved to be in line with other non-PHP files used by libraries and
 +  classes.
  
  ==== Removed configuration ====
  * $wgEnableAPI and $wgEnableWriteAPI – These settings, deprecated in 1.31,
    message `emailsender`.
  * $wgTidyConfig – The experimental Html5Internal and Html5Depurate tidy drivers
    were removed. RemexHtml, which is the default, should be used instead.
 +* (T181318) The $wgStyleVersion setting and its appendage to various script and
 +  style URLs in OutputPage, deprecated in 1.31, was removed.
 +* (T140807) The wgResourceLoaderLESSImportPaths configuration option was removed
 +  from ResourceLoader. Instead, use `@import` statements in LESS to import
 +  files directly from nearby directories within the same project.
 +* (T140804) The wgResourceLoaderLESSVars configuration option, deprecated
 +  since 1.30, was removed. Instead, to expose variables from PHP to LESS, use
 +  the ResourceLoaderModule::getLessVars() method.
 +* $wgResourceLoaderValidateStaticJS – This setting, unused since MediaWiki 1.18,
 +  was removed.
 +* Two temporary variables for deploying the feature of filters on change lists,
 +  $wgStructuredChangeFiltersShowPreference introduced in MediaWiki 1.30 and
 +  $wgStructuredChangeFiltersOnWatchlist in 1.31, were removed.
  
  === New features in 1.32 ===
  * (T112474) Generalized the ResourceLoader mechanism for overriding modules
  ==== New external libraries ====
  * Added wikimedia/xmp-reader 0.6.0.
  * Added Add pear/Net_SMTP 1.8.0.
 -* 
 +* Added EasyDeflate (unversioned).
  
  ==== Changed external libraries ====
  * Updated qunitjs from 2.4.0 to 2.6.2.
  * Updated composer/spdx-licenses from 1.3.0 to 1.4.0.
  * Updated jquery.i18n from 1.0.4 to 1.0.5.
  * Updated wikimedia/timestamp from 1.0.0 to 2.2.0.
 -* Updated wikimedia/remex-html from 1.0.3 to 2.0.0.
 -* Updated jquery from v3.2.1 to v3.3.1.
 +* Updated wikimedia/remex-html from 1.0.3 to 2.0.1.
 +* Updated jquery from 3.2.1 to 3.3.1.
 +* Updated wikimedia/base-convert from 1.0.1 to 2.0.0
 +* Updated OOjs from 2.2.0 to 2.2.2
 +* Updated mustache.js from 0.8.2-d9aa703 to 1.0.0
 +* Updated sinonjs from 1.17.3 to 1.17.7
 +* Updated OOUI from 0.26.3 to 0.29.2
 +* Updated CLDRPluralRuleParser from 0.1.0 to 1.3.2-pre
 +* Updated jquery.client from 2.0.0 to 2.0.1.
  
  ==== Removed external libraries ====
  * pear/mail_mime-decode was removed.
 -* …
  
  === Bug fixes in 1.32 ===
  * SpecialPage::execute() will now only call checkLoginSecurityLevel() if
  * (T198214) The 'disabletidy' parameter to action=parse has been
    deprecated; untidy output will not be supported by future wikitext
    parsers.
 +* Added intestactionsdetail to action=query&prop=info to allow retrieving the
 +  reasons an action is not allowed.
 +* Deprecated action=query&prop=info inprop=readable in favor of
 +  intestactions=read.
  
  === Action API internal changes in 1.32 ===
  * Added 'ApiParseMakeOutputPage' hook.
    * ApiUsageException::getCodeString() (deprecated in 1.29)
    * ApiUsageException::getMessageArray() (deprecated in 1.29)
  * Class UsageException, deprecated in 1.29, has been removed.
 +* ApiErrorFormatter: Added getFormat() and newWithFormat(). In particular, you
 +  can now easily test $formatter->getFormat() === 'bc', and then call
 +  $formatter->newWithFormat( 'plaintext' ) to get a non-BC formatter.
  
  === Languages updated in 1.32 ===
  MediaWiki supports over 350 languages. Many localisations are updated regularly.
@@@ -304,6 -262,8 +304,6 @@@ because of Phabricator reports
    removed. Use mediawiki.widgets.visibleLengthLimit instead.
  * The jquery.farbtastic module, unused since 1.18, was removed.
  * The 'jquery.expandableField' module, unused since 1.22, was removed.
 -* (T181318) The $wgStyleVersion setting and its appendage to various script and
 -  style URLs in OutputPage, deprecated in 1.31, was removed.
  * The hooks 'PreferencesFormPreSave' and 'PreferencesGetLegend' may provide
    any HTMLForm object rather than PreferencesForm.
  * The non namespaced TimestampException class, deprecated in 1.29, was removed.
    The UtfNormal\Utils class from the utfnormal library should be used instead.
  * The deprecated UTF8_ and UNICODE_ constants were removed. The class constants
    from the UtfNormal\Constants class from the utfnormal library should be used
 -* (T140807) The wgResourceLoaderLESSImportPaths configuration option was removed
 -  from ResourceLoader. Instead, use `@import` statements in LESS to import
 -  files directly from nearby directories within the same project.
 -* (T140804) The wgResourceLoaderLESSVars configuration option, deprecated
 -  since 1.30, was removed. Instead, to expose variables from PHP to LESS, use
 -  the ResourceLoaderModule::getLessVars() method.
  * The protected methods PHPSessionHandler::returnSuccess() and returnFailure(),
    only needed for PHP5 compatibility, have been removed. It now uses the boolean
    values `true` and `false` respectively.
    a no-op function since 1.30.
  * SpecialPageFactory::resetList() is a no-op.  Call overrideMwServices()
    instead.
 -* MediaWiki no longer supports a StartProfiler.php file.
 -  Define $wgProfiler via LocalSettings.php instead.
 +* MediaWiki no longer supports a StartProfiler.php file. Instead, you can set
 +  $wgProfiler and $wgEnableProfileInfo.
  * The mw.loader.addSource() is now considered a private method, and no longer
    supports the `id, url` signature. Use the `Object` parameter instead.
  * The backwards-compatibility code in HTMLForm to add a drop-down control to an
    * ApiUsageException::getCodeString() (deprecated in 1.29)
    * ApiUsageException::getMessageArray() (deprecated in 1.29)
  * Class UsageException, deprecated in 1.29, has been removed.
+ * MediaWiki no longer has a 'JavaScript-powered' wikitext toolbar built in. The
+   old "bulletin board style toolbar", known as "the 2006 wikitext editor", has
+   been removed, and instead sysadmins will be required to choose one (or more)
+   of the several extensions available for this purpose if they need the
+   functionality. The MediaWiki "tarball" releases have included the replacement
+   extension for this, the WikiEditor extension aka "the 2010 wikitext editor",
+   for many years now. As part of this, several parts of MediaWiki have been
+   removed or simplified:
+   * The user option 'showtoolbar' (shown as "Show edit toolbar") is no longer
+     available; if an extension adds a toolbar via the EditPageBeforeEditToolbar
+     hook, it will be shown; extensions should provide a specific user preference
+     to disable themselves as needed.
+   * The public methods Language::getImageFile() and ::getImageFiles(), and the
+     related specification of $imageFiles within individual languages' code file,
+     as well as the referenced static media assets, all of which were only used
+     inside MediaWiki itself for providing the icons for the old toolbar, have
+     been removed without explicit deprecation.
+   * The internal ResourceLoader module "mediawiki.toolbar", which is unused
+     except by MediaWiki itself and back-compatibility code, has been removed.
+   * The internal ResourceLoaderEditToolbarModule class has been removed.
  
  === Deprecations in 1.32 ===
  * HTMLForm::setSubmitProgressive() is deprecated. No need to call it. Submit
  * The $wgUseKeyHeader configuration option and the
    OutputPage::getKeyHeader() method have been deprecated; the relevant
    draft IETF spec expired without becoming a standard.
 +* Deprecated API action=query&prop=info inprop=readable in favor of
 +  intestactions=read.
  
  === Other changes in 1.32 ===
  * (T198811) The following tables have had their UNIQUE indexes turned into
diff --combined autoload.php
@@@ -613,7 -613,6 +613,7 @@@ $wgAutoloadLocalClasses = 
        'HTMLTextField' => __DIR__ . '/includes/htmlform/fields/HTMLTextField.php',
        'HTMLTextFieldWithButton' => __DIR__ . '/includes/htmlform/fields/HTMLTextFieldWithButton.php',
        'HTMLTitleTextField' => __DIR__ . '/includes/htmlform/fields/HTMLTitleTextField.php',
 +      'HTMLTitlesMultiselectField' => __DIR__ . '/includes/htmlform/fields/HTMLTitlesMultiselectField.php',
        'HTMLUserTextField' => __DIR__ . '/includes/htmlform/fields/HTMLUserTextField.php',
        'HTMLUsersMultiselectField' => __DIR__ . '/includes/htmlform/fields/HTMLUsersMultiselectField.php',
        'HTTPFileStreamer' => __DIR__ . '/includes/libs/filebackend/HTTPFileStreamer.php',
        'MediaWiki\\Widget\\SelectWithInputWidget' => __DIR__ . '/includes/widget/SelectWithInputWidget.php',
        'MediaWiki\\Widget\\SizeFilterWidget' => __DIR__ . '/includes/widget/SizeFilterWidget.php',
        'MediaWiki\\Widget\\TitleInputWidget' => __DIR__ . '/includes/widget/TitleInputWidget.php',
 +      'MediaWiki\\Widget\\TitlesMultiselectWidget' => __DIR__ . '/includes/widget/TitlesMultiselectWidget.php',
        'MediaWiki\\Widget\\UserInputWidget' => __DIR__ . '/includes/widget/UserInputWidget.php',
        'MediaWiki\\Widget\\UsersMultiselectWidget' => __DIR__ . '/includes/widget/UsersMultiselectWidget.php',
        'MemcLockManager' => __DIR__ . '/includes/libs/lockmanager/MemcLockManager.php',
        'ResourceLoader' => __DIR__ . '/includes/resourceloader/ResourceLoader.php',
        'ResourceLoaderClientHtml' => __DIR__ . '/includes/resourceloader/ResourceLoaderClientHtml.php',
        'ResourceLoaderContext' => __DIR__ . '/includes/resourceloader/ResourceLoaderContext.php',
-       'ResourceLoaderEditToolbarModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderEditToolbarModule.php',
        'ResourceLoaderFileModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderFileModule.php',
        'ResourceLoaderFilePath' => __DIR__ . '/includes/resourceloader/ResourceLoaderFilePath.php',
        'ResourceLoaderForeignApiModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderForeignApiModule.php',
        'UserRightsProxy' => __DIR__ . '/includes/user/UserRightsProxy.php',
        'UserrightsPage' => __DIR__ . '/includes/specials/SpecialUserrights.php',
        'UsersPager' => __DIR__ . '/includes/specials/pagers/UsersPager.php',
 -      'UtfNormal' => __DIR__ . '/includes/compat/normal/UtfNormal.php',
        'UzConverter' => __DIR__ . '/languages/classes/LanguageUz.php',
        'VFormHTMLForm' => __DIR__ . '/includes/htmlform/VFormHTMLForm.php',
        'ValidateRegistrationFile' => __DIR__ . '/maintenance/validateRegistrationFile.php',
diff --combined docs/hooks.txt
@@@ -473,15 -473,6 +473,15 @@@ can alter or append to the array
        (url), 'width', 'height', 'alt', 'align'.
      - url: Url for the given title.
  
 +'ApiOptions': Called by action=options before applying changes to user
 +preferences.
 +$apiModule: Calling ApiOptions object
 +$user: User object whose preferences are being changed
 +$changes: Associative array of preference name => value
 +$resetKinds: Array of strings specifying which options kinds to reset.
 +  See User::resetOptions() and User::getOptionKinds() for possible
 +  values.
 +
  'ApiParseMakeOutputPage': Called when preparing the OutputPage object for
  ApiParse. This is mainly intended for calling OutputPage::addContentOverride()
  or OutputPage::addContentOverrideCallback().
@@@ -1480,11 -1471,10 +1480,10 @@@ textarea in the edit form
  &$buttons: Array of edit buttons "Save", "Preview", "Live", and "Diff"
  &$tabindex: HTML tabindex of the last edit check/button
  
- 'EditPageBeforeEditToolbar': Allows modifying the edit toolbar above the
- textarea in the edit form.
- Hook subscribers can return false to avoid the default toolbar code being
- loaded.
- &$toolbar: The toolbar HTML
+ 'EditPageBeforeEditToolbar': Allow adding an edit toolbar above the textarea in
+ the edit form.
+ &$toolbar: The toolbar HTML, initially an empty `<div id="toolbar"></div>`
+ Hook subscribers can return false to have no toolbar HTML be loaded.
  
  'EditPageCopyrightWarning': Allow for site and per-namespace customization of
  contribution/copyright notice.
@@@ -71,7 -71,7 +71,7 @@@ $wgConfigRegistry = 
   * MediaWiki version number
   * @since 1.2
   */
 -$wgVersion = '1.32.0-alpha';
 +$wgVersion = '1.33.0-alpha';
  
  /**
   * Name of the site. It must be changed in LocalSettings.php
@@@ -2736,7 -2736,6 +2736,7 @@@ $wgUseSquid = false
  
  /**
   * If you run Squid3 with ESI support, enable this (default:false):
 + * @deprecated in 1.33. This was a now-defunct experimental feature.
   */
  $wgUseESI = false;
  
@@@ -2850,7 -2849,6 +2850,7 @@@ $wgSquidServersNoPurge = []
   * reverse).
   *
   * @since 1.21
 + * @deprecated since 1.33, will always be true in a future release.
   */
  $wgSquidPurgeUseHostHeader = true;
  
   * @endcode
   *
   * @since 1.22
 - *
 - * $wgHTCPRouting replaces $wgHTCPMulticastRouting that was introduced in 1.20.
 - * For back compatibility purposes, whenever its array is empty
 - * $wgHTCPMutlicastRouting will be used as a fallback if it not null.
 - *
   * @see $wgHTCPMulticastTTL
   */
  $wgHTCPRouting = [];
@@@ -2999,11 -3002,8 +2999,11 @@@ $wgExtraLanguageNames = []
   * @since 1.29
   */
  $wgExtraLanguageCodes = [
 +      // Language codes of macro languages, which get mapped to the main language
        'bh' => 'bho', // Bihari language family
        'no' => 'nb', // Norwegian language family
 +
 +      // Language variants which get mapped to the main language
        'simple' => 'en', // Simple English
  ];
  
@@@ -3022,8 -3022,6 +3022,8 @@@ $wgDummyLanguageCodes = []
   *
   * Note that pages with titles containing presentation forms will become
   * inaccessible, run maintenance/cleanupTitles.php to fix this.
 + *
 + * @deprecated since 1.33: in the future will always be true.
   */
  $wgFixArabicUnicode = true;
  
   *
   * If you enable this on an existing wiki, run maintenance/cleanupTitles.php to
   * fix any ZWJ sequences in existing page titles.
 + *
 + * @deprecated since 1.33: in the future will always be true.
   */
  $wgFixMalayalamUnicode = true;
  
@@@ -4571,6 -4567,10 +4571,6 @@@ $wgAuthManagerConfig = null
   */
  $wgAuthManagerAutoConfig = [
        'preauth' => [
 -              MediaWiki\Auth\LegacyHookPreAuthenticationProvider::class => [
 -                      'class' => MediaWiki\Auth\LegacyHookPreAuthenticationProvider::class,
 -                      'sort' => 0,
 -              ],
                MediaWiki\Auth\ThrottlePreAuthenticationProvider::class => [
                        'class' => MediaWiki\Auth\ThrottlePreAuthenticationProvider::class,
                        'sort' => 0,
@@@ -4887,7 -4887,6 +4887,6 @@@ $wgDefaultUserOptions = 
        'rows' => 25, // @deprecated since 1.29 No longer used in core
        'showhiddencats' => 0,
        'shownumberswatching' => 1,
-       'showtoolbar' => 1,
        'skin' => false,
        'stubthreshold' => 0,
        'thumbsize' => 5,
@@@ -9001,6 -9000,15 +9000,6 @@@ $wgMultiContentRevisionSchemaMigrationS
   */
  $wgActorTableSchemaMigrationStage = SCHEMA_COMPAT_OLD;
  
 -/**
 - * Temporary option to disable the date picker from the Expiry Widget.
 - *
 - * @since 1.32
 - * @deprecated 1.32
 - * @var bool
 - */
 -$wgExpiryWidgetNoDatePicker = false;
 -
  /**
   * change_tag table schema migration stage.
   *
@@@ -9027,16 -9035,6 +9026,16 @@@ $wgChangeTagsSchemaMigrationStage = MIG
   */
  $wgTagStatisticsNewTable = false;
  
 +/**
 + * Flag to enable Partial Blocks. This allows an admin to prevent a user from editing specific pages
 + * or namespaces.
 + *
 + * @since 1.32
 + * @deprecated 1.32
 + * @var bool
 + */
 +$wgEnablePartialBlocks = false;
 +
  /**
   * For really cool vim folding this needs to be at the end:
   * vim: foldmarker=@{,@} foldmethod=marker
diff --combined includes/EditPage.php
@@@ -794,7 -794,7 +794,7 @@@ class EditPage 
                $out->addHTML( $this->editFormTextTop );
  
                if ( $errorMessage !== '' ) {
 -                      $out->addWikiText( $errorMessage );
 +                      $out->addWikiTextAsInterface( $errorMessage );
                        $out->addHTML( "<hr />\n" );
                }
  
                        case self::AS_CANNOT_USE_CUSTOM_MODEL:
                        case self::AS_PARSE_ERROR:
                        case self::AS_UNICODE_NOT_SUPPORTED:
 -                              $out->addWikiText( '<div class="error">' . "\n" . $status->getWikiText() . '</div>' );
 +                              $out->wrapWikiTextAsInterface( 'error', $status->getWikiText() );
                                return true;
  
                        case self::AS_SUCCESS_NEW_ARTICLE:
@@@ -2479,13 -2479,6 +2479,6 @@@ ERROR
                $out->addModuleStyles( 'mediawiki.editfont.styles' );
  
                $user = $this->context->getUser();
-               if ( $user->getOption( 'showtoolbar' ) ) {
-                       // The addition of default buttons is handled by getEditToolbar() which
-                       // has its own dependency on this module. The call here ensures the module
-                       // is loaded in time (it has position "top") for other modules to register
-                       // buttons (e.g. extensions, gadgets, user scripts).
-                       $out->addModules( 'mediawiki.toolbar' );
-               }
  
                if ( $user->getOption( 'uselivepreview' ) ) {
                        $out->addModules( 'mediawiki.action.edit.preview' );
  
                $out->addHTML( $this->editFormTextTop );
  
-               $showToolbar = true;
                if ( $this->wasDeletedSinceLastEdit() ) {
-                       if ( $this->formtype == 'save' ) {
-                               // Hide the toolbar and edit area, user can click preview to get it back
-                               // Add an confirmation checkbox and explanation.
-                               $showToolbar = false;
-                       } else {
+                       if ( $this->formtype !== 'save' ) {
                                $out->wrapWikiMsg( "<div class='error mw-deleted-while-editing'>\n$1\n</div>",
                                        'deletedwhileediting' );
                        }
                        $out->addHTML( $editConflictHelper->getEditFormHtmlBeforeContent() );
                }
  
-               if ( !$this->mTitle->isUserConfigPage() && $showToolbar && $user->getOption( 'showtoolbar' ) ) {
+               if ( !$this->mTitle->isUserConfigPage() ) {
                        $out->addHTML( self::getEditToolbar( $this->mTitle ) );
                }
  
                                        $this->contentFormat,
                                        $ex->getMessage()
                                );
 -                              $out->addWikiText( '<div class="error">' . $msg->plain() . '</div>' );
 +                              $out->wrapWikiTextAsInterface( 'error', $msg->plain() );
                        }
                }
  
                        }
  
                        if ( $this->hookError !== '' ) {
 -                              $out->addWikiText( $this->hookError );
 +                              $out->addWikiTextAsInterface( $this->hookError );
                        }
  
                        if ( $this->section != 'new' ) {
                                        $this->contentFormat,
                                        $ex->getMessage()
                                );
 -                              $out->addWikiText( '<div class="error">' . $msg->plain() . '</div>' );
 +                              $out->wrapWikiTextAsInterface( 'error', $msg->plain() );
                        }
                }
        }
                $out->addHTML( "<div class='editCheckboxes'>" . $checkboxesHTML . "</div>\n" );
  
                // Show copyright warning.
 -              $out->addWikiText( $this->getCopywarn() );
 +              $out->addWikiTextAsInterface( $this->getCopywarn() );
                $out->addHTML( $this->editFormTextAfterWarn );
  
                $out->addHTML( "<div class='editButtons'>\n" );
        }
  
        /**
-        * Shows a bulletin board style toolbar for common editing functions.
-        * It can be disabled in the user preferences.
+        * Allow extensions to provide a toolbar.
         *
         * @param Title|null $title Title object for the page being edited (optional)
-        * @return string
+        * @return string|null
         */
        public static function getEditToolbar( $title = null ) {
-               global $wgOut, $wgEnableUploads, $wgForeignFileRepos;
-               $imagesAvailable = $wgEnableUploads || count( $wgForeignFileRepos );
-               $showSignature = true;
-               if ( $title ) {
-                       $showSignature = MWNamespace::wantSignatures( $title->getNamespace() );
-               }
-               $contLang = MediaWikiServices::getInstance()->getContentLanguage();
-               /**
-                * $toolarray is an array of arrays each of which includes the
-                * opening tag, the closing tag, optionally a sample text that is
-                * inserted between the two when no selection is highlighted
-                * and.  The tip text is shown when the user moves the mouse
-                * over the button.
-                *
-                * Images are defined in ResourceLoaderEditToolbarModule.
-                */
-               $toolarray = [
-                       [
-                               'id'     => 'mw-editbutton-bold',
-                               'open'   => '\'\'\'',
-                               'close'  => '\'\'\'',
-                               'sample' => wfMessage( 'bold_sample' )->text(),
-                               'tip'    => wfMessage( 'bold_tip' )->text(),
-                       ],
-                       [
-                               'id'     => 'mw-editbutton-italic',
-                               'open'   => '\'\'',
-                               'close'  => '\'\'',
-                               'sample' => wfMessage( 'italic_sample' )->text(),
-                               'tip'    => wfMessage( 'italic_tip' )->text(),
-                       ],
-                       [
-                               'id'     => 'mw-editbutton-link',
-                               'open'   => '[[',
-                               'close'  => ']]',
-                               'sample' => wfMessage( 'link_sample' )->text(),
-                               'tip'    => wfMessage( 'link_tip' )->text(),
-                       ],
-                       [
-                               'id'     => 'mw-editbutton-extlink',
-                               'open'   => '[',
-                               'close'  => ']',
-                               'sample' => wfMessage( 'extlink_sample' )->text(),
-                               'tip'    => wfMessage( 'extlink_tip' )->text(),
-                       ],
-                       [
-                               'id'     => 'mw-editbutton-headline',
-                               'open'   => "\n== ",
-                               'close'  => " ==\n",
-                               'sample' => wfMessage( 'headline_sample' )->text(),
-                               'tip'    => wfMessage( 'headline_tip' )->text(),
-                       ],
-                       $imagesAvailable ? [
-                               'id'     => 'mw-editbutton-image',
-                               'open'   => '[[' . $contLang->getNsText( NS_FILE ) . ':',
-                               'close'  => ']]',
-                               'sample' => wfMessage( 'image_sample' )->text(),
-                               'tip'    => wfMessage( 'image_tip' )->text(),
-                       ] : false,
-                       $imagesAvailable ? [
-                               'id'     => 'mw-editbutton-media',
-                               'open'   => '[[' . $contLang->getNsText( NS_MEDIA ) . ':',
-                               'close'  => ']]',
-                               'sample' => wfMessage( 'media_sample' )->text(),
-                               'tip'    => wfMessage( 'media_tip' )->text(),
-                       ] : false,
-                       [
-                               'id'     => 'mw-editbutton-nowiki',
-                               'open'   => "<nowiki>",
-                               'close'  => "</nowiki>",
-                               'sample' => wfMessage( 'nowiki_sample' )->text(),
-                               'tip'    => wfMessage( 'nowiki_tip' )->text(),
-                       ],
-                       $showSignature ? [
-                               'id'     => 'mw-editbutton-signature',
-                               'open'   => wfMessage( 'sig-text', '~~~~' )->inContentLanguage()->text(),
-                               'close'  => '',
-                               'sample' => '',
-                               'tip'    => wfMessage( 'sig_tip' )->text(),
-                       ] : false,
-                       [
-                               'id'     => 'mw-editbutton-hr',
-                               'open'   => "\n----\n",
-                               'close'  => '',
-                               'sample' => '',
-                               'tip'    => wfMessage( 'hr_tip' )->text(),
-                       ]
-               ];
+               $startingToolbar = '<div id="toolbar"></div>';
+               $toolbar = $startingToolbar;
  
-               $script = '';
-               foreach ( $toolarray as $tool ) {
-                       if ( !$tool ) {
-                               continue;
-                       }
-                       $params = [
-                               // Images are defined in ResourceLoaderEditToolbarModule
-                               false,
-                               // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
-                               // Older browsers show a "speedtip" type message only for ALT.
-                               // Ideally these should be different, realistically they
-                               // probably don't need to be.
-                               $tool['tip'],
-                               $tool['open'],
-                               $tool['close'],
-                               $tool['sample'],
-                               $tool['id'],
-                       ];
-                       $script .= Xml::encodeJsCall(
-                               'mw.toolbar.addButton',
-                               $params,
-                               ResourceLoader::inDebugMode()
-                       );
-               }
-               $toolbar = '<div id="toolbar"></div>';
-               if ( Hooks::run( 'EditPageBeforeEditToolbar', [ &$toolbar ] ) ) {
-                       // Only add the old toolbar cruft to the page payload if the toolbar has not
-                       // been over-written by a hook caller
-                       $nonce = $wgOut->getCSPNonce();
-                       $wgOut->addScript( Html::inlineScript(
-                               ResourceLoader::makeInlineCodeWithModule( 'mediawiki.toolbar', $script ),
-                               $nonce
-                       ) );
+               if ( !Hooks::run( 'EditPageBeforeEditToolbar', [ &$toolbar ] ) ) {
+                       return null;
                };
-               return $toolbar;
+               // Don't add a pointless `<div>` to the page unless a hook caller populated it
+               return ( $toolbar === $startingToolbar ) ? null : $toolbar;
        }
  
        /**
diff --combined languages/Language.php
@@@ -814,22 -814,6 +814,6 @@@ class Language 
                return self::$dataCache->getItem( $this->mCode, 'datePreferenceMigrationMap' );
        }
  
-       /**
-        * @param string $image
-        * @return array|null
-        */
-       function getImageFile( $image ) {
-               return self::$dataCache->getSubitem( $this->mCode, 'imageFiles', $image );
-       }
-       /**
-        * @return array
-        * @since 1.24
-        */
-       public function getImageFiles() {
-               return self::$dataCache->getItem( $this->mCode, 'imageFiles' );
-       }
        /**
         * @return array
         */
                );
        }
  
 -      /**
 -       * This method is deprecated since 1.31 and kept as alias for truncateForDatabase, which
 -       * has replaced it. This method provides truncation suitable for DB.
 -       *
 -       * The database offers limited byte lengths for some columns in the database;
 -       * multi-byte character sets mean we need to ensure that only whole characters
 -       * are included, otherwise broken characters can be passed to the user.
 -       *
 -       * @deprecated since 1.31, use truncateForDatabase or truncateForVisual as appropriate.
 -       *
 -       * @param string $string String to truncate
 -       * @param int $length Maximum length (including ellipsis)
 -       * @param string $ellipsis String to append to the truncated text
 -       * @param bool $adjustLength Subtract length of ellipsis from $length.
 -       *      $adjustLength was introduced in 1.18, before that behaved as if false.
 -       * @return string
 -       */
 -      function truncate( $string, $length, $ellipsis = '...', $adjustLength = true ) {
 -              wfDeprecated( __METHOD__, '1.31' );
 -              return $this->truncateForDatabase( $string, $length, $ellipsis, $adjustLength );
 -      }
 -
        /**
         * Truncate a string to a specified length in bytes, appending an optional
         * string (e.g. for ellipsis)
        }
  
        /**
 -       * Check if the language has the specific variant
 +       * Strict check if the language has the specific variant.
 +       *
 +       * Compare to LanguageConverter::validateVariant() which does a more
 +       * lenient check and attempts to coerce the given code to a valid one.
         *
         * @since 1.19
         * @param string $variant
         * @return bool
         */
        public function hasVariant( $variant ) {
 -              return (bool)$this->mConverter->validateVariant( $variant );
 +              return $variant && ( $variant === $this->mConverter->validateVariant( $variant ) );
        }
  
        /**
diff --combined languages/i18n/en.json
@@@ -11,7 -11,6 +11,6 @@@
        "tog-extendwatchlist": "Expand watchlist to show all changes, not just the most recent",
        "tog-usenewrc": "Group changes by page in recent changes and watchlist",
        "tog-numberheadings": "Auto-number headings",
-       "tog-showtoolbar": "Show edit toolbar",
        "tog-editondblclick": "Edit pages on double click",
        "tog-editsectiononrightclick": "Enable section editing by right clicking on section titles",
        "tog-watchcreations": "Add pages I create and files I upload to my watchlist",
        "subject-preview": "Preview of subject:",
        "previewerrortext": "An error occurred while attempting to preview your changes.",
        "blockedtitle": "User is blocked",
 +      "blocked-email-user": "<strong>Your username has been blocked from sending email. You can still edit other pages on this wiki.</strong> You can view the full block details at [[Special:MyContributions|account contributions]].\n\nThe block was made by $1.\n\nThe reason given is <em>$2</em>.\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n* Block ID #$5",
 +      "blockedtext-partial": "<strong>Your username or IP address has been blocked from making changes to this page. You can still edit other pages on this wiki.</strong> You can view the full block details at [[Special:MyContributions|account contributions]].\n\nThe block was made by $1.\n\nThe reason given is <em>$2</em>.\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n* Block ID #$5",
        "blockedtext": "<strong>Your username or IP address has been blocked.</strong>\n\nThe block was made by $1.\nThe reason given is <em>$2</em>.\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n\nYou can contact $1 or another [[{{MediaWiki:Grouppage-sysop}}|administrator]] to discuss the block.\nYou cannot use the \"{{int:emailuser}}\" feature unless a valid email address is specified in your [[Special:Preferences|account preferences]] and you have not been blocked from using it.\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
        "autoblockedtext": "Your IP address has been automatically blocked because it was used by another user, who was blocked by $1.\nThe reason given is:\n\n:<em>$2</em>\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n\nYou may contact $1 or one of the other [[{{MediaWiki:Grouppage-sysop}}|administrators]] to discuss the block.\n\nNote that you may not use the \"{{int:emailuser}}\" feature unless you have a valid email address registered in your [[Special:Preferences|user preferences]] and you have not been blocked from using it.\n\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
        "systemblockedtext": "Your username or IP address has been automatically blocked by MediaWiki.\nThe reason given is:\n\n:<em>$2</em>\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n\nYour current IP address is $3.\nPlease include all above details in any queries you make.",
        "prefixindex-namespace": "All pages with prefix ($1 namespace)",
        "prefixindex-summary": "",
        "prefixindex-submit": "Show",
 -      "prefixindex-strip": "Strip prefix in list",
 +      "prefixindex-strip": "Hide the prefix in results",
        "shortpages": "Short pages",
        "shortpages-summary": "",
        "longpages": "Long pages",
        "ipb-disableusertalk": "Prevent this user from editing their own talk page while blocked",
        "ipb-change-block": "Re-block the user with these settings",
        "ipb-confirm": "Confirm block",
 +      "ipb-sitewide": "Sitewide",
 +      "ipb-partial": "Partial",
 +      "ipb-type-label": "Type",
 +      "ipb-pages-label": "Pages",
        "badipaddress": "Invalid IP address",
        "blockipsuccesssub": "Block succeeded",
        "blockipsuccesstext": "[[Special:Contributions/$1|$1]] has been blocked.<br />\nSee the [[Special:BlockList|block list]] to review blocks.",
        "logentry-block-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} with an expiration time of $5 $6",
        "logentry-block-unblock": "$1 {{GENDER:$2|unblocked}} {{GENDER:$4|$3}}",
        "logentry-block-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} with an expiration time of $5 $6",
 +      "logentry-partialblock-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} from editing {{PLURAL:$8||the pages}} $7 with an expiration time of $5 $6",
 +      "logentry-partialblock-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} preventing edits on {{PLURAL:$8||the pages}} $7 with an expiration time of $5 $6",
 +      "logentry-non-editing-block-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} from non-editing actions with an expiration time of $5 $6",
 +      "logentry-non-editing-block-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} for non-editing actions with an expiration time of $5 $6",
        "logentry-suppress-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} with an expiration time of $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} with an expiration time of $5 $6",
        "logentry-import-upload": "$1 {{GENDER:$2|imported}} $3 by file upload",
        "mw-widgets-titleinput-description-redirect": "redirect to $1",
        "mw-widgets-categoryselector-add-category-placeholder": "Add a category...",
        "mw-widgets-usersmultiselect-placeholder": "Add more...",
 +      "mw-widgets-titlesmultiselect-placeholder": "Add more...",
        "date-range-from": "From date:",
        "date-range-to": "To date:",
        "sessionmanager-tie": "Cannot combine multiple request authentication types: $1.",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "Password cannot match specifically blacklisted passwords",
        "passwordpolicies-policy-maximalpasswordlength": "Password must be less than $1 {{PLURAL:$1|character|characters}} long",
        "passwordpolicies-policy-passwordcannotbepopular": "Password cannot be {{PLURAL:$1|the popular password|in the list of $1 popular passwords}}",
 -      "easydeflate-invaliddeflate": "Content provided is not properly deflated"
 +      "easydeflate-invaliddeflate": "Content provided is not properly deflated",
 +      "unprotected-js": "For security reasons JavaScript cannot be loaded from unprotected pages. Please only create javascript in the MediaWiki: namespace or as a User subpage"
  }
diff --combined languages/i18n/qqq.json
        "tog-extendwatchlist": "[[Special:Preferences]], tab 'Watchlist'. Offers user to show all applicable changes in watchlist (by default only the last change to a page on the watchlist is shown). {{Gender}}",
        "tog-usenewrc": "{{Gender}}\nUsed as label for the checkbox in [[Special:Preferences]], tab \"Recent changes\".\n\nOffers user to use alternative representation of [[Special:RecentChanges]] and watchlist.",
        "tog-numberheadings": "[[Special:Preferences]], tab 'Misc'. Offers numbered headings on content pages to user. {{Gender}}",
-       "tog-showtoolbar": "{{Gender}}\n[[Special:Preferences]], tab 'Edit'. Offers user to show edit toolbar in page edit screen.\n\nThis is the toolbar: [[Image:Toolbar.png]]",
        "tog-editondblclick": "{{Gender}}\n[[Special:Preferences]], tab 'Edit'. Offers user to open edit page on double click.",
        "tog-editsectiononrightclick": "{{Gender}}\n[[Special:Preferences]], tab 'Edit'. Offers user to edit a section by clicking on a section title.",
        "tog-watchcreations": "[[Special:Preferences]], tab 'Watchlist'. Offers user to add created pages to watchlist. {{Gender}}",
        "subject-preview": "Used as label for preview of the section title when adding a new section on a talk page.\n\nShould match {{msg-mw|subject}}.\n\nSee also:\n* {{msg-mw|Summary-preview}}\n\n{{Identical|Subject}}",
        "previewerrortext": "When a user has the editing preference LivePreview enabled, clicked the Preview or Show Changes button in the edit page and the action did not succeed.",
        "blockedtitle": "Used as title displayed for blocked users. The corresponding message body is one of the following messages:\n* {{msg-mw|Blockedtext|notext=1}}\n* {{msg-mw|Autoblockedtext|notext=1}}\n* {{msg-mw|Systemblockedtext}}",
 +      "blocked-email-user": "Text displayed to partially blocked users that are blocked from sending email.\n\n\"email this user\" should be consistent with {{msg-mw|Emailuser}}.\n\nParameters:\n* $1 - the blocking sysop (with a link to his/her userpage)\n* $2 - the reason for the block\n* $3 - the current IP address of the blocked user\n* $4 - (Unused) the blocking sysop's username (plain text, without the link)\n* $5 - the unique numeric identifier of the applied autoblock\n* $6 - the expiry of the block\n* $7 - the intended target of the block (what the blocking user specified in the blocking form)\n* $8 - the timestamp when the block started\nSee also:\n* {{msg-mw|Grouppage-sysop}}\n* {{msg-mw|Autoblockedtext}}\n* {{msg-mw|Systemblockedtext}}",
 +      "blockedtext-partial": "Text displayed to partially blocked users.\n\n\"email this user\" should be consistent with {{msg-mw|Emailuser}}.\n\nParameters:\n* $1 - the blocking sysop (with a link to his/her userpage)\n* $2 - the reason for the block\n* $3 - the current IP address of the blocked user\n* $4 - (Unused) the blocking sysop's username (plain text, without the link)\n* $5 - the unique numeric identifier of the applied autoblock\n* $6 - the expiry of the block\n* $7 - the intended target of the block (what the blocking user specified in the blocking form)\n* $8 - the timestamp when the block started\nSee also:\n* {{msg-mw|Grouppage-sysop}}\n* {{msg-mw|Autoblockedtext}}\n* {{msg-mw|Systemblockedtext}}",
        "blockedtext": "Text displayed to blocked users.\n\n\"email this user\" should be consistent with {{msg-mw|Emailuser}}.\n\nParameters:\n* $1 - the blocking sysop (with a link to his/her userpage)\n* $2 - the reason for the block\n* $3 - the current IP address of the blocked user\n* $4 - (Unused) the blocking sysop's username (plain text, without the link)\n* $5 - the unique numeric identifier of the applied autoblock\n* $6 - the expiry of the block\n* $7 - the intended target of the block (what the blocking user specified in the blocking form)\n* $8 - the timestamp when the block started\nSee also:\n* {{msg-mw|Grouppage-sysop}}\n* {{msg-mw|Autoblockedtext}}\n* {{msg-mw|Systemblockedtext}}",
        "autoblockedtext": "Text displayed to automatically blocked users.\n\n\"email this user\" should be consistent with {{msg-mw|Emailuser}}.\n\nParameters:\n* $1 - the blocking sysop (with a link to his/her userpage)\n* $2 - the reason for the block (in case of autoblocks: {{msg-mw|autoblocker}})\n* $3 - the current IP address of the blocked user\n* $4 - (Unused) the blocking sysop's username (plain text, without the link). Use it for GENDER.\n* $5 - the unique numeric identifier of the applied autoblock\n* $6 - the expiry of the block\n* $7 - the intended target of the block (what the blocking user specified in the blocking form)\n* $8 - the timestamp when the block started\nSee also:\n* {{msg-mw|Grouppage-sysop}}\n* {{msg-mw|Blockedtext}}\n* {{msg-mw|Systemblockedtext}}",
        "systemblockedtext": "Text displayed to requests blocked by MediaWiki configuration.\n\n\"email this user\" should be consistent with {{msg-mw|Emailuser}}.\n\nParameters:\n* $1 - (Unused) A dummy user attributed as the blocker, possibly as a link to a user page.\n* $2 - the reason for the block\n* $3 - the current IP address of the blocked user\n* $4 - (Unused) the dummy blocking user's username (plain text, without the link).\n* $5 - A short string indicating the type of system block.\n* $6 - the expiry of the block\n* $7 - the intended target of the block\n* $8 - the timestamp when the block started\nSee also:\n* {{msg-mw|Grouppage-sysop}}\n* {{msg-mw|Blockedtext}}\n* {{msg-mw|Autoblockedtext}}",
        "ipb-disableusertalk": "{{doc-singularthey}}\nUsed as label for checkbox in [[Special:Block]].\n\nSee also:\n* {{msg-mw|ipbemailban}}\n* {{msg-mw|ipbenableautoblock}}\n* {{msg-mw|ipbhidename}}\n* {{msg-mw|ipbwatchuser}}\n* {{msg-mw|ipb-hardblock}}",
        "ipb-change-block": "Confirmation checkbox required for blocks that would override an earlier block. Appears together with {{msg-mw|ipb-needreblock}}.",
        "ipb-confirm": "Used as hidden field in the form on [[Special:Block]].",
 +      "ipb-sitewide": "A type of block the user can select from on [[Special:Block]].",
 +      "ipb-partial": "A type of block the user can select from on [[Special:Block]].",
 +      "ipb-type-label": "The label of the type of editing restriction the admin would like to impose on [[Special:Block]].",
 +      "ipb-pages-label": "The label for a autocomplete text field to specify pages to block a user from editing on [[Special:Block]].",
        "badipaddress": "An error message shown when one entered an invalid IP address in blocking page.",
        "blockipsuccesssub": "Used as page title in [[Special:Block]].\n\nThis message is the subject for the following message:\n* {{msg-mw|Blockipsuccesstext}}",
        "blockipsuccesstext": "Used in [[Special:Block]].\nThe title (subject) for this message is {{msg-mw|Blockipsuccesssub}}.\n\nParameters:\n* $1 - username, can be used for GENDER",
        "logentry-block-block": "{{Logentry|[[Special:Log/block]]}}\n* $4 - user name for gender or empty string for autoblocks\n* $5 - the block duration, localized and formatted with the english tooltip\n* $6 - block detail flags or empty string\n\nCf. {{msg-mw|Blocklogentry}}",
        "logentry-block-unblock": "{{Logentry|[[Special:Log/block]]}}\n* $4 - user name for gender or empty string for autoblocks\n\nCf. {{msg-mw|Unblocklogentry}}",
        "logentry-block-reblock": "{{Logentry|[[Special:Log/block]]}}\n* $4 - user name for gender or empty string for autoblocks\n* $5 - the block duration, localized and formatted with the english tooltip\n* $6 - block detail flags or empty string\n\nCf. {{msg-mw|Reblock-logentry}}",
 +      "logentry-partialblock-block": "{{Logentry|[[Special:Log/block]]}}\n* $4 - user name for gender or empty string for autoblocks\n* $5 - the block duration, localized and formatted with the english tooltip\n* $6 - block detail flags or empty string\n* $7 - list of pages separated by a comma\n* $8 - total number of pages\n\nCf. {{msg-mw|Blocklogentry}}",
 +      "logentry-partialblock-reblock": "{{Logentry|[[Special:Log/block]]}}\n* $4 - user name for gender or empty string for autoblocks\n* $5 - the block duration, localized and formatted with the english tooltip\n* $6 - block detail flags or empty string\n* $7 - list of pages separated by a comma\n* $8 - total number of pages\n\nCf. {{msg-mw|Reblock-logentry}}",
 +      "logentry-non-editing-block-block": "{{Logentry|[[Special:Log/block]]}}\n* $4 - user name for gender or empty string for autoblocks\n* $5 - the block duration, localized and formatted with the english tooltip\n* $6 - block detail flags or empty string\n\nCf. {{msg-mw|Blocklogentry}}",
 +      "logentry-non-editing-block-reblock": "{{Logentry|[[Special:Log/block]]}}\n* $4 - user name for gender or empty string for autoblocks\n* $5 - the block duration, localized and formatted with the english tooltip\n* $6 - block detail flags or empty string\n\nCf. {{msg-mw|Reblock-logentry}}",
        "logentry-suppress-block": "{{Logentry}}\n* $4 - user name for gender or empty string for autoblocks\n* $5 - the block duration, localized and formatted with the english tooltip\n* $6 - block detail flags or empty string",
        "logentry-suppress-reblock": "{{Logentry}}\n* $4 - user name for gender or empty string for autoblocks\n* $5 - the block duration, localized and formatted with the english tooltip\n* $6 - block detail flags or empty string",
        "logentry-import-upload": "{{Logentry|[[Special:Log/import]]}}",
        "mw-widgets-titleinput-description-redirect": "Description label for a redirect in the title input widget.",
        "mw-widgets-categoryselector-add-category-placeholder": "Placeholder displayed in the category selector widget after the capsules of already added categories.",
        "mw-widgets-usersmultiselect-placeholder": "Placeholder displayed in the input field, where new usernames are entered",
 +      "mw-widgets-titlesmultiselect-placeholder": "Placeholder displayed in the input field, where new titles are entered",
        "date-range-from": "Label for an input field that specifies the start date of a date range filter.",
        "date-range-to": "Label for an input field that specifies the end date of a date range filter.",
        "sessionmanager-tie": "Used as an error message when multiple session sources are tied in priority.\n\nParameters:\n* $1 - List of dession type descriptions, from messages like {{msg-mw|sessionprovider-mediawiki-session-cookiesessionprovider}}.",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "Password policy that enforces that passwords are not on a list of blacklisted passwords (often previously used during MediaWiki automated testing)",
        "passwordpolicies-policy-maximalpasswordlength": "Password policy that enforces a maximum number of characters a password must be. $1 - maximum number of characters that a password can be",
        "passwordpolicies-policy-passwordcannotbepopular": "Password policy that enforces that a password is not in a list of $1 number of \"popular\" passwords. $1 - number of popular passwords the password will be checked against",
 -      "easydeflate-invaliddeflate": "Error message if the content passed to easydeflate was not deflated (compressed) properly"
 +      "easydeflate-invaliddeflate": "Error message if the content passed to easydeflate was not deflated (compressed) properly",
 +      "unprotected-js": "Error message shown when trying to load javascript via action=raw that is not protected"
  }
diff --combined resources/Resources.php
@@@ -1394,12 -1394,6 +1394,6 @@@ return 
                'dependencies' => 'jquery.cookie',
                'targets' => [ 'desktop', 'mobile' ],
        ],
-       'mediawiki.toolbar' => [
-               'class' => ResourceLoaderEditToolbarModule::class,
-               'scripts' => 'resources/src/mediawiki.toolbar/toolbar.js',
-               'styles' => 'resources/src/mediawiki.toolbar/toolbar.less',
-               'dependencies' => 'jquery.textSelection',
-       ],
        'mediawiki.experiments' => [
                'scripts' => 'resources/src/mediawiki.experiments.js',
                'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.special.block' => [
                'scripts' => 'resources/src/mediawiki.special.block.js',
 +              'styles' => 'resources/src/mediawiki.special.block.less',
                'dependencies' => [
                        'oojs-ui-core',
                        'oojs-ui.styles.icons-editing-core',
                        'mediawiki.htmlform',
                        'moment',
                ],
 +              'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.special.changecredentials.js' => [
                'scripts' => 'resources/src/mediawiki.special.changecredentials.js',
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
 +      'mediawiki.widgets.TitlesMultiselectWidget' => [
 +              'scripts' => [
 +                      'resources/src/mediawiki.widgets/mw.widgets.TitlesMultiselectWidget.js',
 +              ],
 +              'dependencies' => [
 +                      'mediawiki.api',
 +                      'oojs-ui-widgets',
 +                      // FIXME: Needs TitleInputWidget only
 +                      'mediawiki.widgets',
 +              ],
 +              'targets' => [ 'desktop', 'mobile' ],
 +      ],
        'mediawiki.widgets.SearchInputWidget' => [
                'scripts' => [
                        'resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js',