From 8aa8ce1ffbcca9c727f46e58c714e1d351f7ef88 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Fri, 9 Sep 2022 07:26:42 +0100
Subject: [PATCH] Issue #3278415 by nod_, lauriii, catch, Wim Leers, longwave,
 xjm, claudiu.cristea: Remove usages of the JavaScript ES6 build step, the
 build step itself, and associated dev dependencies

---
 core/.eslintignore                            |   11 +-
 core/.prettierignore                          |   10 +-
 core/misc/active-link.es6.js                  |   72 -
 core/misc/active-link.js                      |   61 +-
 core/misc/ajax.es6.js                         | 1740 -----------------
 core/misc/ajax.js                             | 1390 +++++++++++--
 core/misc/announce.es6.js                     |  117 --
 core/misc/announce.js                         |   83 +-
 core/misc/autocomplete.es6.js                 |  286 ---
 core/misc/autocomplete.js                     |  185 +-
 core/misc/batch.es6.js                        |   47 -
 core/misc/batch.js                            |   28 +-
 core/misc/checkbox.es6.js                     |   15 -
 core/misc/checkbox.js                         |   21 +-
 core/misc/collapse.es6.js                     |  155 --
 core/misc/collapse.js                         |  163 +-
 core/misc/debounce.es6.js                     |   48 -
 core/misc/debounce.js                         |   44 +-
 core/misc/details-aria.es6.js                 |   32 -
 core/misc/details-aria.js                     |   40 +-
 core/misc/details-summarized-content.es6.js   |  105 -
 core/misc/details-summarized-content.js       |  113 +-
 core/misc/dialog/dialog.ajax.es6.js           |  249 ---
 core/misc/dialog/dialog.ajax.js               |  183 +-
 core/misc/dialog/dialog.es6.js                |   97 -
 core/misc/dialog/dialog.jquery-ui.es6.js      |   75 -
 core/misc/dialog/dialog.jquery-ui.js          |   46 +-
 core/misc/dialog/dialog.js                    |   72 +-
 core/misc/dialog/dialog.position.es6.js       |  140 --
 core/misc/dialog/dialog.position.js           |  132 +-
 .../dialog/off-canvas/js/off-canvas.es6.js    |  361 ----
 core/misc/dialog/off-canvas/js/off-canvas.js  |  305 ++-
 core/misc/displace.es6.js                     |  267 ---
 core/misc/displace.js                         |  200 +-
 core/misc/dropbutton/dropbutton.es6.js        |  236 ---
 core/misc/dropbutton/dropbutton.js            |  245 ++-
 core/misc/drupal.es6.js                       |  655 -------
 core/misc/drupal.init.es6.js                  |   34 -
 core/misc/drupal.init.js                      |   23 +-
 core/misc/drupal.js                           |  547 +++++-
 core/misc/drupalSettingsLoader.es6.js         |   24 -
 core/misc/drupalSettingsLoader.js             |   23 +-
 core/misc/entity-form.es6.js                  |   71 -
 core/misc/entity-form.js                      |   86 +-
 core/misc/form.es6.js                         |  325 ---
 core/misc/form.js                             |  263 ++-
 core/misc/jquery.tabbable.shim.es6.js         |   28 -
 core/misc/jquery.tabbable.shim.js             |   28 +-
 core/misc/machine-name.es6.js                 |  237 ---
 core/misc/machine-name.js                     |  161 +-
 core/misc/message.es6.js                      |  254 ---
 core/misc/message.js                          |  221 ++-
 core/misc/position.es6.js                     |  628 ------
 core/misc/position.js                         |  438 +++--
 core/misc/progress.es6.js                     |  180 --
 core/misc/progress.js                         |  244 ++-
 core/misc/states.es6.js                       |  736 -------
 core/misc/states.js                           |  540 ++++-
 core/misc/tabbingmanager.es6.js               |  412 ----
 core/misc/tabbingmanager.js                   |  547 ++++--
 core/misc/tabledrag.es6.js                    | 1711 ----------------
 core/misc/tabledrag.js                        | 1311 ++++++++++---
 core/misc/tableheader.es6.js                  |  335 ----
 core/misc/tableheader.js                      |  366 +++-
 core/misc/tableresponsive.es6.js              |  194 --
 core/misc/tableresponsive.js                  |  247 ++-
 core/misc/tableselect.es6.js                  |  177 --
 core/misc/tableselect.js                      |  173 +-
 core/misc/timezone.es6.js                     |   84 -
 core/misc/timezone.js                         |   62 +-
 core/misc/touchevents-test.es6.js             |   11 -
 core/misc/touchevents-test.js                 |   15 +-
 core/misc/vertical-tabs.es6.js                |  300 ---
 core/misc/vertical-tabs.js                    |  291 ++-
 core/modules/big_pipe/js/big_pipe.es6.js      |  137 --
 core/modules/big_pipe/js/big_pipe.js          |   85 +-
 core/modules/block/js/block.admin.es6.js      |  109 --
 core/modules/block/js/block.admin.js          |   85 +-
 core/modules/block/js/block.es6.js            |  262 ---
 core/modules/block/js/block.js                |  233 ++-
 core/modules/book/book.es6.js                 |   33 -
 core/modules/book/book.js                     |   47 +-
 .../ckeditor5/js/ckeditor5.admin.es6.js       | 1069 ----------
 core/modules/ckeditor5/js/ckeditor5.admin.js  | 1080 +++++++---
 .../ckeditor5/js/ckeditor5.dialog.fix.es6.js  |   18 -
 .../ckeditor5/js/ckeditor5.dialog.fix.js      |   21 +-
 core/modules/ckeditor5/js/ckeditor5.es6.js    |  637 ------
 .../js/ckeditor5.filter.admin.es6.js          |   74 -
 .../ckeditor5/js/ckeditor5.filter.admin.js    |   75 +-
 core/modules/ckeditor5/js/ckeditor5.js        |  563 ++++--
 .../ckeditor5/js/ckeditor5.style.admin.es6.js |   39 -
 .../ckeditor5/js/ckeditor5.style.admin.js     |   49 +-
 .../Tests/drupalHtmlBuilderTest.es6.js        |  131 --
 .../Nightwatch/Tests/drupalHtmlBuilderTest.js |  124 +-
 .../comment/comment-entity-form.es6.js        |   25 -
 core/modules/comment/comment-entity-form.js   |   27 +-
 .../comment/js/comment-by-viewer.es6.js       |   25 -
 core/modules/comment/js/comment-by-viewer.js  |   29 +-
 .../comment/js/comment-new-indicator.es6.js   |  103 -
 .../comment/js/comment-new-indicator.js       |   75 +-
 .../comment/js/node-new-comments-link.es6.js  |  195 --
 .../comment/js/node-new-comments-link.js      |  149 +-
 .../content_translation.admin.es6.js          |  137 --
 .../content_translation.admin.js              |  125 +-
 core/modules/contextual/js/contextual.es6.js  |  321 ---
 core/modules/contextual/js/contextual.js      |  280 ++-
 .../contextual/js/contextual.toolbar.es6.js   |   86 -
 .../contextual/js/contextual.toolbar.js       |   76 +-
 .../contextual/js/models/StateModel.es6.js    |  130 --
 .../contextual/js/models/StateModel.js        |  160 +-
 .../js/toolbar/models/StateModel.es6.js       |  126 --
 .../js/toolbar/models/StateModel.js           |  153 +-
 .../js/toolbar/views/AuralView.es6.js         |  122 --
 .../contextual/js/toolbar/views/AuralView.js  |  164 +-
 .../js/toolbar/views/VisualView.es6.js        |   85 -
 .../contextual/js/toolbar/views/VisualView.js |  114 +-
 .../contextual/js/views/AuralView.es6.js      |   59 -
 core/modules/contextual/js/views/AuralView.js |   78 +-
 .../contextual/js/views/KeyboardView.es6.js   |   62 -
 .../contextual/js/views/KeyboardView.js       |   84 +-
 .../contextual/js/views/RegionView.es6.js     |   75 -
 .../modules/contextual/js/views/RegionView.js |  107 +-
 .../contextual/js/views/VisualView.es6.js     |  109 --
 .../modules/contextual/js/views/VisualView.js |  153 +-
 core/modules/editor/js/editor.admin.es6.js    | 1037 ----------
 core/modules/editor/js/editor.admin.js        |  848 +++++++-
 core/modules/editor/js/editor.dialog.es6.js   |   34 -
 core/modules/editor/js/editor.dialog.js       |   36 +-
 core/modules/editor/js/editor.es6.js          |  335 ----
 core/modules/editor/js/editor.js              |  254 ++-
 core/modules/field_ui/field_ui.es6.js         |  386 ----
 core/modules/field_ui/field_ui.js             |  308 ++-
 core/modules/file/file.es6.js                 |  299 ---
 core/modules/file/file.js                     |  252 ++-
 core/modules/filter/filter.admin.es6.js       |   74 -
 core/modules/filter/filter.admin.js           |   56 +-
 core/modules/filter/filter.es6.js             |   39 -
 .../filter/filter.filter_html.admin.es6.js    |  393 ----
 .../filter/filter.filter_html.admin.js        |  335 +++-
 core/modules/filter/filter.js                 |   42 +-
 core/modules/filter/filter.module             |    2 +-
 .../src/Plugin/Filter/FilterCaption.php       |    2 +-
 core/modules/history/js/history.es6.js        |  146 --
 core/modules/history/js/history.js            |  118 +-
 core/modules/history/js/mark-as-read.es6.js   |   21 -
 core/modules/history/js/mark-as-read.js       |   21 +-
 core/modules/language/language.admin.es6.js   |   46 -
 core/modules/language/language.admin.js       |   50 +-
 .../layout_builder/js/layout-builder.es6.js   |  446 -----
 .../layout_builder/js/layout-builder.js       |  381 +++-
 core/modules/locale/locale.admin.es6.js       |  125 --
 core/modules/locale/locale.admin.js           |  101 +-
 core/modules/locale/locale.bulk.es6.js        |   37 -
 core/modules/locale/locale.bulk.js            |   32 +-
 core/modules/locale/tests/locale_test.es6.js  |   54 -
 core/modules/locale/tests/locale_test.js      |   76 +-
 .../LocaleJavascriptTranslationTest.php       |    6 +-
 core/modules/media/js/form.es6.js             |   40 -
 core/modules/media/js/form.js                 |   65 +-
 .../js/media_embed_ckeditor.theme.es6.js      |   19 -
 .../media/js/media_embed_ckeditor.theme.js    |   25 +-
 core/modules/media/js/type_form.es6.js        |   54 -
 core/modules/media/js/type_form.js            |   61 +-
 .../js/media_library.click_to_select.es6.js   |   65 -
 .../js/media_library.click_to_select.js       |   83 +-
 .../media_library/js/media_library.ui.es6.js  |  427 ----
 .../media_library/js/media_library.ui.js      |  387 +++-
 .../js/media_library.view.es6.js              |   49 -
 .../media_library/js/media_library.view.js    |   60 +-
 .../js/media_library.widget.es6.js            |  106 -
 .../media_library/js/media_library.widget.js  |   99 +-
 .../EntityReferenceWidgetTest.php             |    2 +-
 core/modules/menu_ui/menu_ui.admin.es6.js     |   70 -
 core/modules/menu_ui/menu_ui.admin.js         |   50 +-
 core/modules/menu_ui/menu_ui.es6.js           |   96 -
 core/modules/menu_ui/menu_ui.js               |   78 +-
 core/modules/node/content_types.es6.js        |   74 -
 core/modules/node/content_types.js            |   75 +-
 core/modules/node/node.es6.js                 |   57 -
 core/modules/node/node.js                     |   48 +-
 core/modules/node/node.preview.es6.js         |  116 --
 core/modules/node/node.preview.js             |  114 +-
 core/modules/path/path.es6.js                 |   29 -
 core/modules/path/path.js                     |   40 +-
 .../settings_tray/js/settings_tray.es6.js     |  260 ---
 .../modules/settings_tray/js/settings_tray.js |  213 +-
 .../settings_tray/settings_tray.api.php       |    2 +-
 core/modules/statistics/statistics.es6.js     |   15 -
 core/modules/statistics/statistics.js         |   12 +-
 core/modules/system/js/system.date.es6.js     |   69 -
 core/modules/system/js/system.date.js         |   63 +-
 core/modules/system/js/system.es6.js          |   82 -
 core/modules/system/js/system.js              |   72 +-
 core/modules/system/js/system.modules.es6.js  |  109 --
 core/modules/system/js/system.modules.js      |   68 +-
 .../ajax_test/js/command_promise-ajax.es6.js  |   31 -
 .../ajax_test/js/command_promise-ajax.js      |   28 +-
 .../modules/ajax_test/js/focus-ajax.es6.js    |   23 -
 .../tests/modules/ajax_test/js/focus-ajax.js  |   29 +-
 .../modules/ajax_test/js/insert-ajax.es6.js   |   41 -
 .../tests/modules/ajax_test/js/insert-ajax.js |   24 +-
 .../js/disable_transitions.theme.es6.js       |    3 -
 .../js/disable_transitions.theme.js           |    9 +-
 .../js/jquery.keyevent.polyfill.es6.js        |   52 -
 .../js/jquery.keyevent.polyfill.js            |   32 +-
 .../js/js_deprecation_test.es6.js             |   24 -
 .../js/js_deprecation_test.js                 |   34 +-
 .../js_errors_test/js/js_errors_test.es6.js   |   11 -
 .../js_errors_test/js/js_errors_test.js       |   19 +-
 .../js_interaction_test.trigger_link.es6.js   |   38 -
 .../js/js_interaction_test.trigger_link.js    |   39 +-
 .../js_message_test/js/js_message_test.es6.js |  126 --
 .../js_message_test/js/js_message_test.js     |  161 +-
 .../js/js_testing_log.es6.js                  |   35 -
 .../js_testing_log_test/js/js_testing_log.js  |   37 +-
 ...ebassert_test.no_element_after_wait.es6.js |   30 -
 ...js_webassert_test.no_element_after_wait.js |   24 +-
 ...ebassert_test.wait_for_ajax_request.es6.js |   24 -
 ...js_webassert_test.wait_for_ajax_request.js |   25 +-
 .../js_webassert_test.wait_for_element.es6.js |   18 -
 .../js/js_webassert_test.wait_for_element.js  |   19 +-
 .../off_canvas_test/js/resize-helper.es6.js   |   18 -
 .../off_canvas_test/js/resize-helper.js       |   26 +-
 .../modules/olivero_test/js/log-errors.es6.js |   10 -
 .../modules/olivero_test/js/log-errors.js     |   13 +-
 .../tabledrag_test/js/tabledrag_test.es6.js   |   23 -
 .../tabledrag_test/js/tabledrag_test.js       |   30 +-
 .../twig_theme_test/twig_theme_test.es6.js    |    6 -
 .../twig_theme_test/twig_theme_test.js        |   10 +-
 .../themes/test_theme/js/collapse.es6.js      |    4 -
 .../tests/themes/test_theme/js/collapse.js    |    8 +-
 core/modules/taxonomy/taxonomy.es6.js         |   62 -
 core/modules/taxonomy/taxonomy.js             |   50 +-
 core/modules/text/text.es6.js                 |   73 -
 core/modules/text/text.js                     |   71 +-
 core/modules/toolbar/js/escapeAdmin.es6.js    |   45 -
 core/modules/toolbar/js/escapeAdmin.js        |   34 +-
 .../toolbar/js/models/MenuModel.es6.js        |   29 -
 core/modules/toolbar/js/models/MenuModel.js   |   37 +-
 .../toolbar/js/models/ToolbarModel.es6.js     |  159 --
 .../modules/toolbar/js/models/ToolbarModel.js |  185 +-
 core/modules/toolbar/js/toolbar.es6.js        |  317 ---
 core/modules/toolbar/js/toolbar.js            |  316 ++-
 core/modules/toolbar/js/toolbar.menu.es6.js   |  204 --
 core/modules/toolbar/js/toolbar.menu.js       |  141 +-
 .../toolbar/js/views/BodyVisualView.es6.js    |   48 -
 .../toolbar/js/views/BodyVisualView.js        |   63 +-
 .../toolbar/js/views/MenuVisualView.es6.js    |   38 -
 .../toolbar/js/views/MenuVisualView.js        |   56 +-
 .../toolbar/js/views/ToolbarAuralView.es6.js  |   80 -
 .../toolbar/js/views/ToolbarAuralView.js      |  116 +-
 .../toolbar/js/views/ToolbarVisualView.es6.js |  387 ----
 .../toolbar/js/views/ToolbarVisualView.js     |  521 +++--
 .../tests/src/Nightwatch/Tests/toolbarTest.js |   20 +-
 core/modules/tour/js/tour.es6.js              |  414 ----
 core/modules/tour/js/tour.js                  |  507 +++--
 .../modules/tracker/js/tracker-history.es6.js |  149 --
 core/modules/tracker/js/tracker-history.js    |  115 +-
 core/modules/user/user.es6.js                 |  370 ----
 core/modules/user/user.js                     |  267 ++-
 core/modules/user/user.permissions.es6.js     |   92 -
 core/modules/user/user.permissions.js         |   76 +-
 core/modules/user/user.theme.es6.js           |   70 -
 core/modules/user/user.theme.js               |   81 +-
 core/modules/views/js/ajax_view.es6.js        |  236 ---
 core/modules/views/js/ajax_view.js            |  183 +-
 core/modules/views/js/base.es6.js             |  111 --
 core/modules/views/js/base.js                 |   81 +-
 .../views_test_data/views_cache.test.es6.js   |    8 -
 .../views_test_data/views_cache.test.js       |   12 +-
 core/modules/views_ui/js/ajax.es6.js          |  293 ---
 core/modules/views_ui/js/ajax.js              |  260 ++-
 core/modules/views_ui/js/dialog.views.es6.js  |   64 -
 core/modules/views_ui/js/dialog.views.js      |   52 +-
 core/modules/views_ui/js/views-admin.es6.js   | 1337 -------------
 core/modules/views_ui/js/views-admin.js       | 1399 +++++++++----
 .../views_ui/js/views_ui.listing.es6.js       |   57 -
 core/modules/views_ui/js/views_ui.listing.js  |   34 +-
 core/package.json                             |   45 +-
 .../classy/media_embed_ckeditor.theme.es6.js  |   22 -
 .../js/classy/media_embed_ckeditor.theme.js   |   28 +-
 .../navigation/menu-main/menu-main.es6.js     |   19 -
 .../navigation/menu-main/menu-main.js         |   14 +-
 core/scripts/css/postcss-build.js             |    4 +-
 core/scripts/dev/commit-code-check.sh         |   63 +-
 core/scripts/js/babel-es6-build.js            |   51 -
 core/scripts/js/babel-es6-watch.js            |   45 -
 core/scripts/js/changeOrAdded.js              |   15 -
 core/scripts/js/check.js                      |   22 -
 core/scripts/js/compile.js                    |   30 -
 .../Core/Theme/ConfirmClassyCopiesTest.php    |    5 +-
 .../Nightwatch/Commands/drupalInstall.js      |    6 +-
 .../Nightwatch/Commands/drupalLoginAsAdmin.js |    6 +-
 .../Nightwatch/Commands/drupalLogout.js       |    4 +-
 .../Nightwatch/Commands/drupalUninstall.js    |    4 +-
 .../Tests/jQueryUIPositionShimTest.js         |    2 +-
 core/tests/Drupal/Nightwatch/globals.js       |   17 +-
 .../Drupal/Nightwatch/nightwatch.conf.js      |    4 +-
 core/themes/claro/js/ajax.es6.js              |   45 -
 core/themes/claro/js/ajax.js                  |   49 +-
 core/themes/claro/js/autocomplete.es6.js      |   42 -
 core/themes/claro/js/autocomplete.js          |   62 +-
 core/themes/claro/js/checkbox.es6.js          |   15 -
 core/themes/claro/js/checkbox.js              |   21 +-
 .../classy/media_embed_ckeditor.theme.es6.js  |   22 -
 .../js/classy/media_embed_ckeditor.theme.js   |   28 +-
 core/themes/claro/js/details.es6.js           |   78 -
 core/themes/claro/js/details.js               |   88 +-
 core/themes/claro/js/dropbutton.es6.js        |   23 -
 core/themes/claro/js/dropbutton.js            |   29 +-
 core/themes/claro/js/media-library.ui.es6.js  |   72 -
 core/themes/claro/js/media-library.ui.js      |  103 +-
 core/themes/claro/js/messages.es6.js          |   50 -
 core/themes/claro/js/messages.js              |   46 +-
 core/themes/claro/js/mobile.install.es6.js    |   29 -
 core/themes/claro/js/mobile.install.js        |   13 +-
 core/themes/claro/js/nav-tabs.es6.js          |   88 -
 core/themes/claro/js/nav-tabs.js              |   43 +-
 .../themes/claro/js/responsive-details.es6.js |   51 -
 core/themes/claro/js/responsive-details.js    |   27 +-
 core/themes/claro/js/tabledrag.es6.js         |  247 ---
 core/themes/claro/js/tabledrag.js             |  269 ++-
 core/themes/claro/js/user.theme.es6.js        |   81 -
 core/themes/claro/js/user.theme.js            |   85 +-
 core/themes/claro/js/vertical-tabs.es6.js     |   41 -
 core/themes/claro/js/vertical-tabs.js         |   41 +-
 .../js/media_embed_ckeditor.theme.es6.js      |   22 -
 .../classy/js/media_embed_ckeditor.theme.js   |   28 +-
 core/themes/olivero/js/checkbox.es6.js        |   15 -
 core/themes/olivero/js/checkbox.js            |   21 +-
 core/themes/olivero/js/color-picker.es6.js    |  190 --
 core/themes/olivero/js/color-picker.js        |  155 +-
 core/themes/olivero/js/comments.es6.js        |   63 -
 core/themes/olivero/js/comments.js            |   59 +-
 core/themes/olivero/js/message.theme.es6.js   |   81 -
 core/themes/olivero/js/message.theme.js       |   68 +-
 core/themes/olivero/js/messages.es6.js        |   55 -
 core/themes/olivero/js/messages.js            |   43 +-
 core/themes/olivero/js/nav-resize.es6.js      |   86 -
 core/themes/olivero/js/nav-resize.js          |   78 +-
 .../themes/olivero/js/navigation-utils.es6.js |  222 ---
 core/themes/olivero/js/navigation-utils.js    |  158 +-
 core/themes/olivero/js/navigation.es6.js      |  167 --
 core/themes/olivero/js/navigation.js          |   99 +-
 core/themes/olivero/js/search.es6.js          |  155 --
 core/themes/olivero/js/search.js              |  107 +-
 .../olivero/js/second-level-navigation.es6.js |  203 --
 .../olivero/js/second-level-navigation.js     |  174 +-
 core/themes/olivero/js/tabs.es6.js            |   71 -
 core/themes/olivero/js/tabs.js                |   47 +-
 core/themes/stable/js/ajax.es6.js             |   17 -
 core/themes/stable/js/ajax.js                 |   23 +-
 core/themes/stable/js/tour.es6.js             |  139 --
 core/themes/stable/js/tour.js                 |   99 +-
 core/themes/stable/js/user.theme.es6.js       |   40 -
 core/themes/stable/js/user.theme.js           |   44 +-
 core/themes/stable9/js/tour.es6.js            |  139 --
 core/themes/stable9/js/tour.js                |   99 +-
 core/themes/stable9/js/user.theme.es6.js      |   49 -
 core/themes/stable9/js/user.theme.js          |   55 +-
 core/yarn.lock                                |  915 +--------
 361 files changed, 18944 insertions(+), 35047 deletions(-)
 delete mode 100644 core/misc/active-link.es6.js
 delete mode 100644 core/misc/ajax.es6.js
 delete mode 100644 core/misc/announce.es6.js
 delete mode 100644 core/misc/autocomplete.es6.js
 delete mode 100644 core/misc/batch.es6.js
 delete mode 100644 core/misc/checkbox.es6.js
 delete mode 100644 core/misc/collapse.es6.js
 delete mode 100644 core/misc/debounce.es6.js
 delete mode 100644 core/misc/details-aria.es6.js
 delete mode 100644 core/misc/details-summarized-content.es6.js
 delete mode 100644 core/misc/dialog/dialog.ajax.es6.js
 delete mode 100644 core/misc/dialog/dialog.es6.js
 delete mode 100644 core/misc/dialog/dialog.jquery-ui.es6.js
 delete mode 100644 core/misc/dialog/dialog.position.es6.js
 delete mode 100644 core/misc/dialog/off-canvas/js/off-canvas.es6.js
 delete mode 100644 core/misc/displace.es6.js
 delete mode 100644 core/misc/dropbutton/dropbutton.es6.js
 delete mode 100644 core/misc/drupal.es6.js
 delete mode 100644 core/misc/drupal.init.es6.js
 delete mode 100644 core/misc/drupalSettingsLoader.es6.js
 delete mode 100644 core/misc/entity-form.es6.js
 delete mode 100644 core/misc/form.es6.js
 delete mode 100644 core/misc/jquery.tabbable.shim.es6.js
 delete mode 100644 core/misc/machine-name.es6.js
 delete mode 100644 core/misc/message.es6.js
 delete mode 100644 core/misc/position.es6.js
 delete mode 100644 core/misc/progress.es6.js
 delete mode 100644 core/misc/states.es6.js
 delete mode 100644 core/misc/tabbingmanager.es6.js
 delete mode 100644 core/misc/tabledrag.es6.js
 delete mode 100644 core/misc/tableheader.es6.js
 delete mode 100644 core/misc/tableresponsive.es6.js
 delete mode 100644 core/misc/tableselect.es6.js
 delete mode 100644 core/misc/timezone.es6.js
 delete mode 100644 core/misc/touchevents-test.es6.js
 delete mode 100644 core/misc/vertical-tabs.es6.js
 delete mode 100644 core/modules/big_pipe/js/big_pipe.es6.js
 delete mode 100644 core/modules/block/js/block.admin.es6.js
 delete mode 100644 core/modules/block/js/block.es6.js
 delete mode 100644 core/modules/book/book.es6.js
 delete mode 100644 core/modules/ckeditor5/js/ckeditor5.admin.es6.js
 delete mode 100644 core/modules/ckeditor5/js/ckeditor5.dialog.fix.es6.js
 delete mode 100644 core/modules/ckeditor5/js/ckeditor5.es6.js
 delete mode 100644 core/modules/ckeditor5/js/ckeditor5.filter.admin.es6.js
 delete mode 100644 core/modules/ckeditor5/js/ckeditor5.style.admin.es6.js
 delete mode 100644 core/modules/ckeditor5/tests/src/Nightwatch/Tests/drupalHtmlBuilderTest.es6.js
 delete mode 100644 core/modules/comment/comment-entity-form.es6.js
 delete mode 100644 core/modules/comment/js/comment-by-viewer.es6.js
 delete mode 100644 core/modules/comment/js/comment-new-indicator.es6.js
 delete mode 100644 core/modules/comment/js/node-new-comments-link.es6.js
 delete mode 100644 core/modules/content_translation/content_translation.admin.es6.js
 delete mode 100644 core/modules/contextual/js/contextual.es6.js
 delete mode 100644 core/modules/contextual/js/contextual.toolbar.es6.js
 delete mode 100644 core/modules/contextual/js/models/StateModel.es6.js
 delete mode 100644 core/modules/contextual/js/toolbar/models/StateModel.es6.js
 delete mode 100644 core/modules/contextual/js/toolbar/views/AuralView.es6.js
 delete mode 100644 core/modules/contextual/js/toolbar/views/VisualView.es6.js
 delete mode 100644 core/modules/contextual/js/views/AuralView.es6.js
 delete mode 100644 core/modules/contextual/js/views/KeyboardView.es6.js
 delete mode 100644 core/modules/contextual/js/views/RegionView.es6.js
 delete mode 100644 core/modules/contextual/js/views/VisualView.es6.js
 delete mode 100644 core/modules/editor/js/editor.admin.es6.js
 delete mode 100644 core/modules/editor/js/editor.dialog.es6.js
 delete mode 100644 core/modules/editor/js/editor.es6.js
 delete mode 100644 core/modules/field_ui/field_ui.es6.js
 delete mode 100644 core/modules/file/file.es6.js
 delete mode 100644 core/modules/filter/filter.admin.es6.js
 delete mode 100644 core/modules/filter/filter.es6.js
 delete mode 100644 core/modules/filter/filter.filter_html.admin.es6.js
 delete mode 100644 core/modules/history/js/history.es6.js
 delete mode 100644 core/modules/history/js/mark-as-read.es6.js
 delete mode 100644 core/modules/language/language.admin.es6.js
 delete mode 100644 core/modules/layout_builder/js/layout-builder.es6.js
 delete mode 100644 core/modules/locale/locale.admin.es6.js
 delete mode 100644 core/modules/locale/locale.bulk.es6.js
 delete mode 100644 core/modules/locale/tests/locale_test.es6.js
 delete mode 100644 core/modules/media/js/form.es6.js
 delete mode 100644 core/modules/media/js/media_embed_ckeditor.theme.es6.js
 delete mode 100644 core/modules/media/js/type_form.es6.js
 delete mode 100644 core/modules/media_library/js/media_library.click_to_select.es6.js
 delete mode 100644 core/modules/media_library/js/media_library.ui.es6.js
 delete mode 100644 core/modules/media_library/js/media_library.view.es6.js
 delete mode 100644 core/modules/media_library/js/media_library.widget.es6.js
 delete mode 100644 core/modules/menu_ui/menu_ui.admin.es6.js
 delete mode 100644 core/modules/menu_ui/menu_ui.es6.js
 delete mode 100644 core/modules/node/content_types.es6.js
 delete mode 100644 core/modules/node/node.es6.js
 delete mode 100644 core/modules/node/node.preview.es6.js
 delete mode 100644 core/modules/path/path.es6.js
 delete mode 100644 core/modules/settings_tray/js/settings_tray.es6.js
 delete mode 100644 core/modules/statistics/statistics.es6.js
 delete mode 100644 core/modules/system/js/system.date.es6.js
 delete mode 100644 core/modules/system/js/system.es6.js
 delete mode 100644 core/modules/system/js/system.modules.es6.js
 delete mode 100644 core/modules/system/tests/modules/ajax_test/js/command_promise-ajax.es6.js
 delete mode 100644 core/modules/system/tests/modules/ajax_test/js/focus-ajax.es6.js
 delete mode 100644 core/modules/system/tests/modules/ajax_test/js/insert-ajax.es6.js
 delete mode 100644 core/modules/system/tests/modules/css_disable_transitions_test/js/disable_transitions.theme.es6.js
 delete mode 100644 core/modules/system/tests/modules/jquery_keyevent_polyfilll_test/js/jquery.keyevent.polyfill.es6.js
 delete mode 100644 core/modules/system/tests/modules/js_deprecation_test/js/js_deprecation_test.es6.js
 delete mode 100644 core/modules/system/tests/modules/js_errors_test/js/js_errors_test.es6.js
 delete mode 100644 core/modules/system/tests/modules/js_interaction_test/js/js_interaction_test.trigger_link.es6.js
 delete mode 100644 core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js
 delete mode 100644 core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.es6.js
 delete mode 100644 core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.es6.js
 delete mode 100644 core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_ajax_request.es6.js
 delete mode 100644 core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_element.es6.js
 delete mode 100644 core/modules/system/tests/modules/off_canvas_test/js/resize-helper.es6.js
 delete mode 100644 core/modules/system/tests/modules/olivero_test/js/log-errors.es6.js
 delete mode 100644 core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.es6.js
 delete mode 100644 core/modules/system/tests/modules/twig_theme_test/twig_theme_test.es6.js
 delete mode 100644 core/modules/system/tests/themes/test_theme/js/collapse.es6.js
 delete mode 100644 core/modules/taxonomy/taxonomy.es6.js
 delete mode 100644 core/modules/text/text.es6.js
 delete mode 100644 core/modules/toolbar/js/escapeAdmin.es6.js
 delete mode 100644 core/modules/toolbar/js/models/MenuModel.es6.js
 delete mode 100644 core/modules/toolbar/js/models/ToolbarModel.es6.js
 delete mode 100644 core/modules/toolbar/js/toolbar.es6.js
 delete mode 100644 core/modules/toolbar/js/toolbar.menu.es6.js
 delete mode 100644 core/modules/toolbar/js/views/BodyVisualView.es6.js
 delete mode 100644 core/modules/toolbar/js/views/MenuVisualView.es6.js
 delete mode 100644 core/modules/toolbar/js/views/ToolbarAuralView.es6.js
 delete mode 100644 core/modules/toolbar/js/views/ToolbarVisualView.es6.js
 delete mode 100644 core/modules/tour/js/tour.es6.js
 delete mode 100644 core/modules/tracker/js/tracker-history.es6.js
 delete mode 100644 core/modules/user/user.es6.js
 delete mode 100644 core/modules/user/user.permissions.es6.js
 delete mode 100644 core/modules/user/user.theme.es6.js
 delete mode 100644 core/modules/views/js/ajax_view.es6.js
 delete mode 100644 core/modules/views/js/base.es6.js
 delete mode 100644 core/modules/views/tests/modules/views_test_data/views_cache.test.es6.js
 delete mode 100644 core/modules/views_ui/js/ajax.es6.js
 delete mode 100644 core/modules/views_ui/js/dialog.views.es6.js
 delete mode 100644 core/modules/views_ui/js/views-admin.es6.js
 delete mode 100644 core/modules/views_ui/js/views_ui.listing.es6.js
 delete mode 100644 core/profiles/demo_umami/themes/umami/js/classy/media_embed_ckeditor.theme.es6.js
 delete mode 100644 core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js
 delete mode 100644 core/scripts/js/babel-es6-build.js
 delete mode 100644 core/scripts/js/babel-es6-watch.js
 delete mode 100644 core/scripts/js/changeOrAdded.js
 delete mode 100644 core/scripts/js/check.js
 delete mode 100644 core/scripts/js/compile.js
 delete mode 100644 core/themes/claro/js/ajax.es6.js
 delete mode 100644 core/themes/claro/js/autocomplete.es6.js
 delete mode 100644 core/themes/claro/js/checkbox.es6.js
 delete mode 100644 core/themes/claro/js/classy/media_embed_ckeditor.theme.es6.js
 delete mode 100644 core/themes/claro/js/details.es6.js
 delete mode 100644 core/themes/claro/js/dropbutton.es6.js
 delete mode 100644 core/themes/claro/js/media-library.ui.es6.js
 delete mode 100644 core/themes/claro/js/messages.es6.js
 delete mode 100644 core/themes/claro/js/mobile.install.es6.js
 delete mode 100644 core/themes/claro/js/nav-tabs.es6.js
 delete mode 100644 core/themes/claro/js/responsive-details.es6.js
 delete mode 100644 core/themes/claro/js/tabledrag.es6.js
 delete mode 100644 core/themes/claro/js/user.theme.es6.js
 delete mode 100644 core/themes/claro/js/vertical-tabs.es6.js
 delete mode 100644 core/themes/classy/js/media_embed_ckeditor.theme.es6.js
 delete mode 100644 core/themes/olivero/js/checkbox.es6.js
 delete mode 100644 core/themes/olivero/js/color-picker.es6.js
 delete mode 100644 core/themes/olivero/js/comments.es6.js
 delete mode 100644 core/themes/olivero/js/message.theme.es6.js
 delete mode 100644 core/themes/olivero/js/messages.es6.js
 delete mode 100644 core/themes/olivero/js/nav-resize.es6.js
 delete mode 100644 core/themes/olivero/js/navigation-utils.es6.js
 delete mode 100644 core/themes/olivero/js/navigation.es6.js
 delete mode 100644 core/themes/olivero/js/search.es6.js
 delete mode 100644 core/themes/olivero/js/second-level-navigation.es6.js
 delete mode 100644 core/themes/olivero/js/tabs.es6.js
 delete mode 100644 core/themes/stable/js/ajax.es6.js
 delete mode 100644 core/themes/stable/js/tour.es6.js
 delete mode 100644 core/themes/stable/js/user.theme.es6.js
 delete mode 100644 core/themes/stable9/js/tour.es6.js
 delete mode 100644 core/themes/stable9/js/user.theme.es6.js

diff --git a/core/.eslintignore b/core/.eslintignore
index 7f26db1ea68b..3fbb72c37d45 100644
--- a/core/.eslintignore
+++ b/core/.eslintignore
@@ -1,14 +1,15 @@
 assets/vendor/**/*
 node_modules/**/*
 **/js_test_files/**/*
-*.js
-!*.es6.js
-!modules/ckeditor5/js/ckeditor5_plugins/**/*.js
-modules/locale/tests/locale_test.es6.js
-!tests/Drupal/Nightwatch/**/*.js
+**/build/**/*
+modules/locale/tests/locale_test.js
 
 # Ignore deliberately malformed YAML files.
 modules/system/tests/fixtures/HtaccessTest/access_test.yml
 modules/system/tests/themes/test_theme_libraries_empty/test_theme_libraries_empty.info.yml
 tests/Drupal/Tests/Core/Asset/library_test_files/empty.libraries.yml
 tests/Drupal/Tests/Core/Asset/library_test_files/invalid_file.libraries.yml
+
+# Temporary until they are brought up to standards
+scripts/**/*
+modules/ckeditor5/webpack.config.js
diff --git a/core/.prettierignore b/core/.prettierignore
index 352215fa7986..fdd0ba31134c 100644
--- a/core/.prettierignore
+++ b/core/.prettierignore
@@ -1,2 +1,10 @@
-modules/locale/tests/locale_test.es6.js
+assets/vendor/**/*
+node_modules/**/*
+**/build/**/*
+**/js_test_files/**/*
+modules/locale/tests/locale_test.js
 *.yml
+
+# Temporary until they are brought up to standards
+scripts/**/*
+modules/ckeditor5/webpack.config.js
diff --git a/core/misc/active-link.es6.js b/core/misc/active-link.es6.js
deleted file mode 100644
index d6bd9e4095ca..000000000000
--- a/core/misc/active-link.es6.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * @file
- * Attaches behaviors for Drupal's active link marking.
- */
-
-(function (Drupal, drupalSettings) {
-  /**
-   * Append is-active class.
-   *
-   * The link is only active if its path corresponds to the current path, the
-   * language of the linked path is equal to the current language, and if the
-   * query parameters of the link equal those of the current request, since the
-   * same request with different query parameters may yield a different page
-   * (e.g. pagers, exposed View filters).
-   *
-   * Does not discriminate based on element type, so allows you to set the
-   * is-active class on any element: a, li…
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.activeLinks = {
-    attach(context) {
-      // Start by finding all potentially active links.
-      const path = drupalSettings.path;
-      const queryString = JSON.stringify(path.currentQuery);
-      const querySelector = path.currentQuery
-        ? `[data-drupal-link-query='${queryString}']`
-        : ':not([data-drupal-link-query])';
-      const originalSelectors = [
-        `[data-drupal-link-system-path="${path.currentPath}"]`,
-      ];
-      let selectors;
-
-      // If this is the front page, we have to check for the <front> path as
-      // well.
-      if (path.isFront) {
-        originalSelectors.push('[data-drupal-link-system-path="<front>"]');
-      }
-
-      // Add language filtering.
-      selectors = [].concat(
-        // Links without any hreflang attributes (most of them).
-        originalSelectors.map((selector) => `${selector}:not([hreflang])`),
-        // Links with hreflang equals to the current language.
-        originalSelectors.map(
-          (selector) => `${selector}[hreflang="${path.currentLanguage}"]`,
-        ),
-      );
-
-      // Add query string selector for pagers, exposed filters.
-      selectors = selectors.map((current) => current + querySelector);
-
-      // Query the DOM.
-      const activeLinks = context.querySelectorAll(selectors.join(','));
-      const il = activeLinks.length;
-      for (let i = 0; i < il; i++) {
-        activeLinks[i].classList.add('is-active');
-      }
-    },
-    detach(context, settings, trigger) {
-      if (trigger === 'unload') {
-        const activeLinks = context.querySelectorAll(
-          '[data-drupal-link-system-path].is-active',
-        );
-        const il = activeLinks.length;
-        for (let i = 0; i < il; i++) {
-          activeLinks[i].classList.remove('is-active');
-        }
-      }
-    },
-  };
-})(Drupal, drupalSettings);
diff --git a/core/misc/active-link.js b/core/misc/active-link.js
index 2151d47124ad..d6bd9e4095ca 100644
--- a/core/misc/active-link.js
+++ b/core/misc/active-link.js
@@ -1,43 +1,72 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches behaviors for Drupal's active link marking.
+ */
 
 (function (Drupal, drupalSettings) {
+  /**
+   * Append is-active class.
+   *
+   * The link is only active if its path corresponds to the current path, the
+   * language of the linked path is equal to the current language, and if the
+   * query parameters of the link equal those of the current request, since the
+   * same request with different query parameters may yield a different page
+   * (e.g. pagers, exposed View filters).
+   *
+   * Does not discriminate based on element type, so allows you to set the
+   * is-active class on any element: a, li…
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.activeLinks = {
     attach(context) {
+      // Start by finding all potentially active links.
       const path = drupalSettings.path;
       const queryString = JSON.stringify(path.currentQuery);
-      const querySelector = path.currentQuery ? `[data-drupal-link-query='${queryString}']` : ':not([data-drupal-link-query])';
-      const originalSelectors = [`[data-drupal-link-system-path="${path.currentPath}"]`];
+      const querySelector = path.currentQuery
+        ? `[data-drupal-link-query='${queryString}']`
+        : ':not([data-drupal-link-query])';
+      const originalSelectors = [
+        `[data-drupal-link-system-path="${path.currentPath}"]`,
+      ];
       let selectors;
 
+      // If this is the front page, we have to check for the <front> path as
+      // well.
       if (path.isFront) {
         originalSelectors.push('[data-drupal-link-system-path="<front>"]');
       }
 
-      selectors = [].concat(originalSelectors.map(selector => `${selector}:not([hreflang])`), originalSelectors.map(selector => `${selector}[hreflang="${path.currentLanguage}"]`));
-      selectors = selectors.map(current => current + querySelector);
+      // Add language filtering.
+      selectors = [].concat(
+        // Links without any hreflang attributes (most of them).
+        originalSelectors.map((selector) => `${selector}:not([hreflang])`),
+        // Links with hreflang equals to the current language.
+        originalSelectors.map(
+          (selector) => `${selector}[hreflang="${path.currentLanguage}"]`,
+        ),
+      );
+
+      // Add query string selector for pagers, exposed filters.
+      selectors = selectors.map((current) => current + querySelector);
+
+      // Query the DOM.
       const activeLinks = context.querySelectorAll(selectors.join(','));
       const il = activeLinks.length;
-
       for (let i = 0; i < il; i++) {
         activeLinks[i].classList.add('is-active');
       }
     },
-
     detach(context, settings, trigger) {
       if (trigger === 'unload') {
-        const activeLinks = context.querySelectorAll('[data-drupal-link-system-path].is-active');
+        const activeLinks = context.querySelectorAll(
+          '[data-drupal-link-system-path].is-active',
+        );
         const il = activeLinks.length;
-
         for (let i = 0; i < il; i++) {
           activeLinks[i].classList.remove('is-active');
         }
       }
-    }
-
+    },
   };
-})(Drupal, drupalSettings);
\ No newline at end of file
+})(Drupal, drupalSettings);
diff --git a/core/misc/ajax.es6.js b/core/misc/ajax.es6.js
deleted file mode 100644
index c8c8eb1cd39e..000000000000
--- a/core/misc/ajax.es6.js
+++ /dev/null
@@ -1,1740 +0,0 @@
-/**
- * @file
- * Provides Ajax page updating via jQuery $.ajax.
- *
- * Ajax is a method of making a request via JavaScript while viewing an HTML
- * page. The request returns an array of commands encoded in JSON, which is
- * then executed to make any changes that are necessary to the page.
- *
- * Drupal uses this file to enhance form elements with `#ajax['url']` and
- * `#ajax['wrapper']` properties. If set, this file will automatically be
- * included to provide Ajax capabilities.
- */
-
-(function (
-  $,
-  window,
-  Drupal,
-  drupalSettings,
-  loadjs,
-  { isFocusable, tabbable },
-) {
-  /**
-   * Attaches the Ajax behavior to each Ajax form element.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Initialize all {@link Drupal.Ajax} objects declared in
-   *   `drupalSettings.ajax` or initialize {@link Drupal.Ajax} objects from
-   *   DOM elements having the `use-ajax-submit` or `use-ajax` css class.
-   * @prop {Drupal~behaviorDetach} detach
-   *   During `unload` remove all {@link Drupal.Ajax} objects related to
-   *   the removed content.
-   */
-  Drupal.behaviors.AJAX = {
-    attach(context, settings) {
-      function loadAjaxBehavior(base) {
-        const elementSettings = settings.ajax[base];
-        if (typeof elementSettings.selector === 'undefined') {
-          elementSettings.selector = `#${base}`;
-        }
-        // Use jQuery selector instead of a native selector for
-        // backwards compatibility.
-        once('drupal-ajax', $(elementSettings.selector)).forEach((el) => {
-          elementSettings.element = el;
-          elementSettings.base = base;
-          Drupal.ajax(elementSettings);
-        });
-      }
-
-      // Load all Ajax behaviors specified in the settings.
-      Object.keys(settings.ajax || {}).forEach((base) =>
-        loadAjaxBehavior(base),
-      );
-
-      Drupal.ajax.bindAjaxLinks(document.body);
-
-      // This class means to submit the form to the action using Ajax.
-      once('ajax', '.use-ajax-submit').forEach((el) => {
-        const elementSettings = {};
-
-        // Ajax submits specified in this manner automatically submit to the
-        // normal form action.
-        elementSettings.url = $(el.form).attr('action');
-        // Form submit button clicks need to tell the form what was clicked so
-        // it gets passed in the POST request.
-        elementSettings.setClick = true;
-        // Form buttons use the 'click' event rather than mousedown.
-        elementSettings.event = 'click';
-        // Clicked form buttons look better with the throbber than the progress
-        // bar.
-        elementSettings.progress = { type: 'throbber' };
-        elementSettings.base = el.id;
-        elementSettings.element = el;
-
-        Drupal.ajax(elementSettings);
-      });
-    },
-
-    detach(context, settings, trigger) {
-      if (trigger === 'unload') {
-        Drupal.ajax.expired().forEach((instance) => {
-          // Set this to null and allow garbage collection to reclaim
-          // the memory.
-          Drupal.ajax.instances[instance.instanceIndex] = null;
-        });
-      }
-    },
-  };
-
-  /**
-   * Extends Error to provide handling for Errors in Ajax.
-   *
-   * @constructor
-   *
-   * @augments Error
-   *
-   * @param {XMLHttpRequest} xmlhttp
-   *   XMLHttpRequest object used for the failed request.
-   * @param {string} uri
-   *   The URI where the error occurred.
-   * @param {string} customMessage
-   *   The custom message.
-   */
-  Drupal.AjaxError = function (xmlhttp, uri, customMessage) {
-    let statusCode;
-    let statusText;
-    let responseText;
-    if (xmlhttp.status) {
-      statusCode = `\n${Drupal.t('An AJAX HTTP error occurred.')}\n${Drupal.t(
-        'HTTP Result Code: !status',
-        {
-          '!status': xmlhttp.status,
-        },
-      )}`;
-    } else {
-      statusCode = `\n${Drupal.t(
-        'An AJAX HTTP request terminated abnormally.',
-      )}`;
-    }
-    statusCode += `\n${Drupal.t('Debugging information follows.')}`;
-    const pathText = `\n${Drupal.t('Path: !uri', { '!uri': uri })}`;
-    statusText = '';
-    // In some cases, when statusCode === 0, xmlhttp.statusText may not be
-    // defined. Unfortunately, testing for it with typeof, etc, doesn't seem to
-    // catch that and the test causes an exception. So we need to catch the
-    // exception here.
-    try {
-      statusText = `\n${Drupal.t('StatusText: !statusText', {
-        '!statusText': xmlhttp.statusText.trim(),
-      })}`;
-    } catch (e) {
-      // Empty.
-    }
-
-    responseText = '';
-    // Again, we don't have a way to know for sure whether accessing
-    // xmlhttp.responseText is going to throw an exception. So we'll catch it.
-    try {
-      responseText = `\n${Drupal.t('ResponseText: !responseText', {
-        '!responseText': xmlhttp.responseText.trim(),
-      })}`;
-    } catch (e) {
-      // Empty.
-    }
-
-    // Make the responseText more readable by stripping HTML tags and newlines.
-    responseText = responseText.replace(/<("[^"]*"|'[^']*'|[^'">])*>/gi, '');
-    responseText = responseText.replace(/[\n]+\s+/g, '\n');
-
-    // We don't need readyState except for status == 0.
-    const readyStateText =
-      xmlhttp.status === 0
-        ? `\n${Drupal.t('ReadyState: !readyState', {
-            '!readyState': xmlhttp.readyState,
-          })}`
-        : '';
-
-    customMessage = customMessage
-      ? `\n${Drupal.t('CustomMessage: !customMessage', {
-          '!customMessage': customMessage,
-        })}`
-      : '';
-
-    /**
-     * Formatted and translated error message.
-     *
-     * @type {string}
-     */
-    this.message =
-      statusCode +
-      pathText +
-      statusText +
-      customMessage +
-      responseText +
-      readyStateText;
-
-    /**
-     * Used by some browsers to display a more accurate stack trace.
-     *
-     * @type {string}
-     */
-    this.name = 'AjaxError';
-  };
-
-  Drupal.AjaxError.prototype = new Error();
-  Drupal.AjaxError.prototype.constructor = Drupal.AjaxError;
-
-  /**
-   * Provides Ajax page updating via jQuery $.ajax.
-   *
-   * This function is designed to improve developer experience by wrapping the
-   * initialization of {@link Drupal.Ajax} objects and storing all created
-   * objects in the {@link Drupal.ajax.instances} array.
-   *
-   * @example
-   * Drupal.behaviors.myCustomAJAXStuff = {
-   *   attach: function (context, settings) {
-   *
-   *     var ajaxSettings = {
-   *       url: 'my/url/path',
-   *       // If the old version of Drupal.ajax() needs to be used those
-   *       // properties can be added
-   *       base: 'myBase',
-   *       element: $(context).find('.someElement')
-   *     };
-   *
-   *     var myAjaxObject = Drupal.ajax(ajaxSettings);
-   *
-   *     // Declare a new Ajax command specifically for this Ajax object.
-   *     myAjaxObject.commands.insert = function (ajax, response, status) {
-   *       $('#my-wrapper').append(response.data);
-   *       alert('New content was appended to #my-wrapper');
-   *     };
-   *
-   *     // This command will remove this Ajax object from the page.
-   *     myAjaxObject.commands.destroyObject = function (ajax, response, status) {
-   *       Drupal.ajax.instances[this.instanceIndex] = null;
-   *     };
-   *
-   *     // Programmatically trigger the Ajax request.
-   *     myAjaxObject.execute();
-   *   }
-   * };
-   *
-   * @param {object} settings
-   *   The settings object passed to {@link Drupal.Ajax} constructor.
-   * @param {string} [settings.base]
-   *   Base is passed to {@link Drupal.Ajax} constructor as the 'base'
-   *   parameter.
-   * @param {HTMLElement} [settings.element]
-   *   Element parameter of {@link Drupal.Ajax} constructor, element on which
-   *   event listeners will be bound.
-   *
-   * @return {Drupal.Ajax}
-   *   The created Ajax object.
-   *
-   * @see Drupal.AjaxCommands
-   */
-  Drupal.ajax = function (settings) {
-    if (arguments.length !== 1) {
-      throw new Error(
-        'Drupal.ajax() function must be called with one configuration object only',
-      );
-    }
-    // Map those config keys to variables for the old Drupal.ajax function.
-    const base = settings.base || false;
-    const element = settings.element || false;
-    delete settings.base;
-    delete settings.element;
-
-    // By default do not display progress for ajax calls without an element.
-    if (!settings.progress && !element) {
-      settings.progress = false;
-    }
-
-    const ajax = new Drupal.Ajax(base, element, settings);
-    ajax.instanceIndex = Drupal.ajax.instances.length;
-    Drupal.ajax.instances.push(ajax);
-
-    return ajax;
-  };
-
-  /**
-   * Contains all created Ajax objects.
-   *
-   * @type {Array.<Drupal.Ajax|null>}
-   */
-  Drupal.ajax.instances = [];
-
-  /**
-   * List all objects where the associated element is not in the DOM
-   *
-   * This method ignores {@link Drupal.Ajax} objects not bound to DOM elements
-   * when created with {@link Drupal.ajax}.
-   *
-   * @return {Array.<Drupal.Ajax>}
-   *   The list of expired {@link Drupal.Ajax} objects.
-   */
-  Drupal.ajax.expired = function () {
-    return Drupal.ajax.instances.filter(
-      (instance) =>
-        instance &&
-        instance.element !== false &&
-        !document.body.contains(instance.element),
-    );
-  };
-
-  /**
-   * Bind Ajax functionality to links that use the 'use-ajax' class.
-   *
-   * @param {HTMLElement} element
-   *   Element to enable Ajax functionality for.
-   */
-  Drupal.ajax.bindAjaxLinks = (element) => {
-    // Bind Ajax behaviors to all items showing the class.
-    once('ajax', '.use-ajax', element).forEach((ajaxLink) => {
-      const $linkElement = $(ajaxLink);
-
-      const elementSettings = {
-        // Clicked links look better with the throbber than the progress bar.
-        progress: { type: 'throbber' },
-        dialogType: $linkElement.data('dialog-type'),
-        dialog: $linkElement.data('dialog-options'),
-        dialogRenderer: $linkElement.data('dialog-renderer'),
-        base: $linkElement.attr('id'),
-        element: ajaxLink,
-      };
-      const href = $linkElement.attr('href');
-      /**
-       * For anchor tags, these will go to the target of the anchor rather than
-       * the usual location.
-       */
-      if (href) {
-        elementSettings.url = href;
-        elementSettings.event = 'click';
-      }
-      Drupal.ajax(elementSettings);
-    });
-  };
-
-  /**
-   * Settings for an Ajax object.
-   *
-   * @typedef {object} Drupal.Ajax~elementSettings
-   *
-   * @prop {string} url
-   *   Target of the Ajax request.
-   * @prop {?string} [event]
-   *   Event bound to settings.element which will trigger the Ajax request.
-   * @prop {bool} [keypress=true]
-   *   Triggers a request on keypress events.
-   * @prop {?string} selector
-   *   jQuery selector targeting the element to bind events to or used with
-   *   {@link Drupal.AjaxCommands}.
-   * @prop {string} [effect='none']
-   *   Name of the jQuery method to use for displaying new Ajax content.
-   * @prop {string|number} [speed='none']
-   *   Speed with which to apply the effect.
-   * @prop {string} [method]
-   *   Name of the jQuery method used to insert new content in the targeted
-   *   element.
-   * @prop {object} [progress]
-   *   Settings for the display of a user-friendly loader.
-   * @prop {string} [progress.type='throbber']
-   *   Type of progress element, core provides `'bar'`, `'throbber'` and
-   *   `'fullscreen'`.
-   * @prop {string} [progress.message=Drupal.t('Please wait...')]
-   *   Custom message to be used with the bar indicator.
-   * @prop {object} [submit]
-   *   Extra data to be sent with the Ajax request.
-   * @prop {bool} [submit.js=true]
-   *   Allows the PHP side to know this comes from an Ajax request.
-   * @prop {object} [dialog]
-   *   Options for {@link Drupal.dialog}.
-   * @prop {string} [dialogType]
-   *   One of `'modal'` or `'dialog'`.
-   * @prop {string} [prevent]
-   *   List of events on which to stop default action and stop propagation.
-   */
-
-  /**
-   * Ajax constructor.
-   *
-   * The Ajax request returns an array of commands encoded in JSON, which is
-   * then executed to make any changes that are necessary to the page.
-   *
-   * Drupal uses this file to enhance form elements with `#ajax['url']` and
-   * `#ajax['wrapper']` properties. If set, this file will automatically be
-   * included to provide Ajax capabilities.
-   *
-   * @constructor
-   *
-   * @param {string} [base]
-   *   Base parameter of {@link Drupal.Ajax} constructor
-   * @param {HTMLElement} [element]
-   *   Element parameter of {@link Drupal.Ajax} constructor, element on which
-   *   event listeners will be bound.
-   * @param {Drupal.Ajax~elementSettings} elementSettings
-   *   Settings for this Ajax object.
-   */
-  Drupal.Ajax = function (base, element, elementSettings) {
-    const defaults = {
-      event: element ? 'mousedown' : null,
-      keypress: true,
-      selector: base ? `#${base}` : null,
-      effect: 'none',
-      speed: 'none',
-      method: 'replaceWith',
-      progress: {
-        type: 'throbber',
-        message: Drupal.t('Please wait...'),
-      },
-      submit: {
-        js: true,
-      },
-    };
-
-    $.extend(this, defaults, elementSettings);
-
-    /**
-     * @type {Drupal.AjaxCommands}
-     */
-    this.commands = new Drupal.AjaxCommands();
-
-    /**
-     * @type {bool|number}
-     */
-    this.instanceIndex = false;
-
-    // @todo Remove this after refactoring the PHP code to:
-    //   - Call this 'selector'.
-    //   - Include the '#' for ID-based selectors.
-    //   - Support non-ID-based selectors.
-    if (this.wrapper) {
-      /**
-       * @type {string}
-       */
-      this.wrapper = `#${this.wrapper}`;
-    }
-
-    /**
-     * @type {HTMLElement}
-     */
-    this.element = element;
-
-    /**
-     * @type {Drupal.Ajax~elementSettings}
-     */
-    this.elementSettings = elementSettings;
-
-    // If there isn't a form, jQuery.ajax() will be used instead, allowing us to
-    // bind Ajax to links as well.
-    if (this.element && this.element.form) {
-      /**
-       * @type {jQuery}
-       */
-      this.$form = $(this.element.form);
-    }
-
-    // If no Ajax callback URL was given, use the link href or form action.
-    if (!this.url) {
-      const $element = $(this.element);
-      if ($element.is('a')) {
-        this.url = $element.attr('href');
-      } else if (this.element && element.form) {
-        this.url = this.$form.attr('action');
-      }
-    }
-
-    // Replacing 'nojs' with 'ajax' in the URL allows for an easy method to let
-    // the server detect when it needs to degrade gracefully.
-    // There are four scenarios to check for:
-    // 1. /nojs/
-    // 2. /nojs$ - The end of a URL string.
-    // 3. /nojs? - Followed by a query (e.g. path/nojs?destination=foobar).
-    // 4. /nojs# - Followed by a fragment (e.g.: path/nojs#my-fragment).
-    const originalUrl = this.url;
-
-    /**
-     * Processed Ajax URL.
-     *
-     * @type {string}
-     */
-    this.url = this.url.replace(/\/nojs(\/|$|\?|#)/, '/ajax$1');
-    // If the 'nojs' version of the URL is trusted, also trust the 'ajax'
-    // version.
-    if (drupalSettings.ajaxTrustedUrl[originalUrl]) {
-      drupalSettings.ajaxTrustedUrl[this.url] = true;
-    }
-
-    // Set the options for the ajaxSubmit function.
-    // The 'this' variable will not persist inside of the options object.
-    const ajax = this;
-
-    /**
-     * Options for the jQuery.ajax function.
-     *
-     * @name Drupal.Ajax#options
-     *
-     * @type {object}
-     *
-     * @prop {string} url
-     *   Ajax URL to be called.
-     * @prop {object} data
-     *   Ajax payload.
-     * @prop {function} beforeSerialize
-     *   Implement jQuery beforeSerialize function to call
-     *   {@link Drupal.Ajax#beforeSerialize}.
-     * @prop {function} beforeSubmit
-     *   Implement jQuery beforeSubmit function to call
-     *   {@link Drupal.Ajax#beforeSubmit}.
-     * @prop {function} beforeSend
-     *   Implement jQuery beforeSend function to call
-     *   {@link Drupal.Ajax#beforeSend}.
-     * @prop {function} success
-     *   Implement jQuery success function to call
-     *   {@link Drupal.Ajax#success}.
-     * @prop {function} complete
-     *   Implement jQuery success function to clean up ajax state and trigger an
-     *   error if needed.
-     * @prop {string} dataType='json'
-     *   Type of the response expected.
-     * @prop {string} type='POST'
-     *   HTTP method to use for the Ajax request.
-     */
-    ajax.options = {
-      url: ajax.url,
-      data: ajax.submit,
-      beforeSerialize(elementSettings, options) {
-        return ajax.beforeSerialize(elementSettings, options);
-      },
-      beforeSubmit(formValues, elementSettings, options) {
-        ajax.ajaxing = true;
-        return ajax.beforeSubmit(formValues, elementSettings, options);
-      },
-      beforeSend(xmlhttprequest, options) {
-        ajax.ajaxing = true;
-        return ajax.beforeSend(xmlhttprequest, options);
-      },
-      success(response, status, xmlhttprequest) {
-        // Sanity check for browser support (object expected).
-        // When using iFrame uploads, responses must be returned as a string.
-        if (typeof response === 'string') {
-          response = $.parseJSON(response);
-        }
-
-        // Prior to invoking the response's commands, verify that they can be
-        // trusted by checking for a response header. See
-        // \Drupal\Core\EventSubscriber\AjaxResponseSubscriber for details.
-        // - Empty responses are harmless so can bypass verification. This
-        //   avoids an alert message for server-generated no-op responses that
-        //   skip Ajax rendering.
-        // - Ajax objects with trusted URLs (e.g., ones defined server-side via
-        //   #ajax) can bypass header verification. This is especially useful
-        //   for Ajax with multipart forms. Because IFRAME transport is used,
-        //   the response headers cannot be accessed for verification.
-        if (response !== null && !drupalSettings.ajaxTrustedUrl[ajax.url]) {
-          if (xmlhttprequest.getResponseHeader('X-Drupal-Ajax-Token') !== '1') {
-            const customMessage = Drupal.t(
-              'The response failed verification so will not be processed.',
-            );
-            return ajax.error(xmlhttprequest, ajax.url, customMessage);
-          }
-        }
-
-        return (
-          // Ensure that the return of the success callback is a Promise.
-          // When the return is a Promise, using resolve will unwrap it, and
-          // when the return is not a Promise we make sure it can be used as
-          // one. This is useful for code that overrides the success method.
-          Promise.resolve(ajax.success(response, status))
-            // Ajaxing status is back to false when all the AJAX commands have
-            // finished executing.
-            .then(() => {
-              ajax.ajaxing = false;
-            })
-        );
-      },
-      error(xmlhttprequest, status, error) {
-        ajax.ajaxing = false;
-      },
-      complete(xmlhttprequest, status) {
-        if (status === 'error' || status === 'parsererror') {
-          return ajax.error(xmlhttprequest, ajax.url);
-        }
-      },
-      dataType: 'json',
-      jsonp: false,
-      type: 'POST',
-    };
-
-    if (elementSettings.dialog) {
-      ajax.options.data.dialogOptions = elementSettings.dialog;
-    }
-
-    // Ensure that we have a valid URL by adding ? when no query parameter is
-    // yet available, otherwise append using &.
-    if (ajax.options.url.indexOf('?') === -1) {
-      ajax.options.url += '?';
-    } else {
-      ajax.options.url += '&';
-    }
-    // If this element has a dialog type use if for the wrapper if not use 'ajax'.
-    let wrapper = `drupal_${elementSettings.dialogType || 'ajax'}`;
-    if (elementSettings.dialogRenderer) {
-      wrapper += `.${elementSettings.dialogRenderer}`;
-    }
-    ajax.options.url += `${Drupal.ajax.WRAPPER_FORMAT}=${wrapper}`;
-
-    // Bind the ajaxSubmit function to the element event.
-    $(ajax.element).on(elementSettings.event, function (event) {
-      if (
-        !drupalSettings.ajaxTrustedUrl[ajax.url] &&
-        !Drupal.url.isLocal(ajax.url)
-      ) {
-        throw new Error(
-          Drupal.t('The callback URL is not local and not trusted: !url', {
-            '!url': ajax.url,
-          }),
-        );
-      }
-      return ajax.eventResponse(this, event);
-    });
-
-    // If necessary, enable keyboard submission so that Ajax behaviors
-    // can be triggered through keyboard input as well as e.g. a mousedown
-    // action.
-    if (elementSettings.keypress) {
-      $(ajax.element).on('keypress', function (event) {
-        return ajax.keypressResponse(this, event);
-      });
-    }
-
-    // If necessary, prevent the browser default action of an additional event.
-    // For example, prevent the browser default action of a click, even if the
-    // Ajax behavior binds to mousedown.
-    if (elementSettings.prevent) {
-      $(ajax.element).on(elementSettings.prevent, false);
-    }
-  };
-
-  /**
-   * URL query attribute to indicate the wrapper used to render a request.
-   *
-   * The wrapper format determines how the HTML is wrapped, for example in a
-   * modal dialog.
-   *
-   * @const {string}
-   *
-   * @default
-   */
-  Drupal.ajax.WRAPPER_FORMAT = '_wrapper_format';
-
-  /**
-   * Request parameter to indicate that a request is a Drupal Ajax request.
-   *
-   * @const {string}
-   *
-   * @default
-   */
-  Drupal.Ajax.AJAX_REQUEST_PARAMETER = '_drupal_ajax';
-
-  /**
-   * Execute the ajax request.
-   *
-   * Allows developers to execute an Ajax request manually without specifying
-   * an event to respond to.
-   *
-   * @return {object}
-   *   Returns the jQuery.Deferred object underlying the Ajax request. If
-   *   pre-serialization fails, the Deferred will be returned in the rejected
-   *   state.
-   */
-  Drupal.Ajax.prototype.execute = function () {
-    // Do not perform another ajax command if one is already in progress.
-    if (this.ajaxing) {
-      return;
-    }
-
-    try {
-      this.beforeSerialize(this.element, this.options);
-      // Return the jqXHR so that external code can hook into the Deferred API.
-      return $.ajax(this.options);
-    } catch (e) {
-      // Unset the ajax.ajaxing flag here because it won't be unset during
-      // the complete response.
-      this.ajaxing = false;
-      window.alert(
-        `An error occurred while attempting to process ${this.options.url}: ${e.message}`,
-      );
-      // For consistency, return a rejected Deferred (i.e., jqXHR's superclass)
-      // so that calling code can take appropriate action.
-      return $.Deferred().reject();
-    }
-  };
-
-  /**
-   * Handle a key press.
-   *
-   * The Ajax object will, if instructed, bind to a key press response. This
-   * will test to see if the key press is valid to trigger this event and
-   * if it is, trigger it for us and prevent other keypresses from triggering.
-   * In this case we're handling RETURN and SPACEBAR keypresses (event codes 13
-   * and 32. RETURN is often used to submit a form when in a textfield, and
-   * SPACE is often used to activate an element without submitting.
-   *
-   * @param {HTMLElement} element
-   *   Element the event was triggered on.
-   * @param {jQuery.Event} event
-   *   Triggered event.
-   */
-  Drupal.Ajax.prototype.keypressResponse = function (element, event) {
-    // Create a synonym for this to reduce code confusion.
-    const ajax = this;
-
-    // Detect enter key and space bar and allow the standard response for them,
-    // except for form elements of type 'text', 'tel', 'number' and 'textarea',
-    // where the spacebar activation causes inappropriate activation if
-    // #ajax['keypress'] is TRUE. On a text-type widget a space should always
-    // be a space.
-    if (
-      event.which === 13 ||
-      (event.which === 32 &&
-        element.type !== 'text' &&
-        element.type !== 'textarea' &&
-        element.type !== 'tel' &&
-        element.type !== 'number')
-    ) {
-      event.preventDefault();
-      event.stopPropagation();
-      $(element).trigger(ajax.elementSettings.event);
-    }
-  };
-
-  /**
-   * Handle an event that triggers an Ajax response.
-   *
-   * When an event that triggers an Ajax response happens, this method will
-   * perform the actual Ajax call. It is bound to the event using
-   * bind() in the constructor, and it uses the options specified on the
-   * Ajax object.
-   *
-   * @param {HTMLElement} element
-   *   Element the event was triggered on.
-   * @param {jQuery.Event} event
-   *   Triggered event.
-   */
-  Drupal.Ajax.prototype.eventResponse = function (element, event) {
-    event.preventDefault();
-    event.stopPropagation();
-
-    // Create a synonym for this to reduce code confusion.
-    const ajax = this;
-
-    // Do not perform another Ajax command if one is already in progress.
-    if (ajax.ajaxing) {
-      return;
-    }
-
-    try {
-      if (ajax.$form) {
-        // If setClick is set, we must set this to ensure that the button's
-        // value is passed.
-        if (ajax.setClick) {
-          // Mark the clicked button. 'form.clk' is a special variable for
-          // ajaxSubmit that tells the system which element got clicked to
-          // trigger the submit. Without it there would be no 'op' or
-          // equivalent.
-          element.form.clk = element;
-        }
-
-        ajax.$form.ajaxSubmit(ajax.options);
-      } else {
-        ajax.beforeSerialize(ajax.element, ajax.options);
-        $.ajax(ajax.options);
-      }
-    } catch (e) {
-      // Unset the ajax.ajaxing flag here because it won't be unset during
-      // the complete response.
-      ajax.ajaxing = false;
-      window.alert(
-        `An error occurred while attempting to process ${ajax.options.url}: ${e.message}`,
-      );
-    }
-  };
-
-  /**
-   * Handler for the form serialization.
-   *
-   * Runs before the beforeSend() handler (see below), and unlike that one, runs
-   * before field data is collected.
-   *
-   * @param {object} [element]
-   *   Ajax object's `elementSettings`.
-   * @param {object} options
-   *   jQuery.ajax options.
-   */
-  Drupal.Ajax.prototype.beforeSerialize = function (element, options) {
-    // Allow detaching behaviors to update field values before collecting them.
-    // This is only needed when field values are added to the POST data, so only
-    // when there is a form such that this.$form.ajaxSubmit() is used instead of
-    // $.ajax(). When there is no form and $.ajax() is used, beforeSerialize()
-    // isn't called, but don't rely on that: explicitly check this.$form.
-    if (this.$form && document.body.contains(this.$form.get(0))) {
-      const settings = this.settings || drupalSettings;
-      Drupal.detachBehaviors(this.$form.get(0), settings, 'serialize');
-    }
-
-    // Inform Drupal that this is an AJAX request.
-    options.data[Drupal.Ajax.AJAX_REQUEST_PARAMETER] = 1;
-
-    // Allow Drupal to return new JavaScript and CSS files to load without
-    // returning the ones already loaded.
-    // @see \Drupal\Core\Theme\AjaxBasePageNegotiator
-    // @see \Drupal\Core\Asset\LibraryDependencyResolverInterface::getMinimalRepresentativeSubset()
-    // @see system_js_settings_alter()
-    const pageState = drupalSettings.ajaxPageState;
-    options.data['ajax_page_state[theme]'] = pageState.theme;
-    options.data['ajax_page_state[theme_token]'] = pageState.theme_token;
-    options.data['ajax_page_state[libraries]'] = pageState.libraries;
-  };
-
-  /**
-   * Modify form values prior to form submission.
-   *
-   * @param {Array.<object>} formValues
-   *   Processed form values.
-   * @param {jQuery} element
-   *   The form node as a jQuery object.
-   * @param {object} options
-   *   jQuery.ajax options.
-   */
-  Drupal.Ajax.prototype.beforeSubmit = function (formValues, element, options) {
-    // This function is left empty to make it simple to override for modules
-    // that wish to add functionality here.
-  };
-
-  /**
-   * Prepare the Ajax request before it is sent.
-   *
-   * @param {XMLHttpRequest} xmlhttprequest
-   *   Native Ajax object.
-   * @param {object} options
-   *   jQuery.ajax options.
-   */
-  Drupal.Ajax.prototype.beforeSend = function (xmlhttprequest, options) {
-    // For forms without file inputs, the jQuery Form plugin serializes the
-    // form values, and then calls jQuery's $.ajax() function, which invokes
-    // this handler. In this circumstance, options.extraData is never used. For
-    // forms with file inputs, the jQuery Form plugin uses the browser's normal
-    // form submission mechanism, but captures the response in a hidden IFRAME.
-    // In this circumstance, it calls this handler first, and then appends
-    // hidden fields to the form to submit the values in options.extraData.
-    // There is no simple way to know which submission mechanism will be used,
-    // so we add to extraData regardless, and allow it to be ignored in the
-    // former case.
-    if (this.$form) {
-      options.extraData = options.extraData || {};
-
-      // Let the server know when the IFRAME submission mechanism is used. The
-      // server can use this information to wrap the JSON response in a
-      // TEXTAREA, as per http://jquery.malsup.com/form/#file-upload.
-      options.extraData.ajax_iframe_upload = '1';
-
-      // The triggering element is about to be disabled (see below), but if it
-      // contains a value (e.g., a checkbox, textfield, select, etc.), ensure
-      // that value is included in the submission. As per above, submissions
-      // that use $.ajax() are already serialized prior to the element being
-      // disabled, so this is only needed for IFRAME submissions.
-      const v = $.fieldValue(this.element);
-      if (v !== null) {
-        options.extraData[this.element.name] = v;
-      }
-    }
-
-    // Disable the element that received the change to prevent user interface
-    // interaction while the Ajax request is in progress. ajax.ajaxing prevents
-    // the element from triggering a new request, but does not prevent the user
-    // from changing its value.
-    $(this.element).prop('disabled', true);
-
-    if (!this.progress || !this.progress.type) {
-      return;
-    }
-
-    // Insert progress indicator.
-    const progressIndicatorMethod = `setProgressIndicator${this.progress.type
-      .slice(0, 1)
-      .toUpperCase()}${this.progress.type.slice(1).toLowerCase()}`;
-    if (
-      progressIndicatorMethod in this &&
-      typeof this[progressIndicatorMethod] === 'function'
-    ) {
-      this[progressIndicatorMethod].call(this);
-    }
-  };
-
-  /**
-   * An animated progress throbber and container element for AJAX operations.
-   *
-   * @param {string} [message]
-   *   (optional) The message shown on the UI.
-   * @return {string}
-   *   The HTML markup for the throbber.
-   */
-  Drupal.theme.ajaxProgressThrobber = (message) => {
-    // Build markup without adding extra white space since it affects rendering.
-    const messageMarkup =
-      typeof message === 'string'
-        ? Drupal.theme('ajaxProgressMessage', message)
-        : '';
-    const throbber = '<div class="throbber">&nbsp;</div>';
-
-    return `<div class="ajax-progress ajax-progress-throbber">${throbber}${messageMarkup}</div>`;
-  };
-
-  /**
-   * An animated progress throbber and container element for AJAX operations.
-   *
-   * @return {string}
-   *   The HTML markup for the throbber.
-   */
-  Drupal.theme.ajaxProgressIndicatorFullscreen = () =>
-    '<div class="ajax-progress ajax-progress-fullscreen">&nbsp;</div>';
-
-  /**
-   * Formats text accompanying the AJAX progress throbber.
-   *
-   * @param {string} message
-   *   The message shown on the UI.
-   * @return {string}
-   *   The HTML markup for the throbber.
-   */
-  Drupal.theme.ajaxProgressMessage = (message) =>
-    `<div class="message">${message}</div>`;
-
-  /**
-   * Provide a wrapper for the AJAX progress bar element.
-   *
-   * @param {jQuery} $element
-   *   Progress bar element.
-   * @return {string}
-   *   The HTML markup for the progress bar.
-   */
-  Drupal.theme.ajaxProgressBar = ($element) =>
-    $('<div class="ajax-progress ajax-progress-bar"></div>').append($element);
-
-  /**
-   * Sets the progress bar progress indicator.
-   */
-  Drupal.Ajax.prototype.setProgressIndicatorBar = function () {
-    const progressBar = new Drupal.ProgressBar(
-      `ajax-progress-${this.element.id}`,
-      $.noop,
-      this.progress.method,
-      $.noop,
-    );
-    if (this.progress.message) {
-      progressBar.setProgress(-1, this.progress.message);
-    }
-    if (this.progress.url) {
-      progressBar.startMonitoring(
-        this.progress.url,
-        this.progress.interval || 1500,
-      );
-    }
-    this.progress.element = $(
-      Drupal.theme('ajaxProgressBar', progressBar.element),
-    );
-    this.progress.object = progressBar;
-    $(this.element).after(this.progress.element);
-  };
-
-  /**
-   * Sets the throbber progress indicator.
-   */
-  Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () {
-    this.progress.element = $(
-      Drupal.theme('ajaxProgressThrobber', this.progress.message),
-    );
-    $(this.element).after(this.progress.element);
-  };
-
-  /**
-   * Sets the fullscreen progress indicator.
-   */
-  Drupal.Ajax.prototype.setProgressIndicatorFullscreen = function () {
-    this.progress.element = $(Drupal.theme('ajaxProgressIndicatorFullscreen'));
-    $('body').append(this.progress.element);
-  };
-
-  /**
-   * Helper method to make sure commands are executed in sequence.
-   *
-   * @param {Array.<Drupal.AjaxCommands~commandDefinition>} response
-   *   Drupal Ajax response.
-   * @param {number} status
-   *   XMLHttpRequest status.
-   *
-   * @return {Promise}
-   *  The promise that will resolve once all commands have finished executing.
-   */
-  Drupal.Ajax.prototype.commandExecutionQueue = function (response, status) {
-    const ajaxCommands = this.commands;
-    return Object.keys(response || {}).reduce(
-      // Add all commands to a single execution queue.
-      (executionQueue, key) =>
-        executionQueue.then(() => {
-          const { command } = response[key];
-          if (command && ajaxCommands[command]) {
-            // When a command returns a promise, the remaining commands will not
-            // execute until that promise has been fulfilled. This is typically
-            // used to ensure JavaScript files added via the 'add_js' command
-            // have loaded before subsequent commands execute.
-            return ajaxCommands[command](this, response[key], status);
-          }
-        }),
-      Promise.resolve(),
-    );
-  };
-
-  /**
-   * Handler for the form redirection completion.
-   *
-   * @param {Array.<Drupal.AjaxCommands~commandDefinition>} response
-   *   Drupal Ajax response.
-   * @param {number} status
-   *   XMLHttpRequest status.
-   *
-   * @return {Promise}
-   * The promise that will resolve once all commands have finished executing.
-   */
-  Drupal.Ajax.prototype.success = function (response, status) {
-    // Remove the progress element.
-    if (this.progress.element) {
-      $(this.progress.element).remove();
-    }
-    if (this.progress.object) {
-      this.progress.object.stopMonitoring();
-    }
-    $(this.element).prop('disabled', false);
-
-    // Save element's ancestors tree so if the element is removed from the dom
-    // we can try to refocus one of its parents. Using addBack reverse the
-    // result array, meaning that index 0 is the highest parent in the hierarchy
-    // in this situation it is usually a <form> element.
-    const elementParents = $(this.element)
-      .parents('[data-drupal-selector]')
-      .addBack()
-      .toArray();
-
-    // Track if any command is altering the focus so we can avoid changing the
-    // focus set by the Ajax command.
-    const focusChanged = Object.keys(response || {}).some((key) => {
-      const { command, method } = response[key];
-      return (
-        command === 'focusFirst' || (command === 'invoke' && method === 'focus')
-      );
-    });
-
-    return (
-      this.commandExecutionQueue(response, status)
-        // If the focus hasn't been changed by the AJAX commands, try to refocus
-        // the triggering element or one of its parents if that element does not
-        // exist anymore.
-        .then(() => {
-          if (
-            !focusChanged &&
-            this.element &&
-            !$(this.element).data('disable-refocus')
-          ) {
-            let target = false;
-
-            for (let n = elementParents.length - 1; !target && n >= 0; n--) {
-              target = document.querySelector(
-                `[data-drupal-selector="${elementParents[n].getAttribute(
-                  'data-drupal-selector',
-                )}"]`,
-              );
-            }
-            if (target) {
-              $(target).trigger('focus');
-            }
-          }
-          // Reattach behaviors, if they were detached in beforeSerialize(). The
-          // attachBehaviors() called on the new content from processing the
-          // response commands is not sufficient, because behaviors from the
-          // entire form need to be reattached.
-          if (this.$form && document.body.contains(this.$form.get(0))) {
-            const settings = this.settings || drupalSettings;
-            Drupal.attachBehaviors(this.$form.get(0), settings);
-          }
-          // Remove any response-specific settings so they don't get used on the
-          // next call by mistake.
-          this.settings = null;
-        })
-        .catch((error) =>
-          // eslint-disable-next-line no-console
-          console.error(
-            Drupal.t(
-              'An error occurred during the execution of the Ajax response: !error',
-              {
-                '!error': error,
-              },
-            ),
-          ),
-        )
-    );
-  };
-
-  /**
-   * Build an effect object to apply an effect when adding new HTML.
-   *
-   * @param {object} response
-   *   Drupal Ajax response.
-   * @param {string} [response.effect]
-   *   Override the default value of {@link Drupal.Ajax#elementSettings}.
-   * @param {string|number} [response.speed]
-   *   Override the default value of {@link Drupal.Ajax#elementSettings}.
-   *
-   * @return {object}
-   *   Returns an object with `showEffect`, `hideEffect` and `showSpeed`
-   *   properties.
-   */
-  Drupal.Ajax.prototype.getEffect = function (response) {
-    const type = response.effect || this.effect;
-    const speed = response.speed || this.speed;
-
-    const effect = {};
-    if (type === 'none') {
-      effect.showEffect = 'show';
-      effect.hideEffect = 'hide';
-      effect.showSpeed = '';
-    } else if (type === 'fade') {
-      effect.showEffect = 'fadeIn';
-      effect.hideEffect = 'fadeOut';
-      effect.showSpeed = speed;
-    } else {
-      effect.showEffect = `${type}Toggle`;
-      effect.hideEffect = `${type}Toggle`;
-      effect.showSpeed = speed;
-    }
-
-    return effect;
-  };
-
-  /**
-   * Handler for the form redirection error.
-   *
-   * @param {object} xmlhttprequest
-   *   Native XMLHttpRequest object.
-   * @param {string} uri
-   *   Ajax Request URI.
-   * @param {string} [customMessage]
-   *   Extra message to print with the Ajax error.
-   */
-  Drupal.Ajax.prototype.error = function (xmlhttprequest, uri, customMessage) {
-    // Remove the progress element.
-    if (this.progress.element) {
-      $(this.progress.element).remove();
-    }
-    if (this.progress.object) {
-      this.progress.object.stopMonitoring();
-    }
-    // Undo hide.
-    $(this.wrapper).show();
-    // Re-enable the element.
-    $(this.element).prop('disabled', false);
-    // Reattach behaviors, if they were detached in beforeSerialize(), and the
-    // form is still part of the document.
-    if (this.$form && document.body.contains(this.$form.get(0))) {
-      const settings = this.settings || drupalSettings;
-      Drupal.attachBehaviors(this.$form.get(0), settings);
-    }
-    throw new Drupal.AjaxError(xmlhttprequest, uri, customMessage);
-  };
-
-  /**
-   * Provide a wrapper for new content via Ajax.
-   *
-   * Wrap the inserted markup when inserting multiple root elements with an
-   * ajax effect.
-   *
-   * @param {jQuery} $newContent
-   *   Response elements after parsing.
-   * @param {Drupal.Ajax} ajax
-   *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-   * @param {object} response
-   *   The response from the Ajax request.
-   *
-   * @deprecated in drupal:8.6.0 and is removed from drupal:10.0.0.
-   *   Use data with desired wrapper.
-   *
-   * @see https://www.drupal.org/node/2940704
-   *
-   * @todo Add deprecation warning after it is possible. For more information
-   *   see: https://www.drupal.org/project/drupal/issues/2973400
-   */
-  Drupal.theme.ajaxWrapperNewContent = ($newContent, ajax, response) =>
-    (response.effect || ajax.effect) !== 'none' &&
-    $newContent.filter(
-      (i) =>
-        !(
-          // We can not consider HTML comments or whitespace text as separate
-          // roots, since they do not cause visual regression with effect.
-          (
-            $newContent[i].nodeName === '#comment' ||
-            ($newContent[i].nodeName === '#text' &&
-              /^(\s|\n|\r)*$/.test($newContent[i].textContent))
-          )
-        ),
-    ).length > 1
-      ? Drupal.theme('ajaxWrapperMultipleRootElements', $newContent)
-      : $newContent;
-
-  /**
-   * Provide a wrapper for multiple root elements via Ajax.
-   *
-   * @param {jQuery} $elements
-   *   Response elements after parsing.
-   *
-   * @deprecated in drupal:8.6.0 and is removed from drupal:10.0.0.
-   *   Use data with desired wrapper.
-   *
-   * @see https://www.drupal.org/node/2940704
-   *
-   * @todo Add deprecation warning after it is possible. For more information
-   *   see: https://www.drupal.org/project/drupal/issues/2973400
-   */
-  Drupal.theme.ajaxWrapperMultipleRootElements = ($elements) =>
-    $('<div></div>').append($elements);
-
-  /**
-   * @typedef {object} Drupal.AjaxCommands~commandDefinition
-   *
-   * @prop {string} command
-   * @prop {string} [method]
-   * @prop {string} [selector]
-   * @prop {string} [data]
-   * @prop {object} [settings]
-   * @prop {bool} [asterisk]
-   * @prop {string} [text]
-   * @prop {string} [title]
-   * @prop {string} [url]
-   * @prop {object} [argument]
-   * @prop {string} [name]
-   * @prop {string} [value]
-   * @prop {string} [old]
-   * @prop {string} [new]
-   * @prop {bool} [merge]
-   * @prop {Array} [args]
-   *
-   * @see Drupal.AjaxCommands
-   */
-
-  /**
-   * Provide a series of commands that the client will perform.
-   *
-   * @constructor
-   */
-  Drupal.AjaxCommands = function () {};
-  Drupal.AjaxCommands.prototype = {
-    /**
-     * Command to insert new content into the DOM.
-     *
-     * @param {Drupal.Ajax} ajax
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {string} response.data
-     *   The data to use with the jQuery method.
-     * @param {string} [response.method]
-     *   The jQuery DOM manipulation method to be used.
-     * @param {string} [response.selector]
-     *   An optional jQuery selector string.
-     * @param {object} [response.settings]
-     *   An optional array of settings that will be used.
-     */
-    insert(ajax, response) {
-      // Get information from the response. If it is not there, default to
-      // our presets.
-      const $wrapper = response.selector
-        ? $(response.selector)
-        : $(ajax.wrapper);
-      const method = response.method || ajax.method;
-      const effect = ajax.getEffect(response);
-
-      // Apply any settings from the returned JSON if available.
-      const settings = response.settings || ajax.settings || drupalSettings;
-
-      // Parse response.data into an element collection.
-      let $newContent = $($.parseHTML(response.data, document, true));
-      // For backward compatibility, in some cases a wrapper will be added. This
-      // behavior will be removed before Drupal 9.0.0. If different behavior is
-      // needed, the theme functions can be overridden.
-      // @see https://www.drupal.org/node/2940704
-      $newContent = Drupal.theme(
-        'ajaxWrapperNewContent',
-        $newContent,
-        ajax,
-        response,
-      );
-
-      // If removing content from the wrapper, detach behaviors first.
-      switch (method) {
-        case 'html':
-        case 'replaceWith':
-        case 'replaceAll':
-        case 'empty':
-        case 'remove':
-          Drupal.detachBehaviors($wrapper.get(0), settings);
-          break;
-        default:
-          break;
-      }
-
-      // Add the new content to the page.
-      $wrapper[method]($newContent);
-
-      // Immediately hide the new content if we're using any effects.
-      if (effect.showEffect !== 'show') {
-        $newContent.hide();
-      }
-
-      // Determine which effect to use and what content will receive the
-      // effect, then show the new content.
-      const $ajaxNewContent = $newContent.find('.ajax-new-content');
-      if ($ajaxNewContent.length) {
-        $ajaxNewContent.hide();
-        $newContent.show();
-        $ajaxNewContent[effect.showEffect](effect.showSpeed);
-      } else if (effect.showEffect !== 'show') {
-        $newContent[effect.showEffect](effect.showSpeed);
-      }
-
-      // Attach all JavaScript behaviors to the new content, if it was
-      // successfully added to the page, this if statement allows
-      // `#ajax['wrapper']` to be optional.
-      if ($newContent.parents('html').length) {
-        // Attach behaviors to all element nodes.
-        $newContent.each((index, element) => {
-          if (element.nodeType === Node.ELEMENT_NODE) {
-            Drupal.attachBehaviors(element, settings);
-          }
-        });
-      }
-    },
-
-    /**
-     * Command to remove a chunk from the page.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {string} response.selector
-     *   A jQuery selector string.
-     * @param {object} [response.settings]
-     *   An optional array of settings that will be used.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    remove(ajax, response, status) {
-      const settings = response.settings || ajax.settings || drupalSettings;
-      $(response.selector)
-        .each(function () {
-          Drupal.detachBehaviors(this, settings);
-        })
-        .remove();
-    },
-
-    /**
-     * Command to mark a chunk changed.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The JSON response object from the Ajax request.
-     * @param {string} response.selector
-     *   A jQuery selector string.
-     * @param {bool} [response.asterisk]
-     *   An optional CSS selector. If specified, an asterisk will be
-     *   appended to the HTML inside the provided selector.
-     * @param {number} [status]
-     *   The request status.
-     */
-    changed(ajax, response, status) {
-      const $element = $(response.selector);
-      if (!$element.hasClass('ajax-changed')) {
-        $element.addClass('ajax-changed');
-        if (response.asterisk) {
-          $element
-            .find(response.asterisk)
-            .append(
-              ` <abbr class="ajax-changed" title="${Drupal.t(
-                'Changed',
-              )}">*</abbr> `,
-            );
-        }
-      }
-    },
-
-    /**
-     * Command to provide an alert.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The JSON response from the Ajax request.
-     * @param {string} response.text
-     *   The text that will be displayed in an alert dialog.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    alert(ajax, response, status) {
-      window.alert(response.text);
-    },
-
-    /**
-     * Command to provide triggers audio UAs to read the supplied text.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The JSON response from the Ajax request.
-     * @param {string} [response.text]
-     *   The text that will be read.
-     * @param {string} [response.priority]
-     *   An optional priority that will be used for the announcement.
-     */
-    announce(ajax, response) {
-      if (response.priority) {
-        Drupal.announce(response.text, response.priority);
-      } else {
-        Drupal.announce(response.text);
-      }
-    },
-
-    /**
-     * Command to set the window.location, redirecting the browser.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {string} response.url
-     *   The URL to redirect to.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    redirect(ajax, response, status) {
-      window.location = response.url;
-    },
-
-    /**
-     * Command to provide the jQuery css() function.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {string} response.selector
-     *   A jQuery selector string.
-     * @param {object} response.argument
-     *   An array of key/value pairs to set in the CSS for the selector.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    css(ajax, response, status) {
-      $(response.selector).css(response.argument);
-    },
-
-    /**
-     * Command to set the settings used for other commands in this response.
-     *
-     * This method will also remove expired `drupalSettings.ajax` settings.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {bool} response.merge
-     *   Determines whether the additional settings should be merged to the
-     *   global settings.
-     * @param {object} response.settings
-     *   Contains additional settings to add to the global settings.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    settings(ajax, response, status) {
-      const ajaxSettings = drupalSettings.ajax;
-
-      // Clean up drupalSettings.ajax.
-      if (ajaxSettings) {
-        Drupal.ajax.expired().forEach((instance) => {
-          // If the Ajax object has been created through drupalSettings.ajax
-          // it will have a selector. When there is no selector the object
-          // has been initialized with a special class name picked up by the
-          // Ajax behavior.
-
-          if (instance.selector) {
-            const selector = instance.selector.replace('#', '');
-            if (selector in ajaxSettings) {
-              delete ajaxSettings[selector];
-            }
-          }
-        });
-      }
-
-      if (response.merge) {
-        $.extend(true, drupalSettings, response.settings);
-      } else {
-        ajax.settings = response.settings;
-      }
-    },
-
-    /**
-     * Command to attach data using jQuery's data API.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {string} response.name
-     *   The name or key (in the key value pair) of the data attached to this
-     *   selector.
-     * @param {string} response.selector
-     *   A jQuery selector string.
-     * @param {string|object} response.value
-     *   The value of to be attached.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    data(ajax, response, status) {
-      $(response.selector).data(response.name, response.value);
-    },
-
-    /**
-     * Command to focus the first tabbable element within a container.
-     *
-     * If no tabbable elements are found and the container is focusable, then
-     * focus will move to that container.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {string} response.selector
-     *   A query selector string of the container to focus within.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    focusFirst(ajax, response, status) {
-      let focusChanged = false;
-      const container = document.querySelector(response.selector);
-      if (container) {
-        // Find all tabbable elements within the container.
-        const tabbableElements = tabbable(container);
-
-        // Move focus to the first tabbable item found.
-        if (tabbableElements.length) {
-          tabbableElements[0].focus();
-          focusChanged = true;
-        } else if (isFocusable(container)) {
-          // If no tabbable elements are found, but the container is focusable,
-          // move focus to the container.
-          container.focus();
-          focusChanged = true;
-        }
-      }
-
-      // If no items were available to receive focus, return focus to the
-      // triggering element.
-      if (ajax.hasOwnProperty('element') && !focusChanged) {
-        ajax.element.focus();
-      }
-    },
-
-    /**
-     * Command to apply a jQuery method.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {Array} response.args
-     *   An array of arguments to the jQuery method, if any.
-     * @param {string} response.method
-     *   The jQuery method to invoke.
-     * @param {string} response.selector
-     *   A jQuery selector string.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    invoke(ajax, response, status) {
-      const $element = $(response.selector);
-      $element[response.method](...response.args);
-    },
-
-    /**
-     * Command to restripe a table.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {string} response.selector
-     *   A jQuery selector string.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    restripe(ajax, response, status) {
-      // :even and :odd are reversed because jQuery counts from 0 and
-      // we count from 1, so we're out of sync.
-      // Match immediate children of the parent element to allow nesting.
-      $(response.selector)
-        .find('> tbody > tr:visible, > tr:visible')
-        .removeClass('odd even')
-        .filter(':even')
-        .addClass('odd')
-        .end()
-        .filter(':odd')
-        .addClass('even');
-    },
-
-    /**
-     * Command to update a form's build ID.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {string} response.old
-     *   The old form build ID.
-     * @param {string} response.new
-     *   The new form build ID.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    update_build_id(ajax, response, status) {
-      document
-        .querySelectorAll(
-          `input[name="form_build_id"][value="${response.old}"]`,
-        )
-        .forEach((item) => {
-          item.value = response.new;
-        });
-    },
-
-    /**
-     * Command to add css.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {string} response.data
-     *   A string that contains the styles to be added.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    add_css(ajax, response, status) {
-      $('head').prepend(response.data);
-    },
-
-    /**
-     * Command to add a message to the message area.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {string} response.messageWrapperQuerySelector
-     *   The zone where to add the message. If null, the default will be used.
-     * @param {string} response.message
-     *   The message text.
-     * @param {string} response.messageOptions
-     *   The options argument for Drupal.Message().add().
-     * @param {bool} response.clearPrevious
-     *   If true, clear previous messages.
-     */
-    message(ajax, response) {
-      const messages = new Drupal.Message(
-        document.querySelector(response.messageWrapperQuerySelector),
-      );
-      if (response.clearPrevious) {
-        messages.clear();
-      }
-      messages.add(response.message, response.messageOptions);
-    },
-
-    /**
-     * Command to add JS.
-     *
-     * @param {Drupal.Ajax} [ajax]
-     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-     * @param {object} response
-     *   The response from the Ajax request.
-     * @param {Array} response.data
-     *   An array of objects of script attributes.
-     * @param {number} [status]
-     *   The XMLHttpRequest status.
-     */
-    add_js(ajax, response, status) {
-      const parentEl = document.querySelector(response.selector || 'body');
-      const settings = ajax.settings || drupalSettings;
-      const allUniqueBundleIds = response.data.map((script) => {
-        // loadjs requires a unique ID, and an AJAX instance's `instanceIndex`
-        // is guaranteed to be unique.
-        // @see Drupal.behaviors.AJAX.detach
-        const uniqueBundleId = script.src + ajax.instanceIndex;
-        loadjs(script.src, uniqueBundleId, {
-          // The default loadjs behavior is to load script with async, in Drupal
-          // we need to explicitly tell scripts to load async, this is set in
-          // the before callback below if necessary.
-          async: false,
-          before(path, scriptEl) {
-            // This allows all attributes to be added, like defer, async and
-            // crossorigin.
-            Object.keys(script).forEach((attributeKey) => {
-              scriptEl.setAttribute(attributeKey, script[attributeKey]);
-            });
-
-            // By default, loadjs appends the script to the head. When scripts
-            // are loaded via AJAX, their location has no impact on
-            // functionality. But, since non-AJAX loaded scripts can choose
-            // their parent element, we provide that option here for the sake of
-            // consistency.
-            parentEl.appendChild(scriptEl);
-            // Return false to bypass loadjs' default DOM insertion mechanism.
-            return false;
-          },
-        });
-        return uniqueBundleId;
-      });
-      // Returns the promise so that the next AJAX command waits on the
-      // completion of this one to execute, ensuring the JS is loaded before
-      // executing.
-      return new Promise((resolve, reject) => {
-        loadjs.ready(allUniqueBundleIds, {
-          success() {
-            Drupal.attachBehaviors(parentEl, settings);
-            // All JS files were loaded and new and old behaviors have
-            // been attached. Resolve the promise and let the remaining
-            // commands execute.
-            resolve();
-          },
-          error(depsNotFound) {
-            const message = Drupal.t(
-              `The following files could not be loaded: @dependencies`,
-              { '@dependencies': depsNotFound.join(', ') },
-            );
-            reject(message);
-          },
-        });
-      });
-    },
-  };
-})(jQuery, window, Drupal, drupalSettings, loadjs, window.tabbable);
diff --git a/core/misc/ajax.js b/core/misc/ajax.js
index 75c97f62abe8..c8c8eb1cd39e 100644
--- a/core/misc/ajax.js
+++ b/core/misc/ajax.js
@@ -1,115 +1,255 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(function ($, window, Drupal, drupalSettings, loadjs, _ref) {
-  let {
-    isFocusable,
-    tabbable
-  } = _ref;
+ * @file
+ * Provides Ajax page updating via jQuery $.ajax.
+ *
+ * Ajax is a method of making a request via JavaScript while viewing an HTML
+ * page. The request returns an array of commands encoded in JSON, which is
+ * then executed to make any changes that are necessary to the page.
+ *
+ * Drupal uses this file to enhance form elements with `#ajax['url']` and
+ * `#ajax['wrapper']` properties. If set, this file will automatically be
+ * included to provide Ajax capabilities.
+ */
+
+(function (
+  $,
+  window,
+  Drupal,
+  drupalSettings,
+  loadjs,
+  { isFocusable, tabbable },
+) {
+  /**
+   * Attaches the Ajax behavior to each Ajax form element.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Initialize all {@link Drupal.Ajax} objects declared in
+   *   `drupalSettings.ajax` or initialize {@link Drupal.Ajax} objects from
+   *   DOM elements having the `use-ajax-submit` or `use-ajax` css class.
+   * @prop {Drupal~behaviorDetach} detach
+   *   During `unload` remove all {@link Drupal.Ajax} objects related to
+   *   the removed content.
+   */
   Drupal.behaviors.AJAX = {
     attach(context, settings) {
       function loadAjaxBehavior(base) {
         const elementSettings = settings.ajax[base];
-
         if (typeof elementSettings.selector === 'undefined') {
           elementSettings.selector = `#${base}`;
         }
-
-        once('drupal-ajax', $(elementSettings.selector)).forEach(el => {
+        // Use jQuery selector instead of a native selector for
+        // backwards compatibility.
+        once('drupal-ajax', $(elementSettings.selector)).forEach((el) => {
           elementSettings.element = el;
           elementSettings.base = base;
           Drupal.ajax(elementSettings);
         });
       }
 
-      Object.keys(settings.ajax || {}).forEach(base => loadAjaxBehavior(base));
+      // Load all Ajax behaviors specified in the settings.
+      Object.keys(settings.ajax || {}).forEach((base) =>
+        loadAjaxBehavior(base),
+      );
+
       Drupal.ajax.bindAjaxLinks(document.body);
-      once('ajax', '.use-ajax-submit').forEach(el => {
+
+      // This class means to submit the form to the action using Ajax.
+      once('ajax', '.use-ajax-submit').forEach((el) => {
         const elementSettings = {};
+
+        // Ajax submits specified in this manner automatically submit to the
+        // normal form action.
         elementSettings.url = $(el.form).attr('action');
+        // Form submit button clicks need to tell the form what was clicked so
+        // it gets passed in the POST request.
         elementSettings.setClick = true;
+        // Form buttons use the 'click' event rather than mousedown.
         elementSettings.event = 'click';
-        elementSettings.progress = {
-          type: 'throbber'
-        };
+        // Clicked form buttons look better with the throbber than the progress
+        // bar.
+        elementSettings.progress = { type: 'throbber' };
         elementSettings.base = el.id;
         elementSettings.element = el;
+
         Drupal.ajax(elementSettings);
       });
     },
 
     detach(context, settings, trigger) {
       if (trigger === 'unload') {
-        Drupal.ajax.expired().forEach(instance => {
+        Drupal.ajax.expired().forEach((instance) => {
+          // Set this to null and allow garbage collection to reclaim
+          // the memory.
           Drupal.ajax.instances[instance.instanceIndex] = null;
         });
       }
-    }
-
+    },
   };
 
+  /**
+   * Extends Error to provide handling for Errors in Ajax.
+   *
+   * @constructor
+   *
+   * @augments Error
+   *
+   * @param {XMLHttpRequest} xmlhttp
+   *   XMLHttpRequest object used for the failed request.
+   * @param {string} uri
+   *   The URI where the error occurred.
+   * @param {string} customMessage
+   *   The custom message.
+   */
   Drupal.AjaxError = function (xmlhttp, uri, customMessage) {
     let statusCode;
     let statusText;
     let responseText;
-
     if (xmlhttp.status) {
-      statusCode = `\n${Drupal.t('An AJAX HTTP error occurred.')}\n${Drupal.t('HTTP Result Code: !status', {
-        '!status': xmlhttp.status
-      })}`;
+      statusCode = `\n${Drupal.t('An AJAX HTTP error occurred.')}\n${Drupal.t(
+        'HTTP Result Code: !status',
+        {
+          '!status': xmlhttp.status,
+        },
+      )}`;
     } else {
-      statusCode = `\n${Drupal.t('An AJAX HTTP request terminated abnormally.')}`;
+      statusCode = `\n${Drupal.t(
+        'An AJAX HTTP request terminated abnormally.',
+      )}`;
     }
-
     statusCode += `\n${Drupal.t('Debugging information follows.')}`;
-    const pathText = `\n${Drupal.t('Path: !uri', {
-      '!uri': uri
-    })}`;
+    const pathText = `\n${Drupal.t('Path: !uri', { '!uri': uri })}`;
     statusText = '';
-
+    // In some cases, when statusCode === 0, xmlhttp.statusText may not be
+    // defined. Unfortunately, testing for it with typeof, etc, doesn't seem to
+    // catch that and the test causes an exception. So we need to catch the
+    // exception here.
     try {
       statusText = `\n${Drupal.t('StatusText: !statusText', {
-        '!statusText': xmlhttp.statusText.trim()
+        '!statusText': xmlhttp.statusText.trim(),
       })}`;
-    } catch (e) {}
+    } catch (e) {
+      // Empty.
+    }
 
     responseText = '';
-
+    // Again, we don't have a way to know for sure whether accessing
+    // xmlhttp.responseText is going to throw an exception. So we'll catch it.
     try {
       responseText = `\n${Drupal.t('ResponseText: !responseText', {
-        '!responseText': xmlhttp.responseText.trim()
+        '!responseText': xmlhttp.responseText.trim(),
       })}`;
-    } catch (e) {}
+    } catch (e) {
+      // Empty.
+    }
 
+    // Make the responseText more readable by stripping HTML tags and newlines.
     responseText = responseText.replace(/<("[^"]*"|'[^']*'|[^'">])*>/gi, '');
     responseText = responseText.replace(/[\n]+\s+/g, '\n');
-    const readyStateText = xmlhttp.status === 0 ? `\n${Drupal.t('ReadyState: !readyState', {
-      '!readyState': xmlhttp.readyState
-    })}` : '';
-    customMessage = customMessage ? `\n${Drupal.t('CustomMessage: !customMessage', {
-      '!customMessage': customMessage
-    })}` : '';
-    this.message = statusCode + pathText + statusText + customMessage + responseText + readyStateText;
+
+    // We don't need readyState except for status == 0.
+    const readyStateText =
+      xmlhttp.status === 0
+        ? `\n${Drupal.t('ReadyState: !readyState', {
+            '!readyState': xmlhttp.readyState,
+          })}`
+        : '';
+
+    customMessage = customMessage
+      ? `\n${Drupal.t('CustomMessage: !customMessage', {
+          '!customMessage': customMessage,
+        })}`
+      : '';
+
+    /**
+     * Formatted and translated error message.
+     *
+     * @type {string}
+     */
+    this.message =
+      statusCode +
+      pathText +
+      statusText +
+      customMessage +
+      responseText +
+      readyStateText;
+
+    /**
+     * Used by some browsers to display a more accurate stack trace.
+     *
+     * @type {string}
+     */
     this.name = 'AjaxError';
   };
 
   Drupal.AjaxError.prototype = new Error();
   Drupal.AjaxError.prototype.constructor = Drupal.AjaxError;
 
+  /**
+   * Provides Ajax page updating via jQuery $.ajax.
+   *
+   * This function is designed to improve developer experience by wrapping the
+   * initialization of {@link Drupal.Ajax} objects and storing all created
+   * objects in the {@link Drupal.ajax.instances} array.
+   *
+   * @example
+   * Drupal.behaviors.myCustomAJAXStuff = {
+   *   attach: function (context, settings) {
+   *
+   *     var ajaxSettings = {
+   *       url: 'my/url/path',
+   *       // If the old version of Drupal.ajax() needs to be used those
+   *       // properties can be added
+   *       base: 'myBase',
+   *       element: $(context).find('.someElement')
+   *     };
+   *
+   *     var myAjaxObject = Drupal.ajax(ajaxSettings);
+   *
+   *     // Declare a new Ajax command specifically for this Ajax object.
+   *     myAjaxObject.commands.insert = function (ajax, response, status) {
+   *       $('#my-wrapper').append(response.data);
+   *       alert('New content was appended to #my-wrapper');
+   *     };
+   *
+   *     // This command will remove this Ajax object from the page.
+   *     myAjaxObject.commands.destroyObject = function (ajax, response, status) {
+   *       Drupal.ajax.instances[this.instanceIndex] = null;
+   *     };
+   *
+   *     // Programmatically trigger the Ajax request.
+   *     myAjaxObject.execute();
+   *   }
+   * };
+   *
+   * @param {object} settings
+   *   The settings object passed to {@link Drupal.Ajax} constructor.
+   * @param {string} [settings.base]
+   *   Base is passed to {@link Drupal.Ajax} constructor as the 'base'
+   *   parameter.
+   * @param {HTMLElement} [settings.element]
+   *   Element parameter of {@link Drupal.Ajax} constructor, element on which
+   *   event listeners will be bound.
+   *
+   * @return {Drupal.Ajax}
+   *   The created Ajax object.
+   *
+   * @see Drupal.AjaxCommands
+   */
   Drupal.ajax = function (settings) {
     if (arguments.length !== 1) {
-      throw new Error('Drupal.ajax() function must be called with one configuration object only');
+      throw new Error(
+        'Drupal.ajax() function must be called with one configuration object only',
+      );
     }
-
+    // Map those config keys to variables for the old Drupal.ajax function.
     const base = settings.base || false;
     const element = settings.element || false;
     delete settings.base;
     delete settings.element;
 
+    // By default do not display progress for ajax calls without an element.
     if (!settings.progress && !element) {
       settings.progress = false;
     }
@@ -117,39 +257,128 @@
     const ajax = new Drupal.Ajax(base, element, settings);
     ajax.instanceIndex = Drupal.ajax.instances.length;
     Drupal.ajax.instances.push(ajax);
+
     return ajax;
   };
 
+  /**
+   * Contains all created Ajax objects.
+   *
+   * @type {Array.<Drupal.Ajax|null>}
+   */
   Drupal.ajax.instances = [];
 
+  /**
+   * List all objects where the associated element is not in the DOM
+   *
+   * This method ignores {@link Drupal.Ajax} objects not bound to DOM elements
+   * when created with {@link Drupal.ajax}.
+   *
+   * @return {Array.<Drupal.Ajax>}
+   *   The list of expired {@link Drupal.Ajax} objects.
+   */
   Drupal.ajax.expired = function () {
-    return Drupal.ajax.instances.filter(instance => instance && instance.element !== false && !document.body.contains(instance.element));
+    return Drupal.ajax.instances.filter(
+      (instance) =>
+        instance &&
+        instance.element !== false &&
+        !document.body.contains(instance.element),
+    );
   };
 
-  Drupal.ajax.bindAjaxLinks = element => {
-    once('ajax', '.use-ajax', element).forEach(ajaxLink => {
+  /**
+   * Bind Ajax functionality to links that use the 'use-ajax' class.
+   *
+   * @param {HTMLElement} element
+   *   Element to enable Ajax functionality for.
+   */
+  Drupal.ajax.bindAjaxLinks = (element) => {
+    // Bind Ajax behaviors to all items showing the class.
+    once('ajax', '.use-ajax', element).forEach((ajaxLink) => {
       const $linkElement = $(ajaxLink);
+
       const elementSettings = {
-        progress: {
-          type: 'throbber'
-        },
+        // Clicked links look better with the throbber than the progress bar.
+        progress: { type: 'throbber' },
         dialogType: $linkElement.data('dialog-type'),
         dialog: $linkElement.data('dialog-options'),
         dialogRenderer: $linkElement.data('dialog-renderer'),
         base: $linkElement.attr('id'),
-        element: ajaxLink
+        element: ajaxLink,
       };
       const href = $linkElement.attr('href');
-
+      /**
+       * For anchor tags, these will go to the target of the anchor rather than
+       * the usual location.
+       */
       if (href) {
         elementSettings.url = href;
         elementSettings.event = 'click';
       }
-
       Drupal.ajax(elementSettings);
     });
   };
 
+  /**
+   * Settings for an Ajax object.
+   *
+   * @typedef {object} Drupal.Ajax~elementSettings
+   *
+   * @prop {string} url
+   *   Target of the Ajax request.
+   * @prop {?string} [event]
+   *   Event bound to settings.element which will trigger the Ajax request.
+   * @prop {bool} [keypress=true]
+   *   Triggers a request on keypress events.
+   * @prop {?string} selector
+   *   jQuery selector targeting the element to bind events to or used with
+   *   {@link Drupal.AjaxCommands}.
+   * @prop {string} [effect='none']
+   *   Name of the jQuery method to use for displaying new Ajax content.
+   * @prop {string|number} [speed='none']
+   *   Speed with which to apply the effect.
+   * @prop {string} [method]
+   *   Name of the jQuery method used to insert new content in the targeted
+   *   element.
+   * @prop {object} [progress]
+   *   Settings for the display of a user-friendly loader.
+   * @prop {string} [progress.type='throbber']
+   *   Type of progress element, core provides `'bar'`, `'throbber'` and
+   *   `'fullscreen'`.
+   * @prop {string} [progress.message=Drupal.t('Please wait...')]
+   *   Custom message to be used with the bar indicator.
+   * @prop {object} [submit]
+   *   Extra data to be sent with the Ajax request.
+   * @prop {bool} [submit.js=true]
+   *   Allows the PHP side to know this comes from an Ajax request.
+   * @prop {object} [dialog]
+   *   Options for {@link Drupal.dialog}.
+   * @prop {string} [dialogType]
+   *   One of `'modal'` or `'dialog'`.
+   * @prop {string} [prevent]
+   *   List of events on which to stop default action and stop propagation.
+   */
+
+  /**
+   * Ajax constructor.
+   *
+   * The Ajax request returns an array of commands encoded in JSON, which is
+   * then executed to make any changes that are necessary to the page.
+   *
+   * Drupal uses this file to enhance form elements with `#ajax['url']` and
+   * `#ajax['wrapper']` properties. If set, this file will automatically be
+   * included to provide Ajax capabilities.
+   *
+   * @constructor
+   *
+   * @param {string} [base]
+   *   Base parameter of {@link Drupal.Ajax} constructor
+   * @param {HTMLElement} [element]
+   *   Element parameter of {@link Drupal.Ajax} constructor, element on which
+   *   event listeners will be bound.
+   * @param {Drupal.Ajax~elementSettings} elementSettings
+   *   Settings for this Ajax object.
+   */
   Drupal.Ajax = function (base, element, elementSettings) {
     const defaults = {
       event: element ? 'mousedown' : null,
@@ -160,30 +389,58 @@
       method: 'replaceWith',
       progress: {
         type: 'throbber',
-        message: Drupal.t('Please wait...')
+        message: Drupal.t('Please wait...'),
       },
       submit: {
-        js: true
-      }
+        js: true,
+      },
     };
+
     $.extend(this, defaults, elementSettings);
+
+    /**
+     * @type {Drupal.AjaxCommands}
+     */
     this.commands = new Drupal.AjaxCommands();
+
+    /**
+     * @type {bool|number}
+     */
     this.instanceIndex = false;
 
+    // @todo Remove this after refactoring the PHP code to:
+    //   - Call this 'selector'.
+    //   - Include the '#' for ID-based selectors.
+    //   - Support non-ID-based selectors.
     if (this.wrapper) {
+      /**
+       * @type {string}
+       */
       this.wrapper = `#${this.wrapper}`;
     }
 
+    /**
+     * @type {HTMLElement}
+     */
     this.element = element;
+
+    /**
+     * @type {Drupal.Ajax~elementSettings}
+     */
     this.elementSettings = elementSettings;
 
+    // If there isn't a form, jQuery.ajax() will be used instead, allowing us to
+    // bind Ajax to links as well.
     if (this.element && this.element.form) {
+      /**
+       * @type {jQuery}
+       */
       this.$form = $(this.element.form);
     }
 
+    // If no Ajax callback URL was given, use the link href or form action.
     if (!this.url) {
       const $element = $(this.element);
-
       if ($element.is('a')) {
         this.url = $element.attr('href');
       } else if (this.element && element.form) {
@@ -191,142 +448,305 @@
       }
     }
 
+    // Replacing 'nojs' with 'ajax' in the URL allows for an easy method to let
+    // the server detect when it needs to degrade gracefully.
+    // There are four scenarios to check for:
+    // 1. /nojs/
+    // 2. /nojs$ - The end of a URL string.
+    // 3. /nojs? - Followed by a query (e.g. path/nojs?destination=foobar).
+    // 4. /nojs# - Followed by a fragment (e.g.: path/nojs#my-fragment).
     const originalUrl = this.url;
-    this.url = this.url.replace(/\/nojs(\/|$|\?|#)/, '/ajax$1');
 
+    /**
+     * Processed Ajax URL.
+     *
+     * @type {string}
+     */
+    this.url = this.url.replace(/\/nojs(\/|$|\?|#)/, '/ajax$1');
+    // If the 'nojs' version of the URL is trusted, also trust the 'ajax'
+    // version.
     if (drupalSettings.ajaxTrustedUrl[originalUrl]) {
       drupalSettings.ajaxTrustedUrl[this.url] = true;
     }
 
+    // Set the options for the ajaxSubmit function.
+    // The 'this' variable will not persist inside of the options object.
     const ajax = this;
+
+    /**
+     * Options for the jQuery.ajax function.
+     *
+     * @name Drupal.Ajax#options
+     *
+     * @type {object}
+     *
+     * @prop {string} url
+     *   Ajax URL to be called.
+     * @prop {object} data
+     *   Ajax payload.
+     * @prop {function} beforeSerialize
+     *   Implement jQuery beforeSerialize function to call
+     *   {@link Drupal.Ajax#beforeSerialize}.
+     * @prop {function} beforeSubmit
+     *   Implement jQuery beforeSubmit function to call
+     *   {@link Drupal.Ajax#beforeSubmit}.
+     * @prop {function} beforeSend
+     *   Implement jQuery beforeSend function to call
+     *   {@link Drupal.Ajax#beforeSend}.
+     * @prop {function} success
+     *   Implement jQuery success function to call
+     *   {@link Drupal.Ajax#success}.
+     * @prop {function} complete
+     *   Implement jQuery success function to clean up ajax state and trigger an
+     *   error if needed.
+     * @prop {string} dataType='json'
+     *   Type of the response expected.
+     * @prop {string} type='POST'
+     *   HTTP method to use for the Ajax request.
+     */
     ajax.options = {
       url: ajax.url,
       data: ajax.submit,
-
       beforeSerialize(elementSettings, options) {
         return ajax.beforeSerialize(elementSettings, options);
       },
-
       beforeSubmit(formValues, elementSettings, options) {
         ajax.ajaxing = true;
         return ajax.beforeSubmit(formValues, elementSettings, options);
       },
-
       beforeSend(xmlhttprequest, options) {
         ajax.ajaxing = true;
         return ajax.beforeSend(xmlhttprequest, options);
       },
-
       success(response, status, xmlhttprequest) {
+        // Sanity check for browser support (object expected).
+        // When using iFrame uploads, responses must be returned as a string.
         if (typeof response === 'string') {
           response = $.parseJSON(response);
         }
 
+        // Prior to invoking the response's commands, verify that they can be
+        // trusted by checking for a response header. See
+        // \Drupal\Core\EventSubscriber\AjaxResponseSubscriber for details.
+        // - Empty responses are harmless so can bypass verification. This
+        //   avoids an alert message for server-generated no-op responses that
+        //   skip Ajax rendering.
+        // - Ajax objects with trusted URLs (e.g., ones defined server-side via
+        //   #ajax) can bypass header verification. This is especially useful
+        //   for Ajax with multipart forms. Because IFRAME transport is used,
+        //   the response headers cannot be accessed for verification.
         if (response !== null && !drupalSettings.ajaxTrustedUrl[ajax.url]) {
           if (xmlhttprequest.getResponseHeader('X-Drupal-Ajax-Token') !== '1') {
-            const customMessage = Drupal.t('The response failed verification so will not be processed.');
+            const customMessage = Drupal.t(
+              'The response failed verification so will not be processed.',
+            );
             return ajax.error(xmlhttprequest, ajax.url, customMessage);
           }
         }
 
-        return Promise.resolve(ajax.success(response, status)).then(() => {
-          ajax.ajaxing = false;
-        });
+        return (
+          // Ensure that the return of the success callback is a Promise.
+          // When the return is a Promise, using resolve will unwrap it, and
+          // when the return is not a Promise we make sure it can be used as
+          // one. This is useful for code that overrides the success method.
+          Promise.resolve(ajax.success(response, status))
+            // Ajaxing status is back to false when all the AJAX commands have
+            // finished executing.
+            .then(() => {
+              ajax.ajaxing = false;
+            })
+        );
       },
-
       error(xmlhttprequest, status, error) {
         ajax.ajaxing = false;
       },
-
       complete(xmlhttprequest, status) {
         if (status === 'error' || status === 'parsererror') {
           return ajax.error(xmlhttprequest, ajax.url);
         }
       },
-
       dataType: 'json',
       jsonp: false,
-      type: 'POST'
+      type: 'POST',
     };
 
     if (elementSettings.dialog) {
       ajax.options.data.dialogOptions = elementSettings.dialog;
     }
 
+    // Ensure that we have a valid URL by adding ? when no query parameter is
+    // yet available, otherwise append using &.
     if (ajax.options.url.indexOf('?') === -1) {
       ajax.options.url += '?';
     } else {
       ajax.options.url += '&';
     }
-
+    // If this element has a dialog type use if for the wrapper if not use 'ajax'.
     let wrapper = `drupal_${elementSettings.dialogType || 'ajax'}`;
-
     if (elementSettings.dialogRenderer) {
       wrapper += `.${elementSettings.dialogRenderer}`;
     }
-
     ajax.options.url += `${Drupal.ajax.WRAPPER_FORMAT}=${wrapper}`;
+
+    // Bind the ajaxSubmit function to the element event.
     $(ajax.element).on(elementSettings.event, function (event) {
-      if (!drupalSettings.ajaxTrustedUrl[ajax.url] && !Drupal.url.isLocal(ajax.url)) {
-        throw new Error(Drupal.t('The callback URL is not local and not trusted: !url', {
-          '!url': ajax.url
-        }));
+      if (
+        !drupalSettings.ajaxTrustedUrl[ajax.url] &&
+        !Drupal.url.isLocal(ajax.url)
+      ) {
+        throw new Error(
+          Drupal.t('The callback URL is not local and not trusted: !url', {
+            '!url': ajax.url,
+          }),
+        );
       }
-
       return ajax.eventResponse(this, event);
     });
 
+    // If necessary, enable keyboard submission so that Ajax behaviors
+    // can be triggered through keyboard input as well as e.g. a mousedown
+    // action.
     if (elementSettings.keypress) {
       $(ajax.element).on('keypress', function (event) {
         return ajax.keypressResponse(this, event);
       });
     }
 
+    // If necessary, prevent the browser default action of an additional event.
+    // For example, prevent the browser default action of a click, even if the
+    // Ajax behavior binds to mousedown.
     if (elementSettings.prevent) {
       $(ajax.element).on(elementSettings.prevent, false);
     }
   };
 
+  /**
+   * URL query attribute to indicate the wrapper used to render a request.
+   *
+   * The wrapper format determines how the HTML is wrapped, for example in a
+   * modal dialog.
+   *
+   * @const {string}
+   *
+   * @default
+   */
   Drupal.ajax.WRAPPER_FORMAT = '_wrapper_format';
+
+  /**
+   * Request parameter to indicate that a request is a Drupal Ajax request.
+   *
+   * @const {string}
+   *
+   * @default
+   */
   Drupal.Ajax.AJAX_REQUEST_PARAMETER = '_drupal_ajax';
 
+  /**
+   * Execute the ajax request.
+   *
+   * Allows developers to execute an Ajax request manually without specifying
+   * an event to respond to.
+   *
+   * @return {object}
+   *   Returns the jQuery.Deferred object underlying the Ajax request. If
+   *   pre-serialization fails, the Deferred will be returned in the rejected
+   *   state.
+   */
   Drupal.Ajax.prototype.execute = function () {
+    // Do not perform another ajax command if one is already in progress.
     if (this.ajaxing) {
       return;
     }
 
     try {
       this.beforeSerialize(this.element, this.options);
+      // Return the jqXHR so that external code can hook into the Deferred API.
       return $.ajax(this.options);
     } catch (e) {
+      // Unset the ajax.ajaxing flag here because it won't be unset during
+      // the complete response.
       this.ajaxing = false;
-      window.alert(`An error occurred while attempting to process ${this.options.url}: ${e.message}`);
+      window.alert(
+        `An error occurred while attempting to process ${this.options.url}: ${e.message}`,
+      );
+      // For consistency, return a rejected Deferred (i.e., jqXHR's superclass)
+      // so that calling code can take appropriate action.
       return $.Deferred().reject();
     }
   };
 
+  /**
+   * Handle a key press.
+   *
+   * The Ajax object will, if instructed, bind to a key press response. This
+   * will test to see if the key press is valid to trigger this event and
+   * if it is, trigger it for us and prevent other keypresses from triggering.
+   * In this case we're handling RETURN and SPACEBAR keypresses (event codes 13
+   * and 32. RETURN is often used to submit a form when in a textfield, and
+   * SPACE is often used to activate an element without submitting.
+   *
+   * @param {HTMLElement} element
+   *   Element the event was triggered on.
+   * @param {jQuery.Event} event
+   *   Triggered event.
+   */
   Drupal.Ajax.prototype.keypressResponse = function (element, event) {
+    // Create a synonym for this to reduce code confusion.
     const ajax = this;
 
-    if (event.which === 13 || event.which === 32 && element.type !== 'text' && element.type !== 'textarea' && element.type !== 'tel' && element.type !== 'number') {
+    // Detect enter key and space bar and allow the standard response for them,
+    // except for form elements of type 'text', 'tel', 'number' and 'textarea',
+    // where the spacebar activation causes inappropriate activation if
+    // #ajax['keypress'] is TRUE. On a text-type widget a space should always
+    // be a space.
+    if (
+      event.which === 13 ||
+      (event.which === 32 &&
+        element.type !== 'text' &&
+        element.type !== 'textarea' &&
+        element.type !== 'tel' &&
+        element.type !== 'number')
+    ) {
       event.preventDefault();
       event.stopPropagation();
       $(element).trigger(ajax.elementSettings.event);
     }
   };
 
+  /**
+   * Handle an event that triggers an Ajax response.
+   *
+   * When an event that triggers an Ajax response happens, this method will
+   * perform the actual Ajax call. It is bound to the event using
+   * bind() in the constructor, and it uses the options specified on the
+   * Ajax object.
+   *
+   * @param {HTMLElement} element
+   *   Element the event was triggered on.
+   * @param {jQuery.Event} event
+   *   Triggered event.
+   */
   Drupal.Ajax.prototype.eventResponse = function (element, event) {
     event.preventDefault();
     event.stopPropagation();
+
+    // Create a synonym for this to reduce code confusion.
     const ajax = this;
 
+    // Do not perform another Ajax command if one is already in progress.
     if (ajax.ajaxing) {
       return;
     }
 
     try {
       if (ajax.$form) {
+        // If setClick is set, we must set this to ensure that the button's
+        // value is passed.
         if (ajax.setClick) {
+          // Mark the clicked button. 'form.clk' is a special variable for
+          // ajaxSubmit that tells the system which element got clicked to
+          // trigger the submit. Without it there would be no 'op' or
+          // equivalent.
           element.form.clk = element;
         }
 
@@ -336,148 +756,358 @@
         $.ajax(ajax.options);
       }
     } catch (e) {
+      // Unset the ajax.ajaxing flag here because it won't be unset during
+      // the complete response.
       ajax.ajaxing = false;
-      window.alert(`An error occurred while attempting to process ${ajax.options.url}: ${e.message}`);
+      window.alert(
+        `An error occurred while attempting to process ${ajax.options.url}: ${e.message}`,
+      );
     }
   };
 
+  /**
+   * Handler for the form serialization.
+   *
+   * Runs before the beforeSend() handler (see below), and unlike that one, runs
+   * before field data is collected.
+   *
+   * @param {object} [element]
+   *   Ajax object's `elementSettings`.
+   * @param {object} options
+   *   jQuery.ajax options.
+   */
   Drupal.Ajax.prototype.beforeSerialize = function (element, options) {
+    // Allow detaching behaviors to update field values before collecting them.
+    // This is only needed when field values are added to the POST data, so only
+    // when there is a form such that this.$form.ajaxSubmit() is used instead of
+    // $.ajax(). When there is no form and $.ajax() is used, beforeSerialize()
+    // isn't called, but don't rely on that: explicitly check this.$form.
     if (this.$form && document.body.contains(this.$form.get(0))) {
       const settings = this.settings || drupalSettings;
       Drupal.detachBehaviors(this.$form.get(0), settings, 'serialize');
     }
 
+    // Inform Drupal that this is an AJAX request.
     options.data[Drupal.Ajax.AJAX_REQUEST_PARAMETER] = 1;
+
+    // Allow Drupal to return new JavaScript and CSS files to load without
+    // returning the ones already loaded.
+    // @see \Drupal\Core\Theme\AjaxBasePageNegotiator
+    // @see \Drupal\Core\Asset\LibraryDependencyResolverInterface::getMinimalRepresentativeSubset()
+    // @see system_js_settings_alter()
     const pageState = drupalSettings.ajaxPageState;
     options.data['ajax_page_state[theme]'] = pageState.theme;
     options.data['ajax_page_state[theme_token]'] = pageState.theme_token;
     options.data['ajax_page_state[libraries]'] = pageState.libraries;
   };
 
-  Drupal.Ajax.prototype.beforeSubmit = function (formValues, element, options) {};
+  /**
+   * Modify form values prior to form submission.
+   *
+   * @param {Array.<object>} formValues
+   *   Processed form values.
+   * @param {jQuery} element
+   *   The form node as a jQuery object.
+   * @param {object} options
+   *   jQuery.ajax options.
+   */
+  Drupal.Ajax.prototype.beforeSubmit = function (formValues, element, options) {
+    // This function is left empty to make it simple to override for modules
+    // that wish to add functionality here.
+  };
 
+  /**
+   * Prepare the Ajax request before it is sent.
+   *
+   * @param {XMLHttpRequest} xmlhttprequest
+   *   Native Ajax object.
+   * @param {object} options
+   *   jQuery.ajax options.
+   */
   Drupal.Ajax.prototype.beforeSend = function (xmlhttprequest, options) {
+    // For forms without file inputs, the jQuery Form plugin serializes the
+    // form values, and then calls jQuery's $.ajax() function, which invokes
+    // this handler. In this circumstance, options.extraData is never used. For
+    // forms with file inputs, the jQuery Form plugin uses the browser's normal
+    // form submission mechanism, but captures the response in a hidden IFRAME.
+    // In this circumstance, it calls this handler first, and then appends
+    // hidden fields to the form to submit the values in options.extraData.
+    // There is no simple way to know which submission mechanism will be used,
+    // so we add to extraData regardless, and allow it to be ignored in the
+    // former case.
     if (this.$form) {
       options.extraData = options.extraData || {};
+
+      // Let the server know when the IFRAME submission mechanism is used. The
+      // server can use this information to wrap the JSON response in a
+      // TEXTAREA, as per http://jquery.malsup.com/form/#file-upload.
       options.extraData.ajax_iframe_upload = '1';
-      const v = $.fieldValue(this.element);
 
+      // The triggering element is about to be disabled (see below), but if it
+      // contains a value (e.g., a checkbox, textfield, select, etc.), ensure
+      // that value is included in the submission. As per above, submissions
+      // that use $.ajax() are already serialized prior to the element being
+      // disabled, so this is only needed for IFRAME submissions.
+      const v = $.fieldValue(this.element);
       if (v !== null) {
         options.extraData[this.element.name] = v;
       }
     }
 
+    // Disable the element that received the change to prevent user interface
+    // interaction while the Ajax request is in progress. ajax.ajaxing prevents
+    // the element from triggering a new request, but does not prevent the user
+    // from changing its value.
     $(this.element).prop('disabled', true);
 
     if (!this.progress || !this.progress.type) {
       return;
     }
 
-    const progressIndicatorMethod = `setProgressIndicator${this.progress.type.slice(0, 1).toUpperCase()}${this.progress.type.slice(1).toLowerCase()}`;
-
-    if (progressIndicatorMethod in this && typeof this[progressIndicatorMethod] === 'function') {
+    // Insert progress indicator.
+    const progressIndicatorMethod = `setProgressIndicator${this.progress.type
+      .slice(0, 1)
+      .toUpperCase()}${this.progress.type.slice(1).toLowerCase()}`;
+    if (
+      progressIndicatorMethod in this &&
+      typeof this[progressIndicatorMethod] === 'function'
+    ) {
       this[progressIndicatorMethod].call(this);
     }
   };
 
-  Drupal.theme.ajaxProgressThrobber = message => {
-    const messageMarkup = typeof message === 'string' ? Drupal.theme('ajaxProgressMessage', message) : '';
+  /**
+   * An animated progress throbber and container element for AJAX operations.
+   *
+   * @param {string} [message]
+   *   (optional) The message shown on the UI.
+   * @return {string}
+   *   The HTML markup for the throbber.
+   */
+  Drupal.theme.ajaxProgressThrobber = (message) => {
+    // Build markup without adding extra white space since it affects rendering.
+    const messageMarkup =
+      typeof message === 'string'
+        ? Drupal.theme('ajaxProgressMessage', message)
+        : '';
     const throbber = '<div class="throbber">&nbsp;</div>';
+
     return `<div class="ajax-progress ajax-progress-throbber">${throbber}${messageMarkup}</div>`;
   };
 
-  Drupal.theme.ajaxProgressIndicatorFullscreen = () => '<div class="ajax-progress ajax-progress-fullscreen">&nbsp;</div>';
-
-  Drupal.theme.ajaxProgressMessage = message => `<div class="message">${message}</div>`;
-
-  Drupal.theme.ajaxProgressBar = $element => $('<div class="ajax-progress ajax-progress-bar"></div>').append($element);
-
+  /**
+   * An animated progress throbber and container element for AJAX operations.
+   *
+   * @return {string}
+   *   The HTML markup for the throbber.
+   */
+  Drupal.theme.ajaxProgressIndicatorFullscreen = () =>
+    '<div class="ajax-progress ajax-progress-fullscreen">&nbsp;</div>';
+
+  /**
+   * Formats text accompanying the AJAX progress throbber.
+   *
+   * @param {string} message
+   *   The message shown on the UI.
+   * @return {string}
+   *   The HTML markup for the throbber.
+   */
+  Drupal.theme.ajaxProgressMessage = (message) =>
+    `<div class="message">${message}</div>`;
+
+  /**
+   * Provide a wrapper for the AJAX progress bar element.
+   *
+   * @param {jQuery} $element
+   *   Progress bar element.
+   * @return {string}
+   *   The HTML markup for the progress bar.
+   */
+  Drupal.theme.ajaxProgressBar = ($element) =>
+    $('<div class="ajax-progress ajax-progress-bar"></div>').append($element);
+
+  /**
+   * Sets the progress bar progress indicator.
+   */
   Drupal.Ajax.prototype.setProgressIndicatorBar = function () {
-    const progressBar = new Drupal.ProgressBar(`ajax-progress-${this.element.id}`, $.noop, this.progress.method, $.noop);
-
+    const progressBar = new Drupal.ProgressBar(
+      `ajax-progress-${this.element.id}`,
+      $.noop,
+      this.progress.method,
+      $.noop,
+    );
     if (this.progress.message) {
       progressBar.setProgress(-1, this.progress.message);
     }
-
     if (this.progress.url) {
-      progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500);
+      progressBar.startMonitoring(
+        this.progress.url,
+        this.progress.interval || 1500,
+      );
     }
-
-    this.progress.element = $(Drupal.theme('ajaxProgressBar', progressBar.element));
+    this.progress.element = $(
+      Drupal.theme('ajaxProgressBar', progressBar.element),
+    );
     this.progress.object = progressBar;
     $(this.element).after(this.progress.element);
   };
 
+  /**
+   * Sets the throbber progress indicator.
+   */
   Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () {
-    this.progress.element = $(Drupal.theme('ajaxProgressThrobber', this.progress.message));
+    this.progress.element = $(
+      Drupal.theme('ajaxProgressThrobber', this.progress.message),
+    );
     $(this.element).after(this.progress.element);
   };
 
+  /**
+   * Sets the fullscreen progress indicator.
+   */
   Drupal.Ajax.prototype.setProgressIndicatorFullscreen = function () {
     this.progress.element = $(Drupal.theme('ajaxProgressIndicatorFullscreen'));
     $('body').append(this.progress.element);
   };
 
+  /**
+   * Helper method to make sure commands are executed in sequence.
+   *
+   * @param {Array.<Drupal.AjaxCommands~commandDefinition>} response
+   *   Drupal Ajax response.
+   * @param {number} status
+   *   XMLHttpRequest status.
+   *
+   * @return {Promise}
+   *  The promise that will resolve once all commands have finished executing.
+   */
   Drupal.Ajax.prototype.commandExecutionQueue = function (response, status) {
     const ajaxCommands = this.commands;
-    return Object.keys(response || {}).reduce((executionQueue, key) => executionQueue.then(() => {
-      const {
-        command
-      } = response[key];
-
-      if (command && ajaxCommands[command]) {
-        return ajaxCommands[command](this, response[key], status);
-      }
-    }), Promise.resolve());
+    return Object.keys(response || {}).reduce(
+      // Add all commands to a single execution queue.
+      (executionQueue, key) =>
+        executionQueue.then(() => {
+          const { command } = response[key];
+          if (command && ajaxCommands[command]) {
+            // When a command returns a promise, the remaining commands will not
+            // execute until that promise has been fulfilled. This is typically
+            // used to ensure JavaScript files added via the 'add_js' command
+            // have loaded before subsequent commands execute.
+            return ajaxCommands[command](this, response[key], status);
+          }
+        }),
+      Promise.resolve(),
+    );
   };
 
+  /**
+   * Handler for the form redirection completion.
+   *
+   * @param {Array.<Drupal.AjaxCommands~commandDefinition>} response
+   *   Drupal Ajax response.
+   * @param {number} status
+   *   XMLHttpRequest status.
+   *
+   * @return {Promise}
+   * The promise that will resolve once all commands have finished executing.
+   */
   Drupal.Ajax.prototype.success = function (response, status) {
+    // Remove the progress element.
     if (this.progress.element) {
       $(this.progress.element).remove();
     }
-
     if (this.progress.object) {
       this.progress.object.stopMonitoring();
     }
-
     $(this.element).prop('disabled', false);
-    const elementParents = $(this.element).parents('[data-drupal-selector]').addBack().toArray();
-    const focusChanged = Object.keys(response || {}).some(key => {
-      const {
-        command,
-        method
-      } = response[key];
-      return command === 'focusFirst' || command === 'invoke' && method === 'focus';
-    });
-    return this.commandExecutionQueue(response, status).then(() => {
-      if (!focusChanged && this.element && !$(this.element).data('disable-refocus')) {
-        let target = false;
 
-        for (let n = elementParents.length - 1; !target && n >= 0; n--) {
-          target = document.querySelector(`[data-drupal-selector="${elementParents[n].getAttribute('data-drupal-selector')}"]`);
-        }
-
-        if (target) {
-          $(target).trigger('focus');
-        }
-      }
-
-      if (this.$form && document.body.contains(this.$form.get(0))) {
-        const settings = this.settings || drupalSettings;
-        Drupal.attachBehaviors(this.$form.get(0), settings);
-      }
+    // Save element's ancestors tree so if the element is removed from the dom
+    // we can try to refocus one of its parents. Using addBack reverse the
+    // result array, meaning that index 0 is the highest parent in the hierarchy
+    // in this situation it is usually a <form> element.
+    const elementParents = $(this.element)
+      .parents('[data-drupal-selector]')
+      .addBack()
+      .toArray();
+
+    // Track if any command is altering the focus so we can avoid changing the
+    // focus set by the Ajax command.
+    const focusChanged = Object.keys(response || {}).some((key) => {
+      const { command, method } = response[key];
+      return (
+        command === 'focusFirst' || (command === 'invoke' && method === 'focus')
+      );
+    });
 
-      this.settings = null;
-    }).catch(error => console.error(Drupal.t('An error occurred during the execution of the Ajax response: !error', {
-      '!error': error
-    })));
+    return (
+      this.commandExecutionQueue(response, status)
+        // If the focus hasn't been changed by the AJAX commands, try to refocus
+        // the triggering element or one of its parents if that element does not
+        // exist anymore.
+        .then(() => {
+          if (
+            !focusChanged &&
+            this.element &&
+            !$(this.element).data('disable-refocus')
+          ) {
+            let target = false;
+
+            for (let n = elementParents.length - 1; !target && n >= 0; n--) {
+              target = document.querySelector(
+                `[data-drupal-selector="${elementParents[n].getAttribute(
+                  'data-drupal-selector',
+                )}"]`,
+              );
+            }
+            if (target) {
+              $(target).trigger('focus');
+            }
+          }
+          // Reattach behaviors, if they were detached in beforeSerialize(). The
+          // attachBehaviors() called on the new content from processing the
+          // response commands is not sufficient, because behaviors from the
+          // entire form need to be reattached.
+          if (this.$form && document.body.contains(this.$form.get(0))) {
+            const settings = this.settings || drupalSettings;
+            Drupal.attachBehaviors(this.$form.get(0), settings);
+          }
+          // Remove any response-specific settings so they don't get used on the
+          // next call by mistake.
+          this.settings = null;
+        })
+        .catch((error) =>
+          // eslint-disable-next-line no-console
+          console.error(
+            Drupal.t(
+              'An error occurred during the execution of the Ajax response: !error',
+              {
+                '!error': error,
+              },
+            ),
+          ),
+        )
+    );
   };
 
+  /**
+   * Build an effect object to apply an effect when adding new HTML.
+   *
+   * @param {object} response
+   *   Drupal Ajax response.
+   * @param {string} [response.effect]
+   *   Override the default value of {@link Drupal.Ajax#elementSettings}.
+   * @param {string|number} [response.speed]
+   *   Override the default value of {@link Drupal.Ajax#elementSettings}.
+   *
+   * @return {object}
+   *   Returns an object with `showEffect`, `hideEffect` and `showSpeed`
+   *   properties.
+   */
   Drupal.Ajax.prototype.getEffect = function (response) {
     const type = response.effect || this.effect;
     const speed = response.speed || this.speed;
-    const effect = {};
 
+    const effect = {};
     if (type === 'none') {
       effect.showEffect = 'show';
       effect.hideEffect = 'hide';
@@ -495,41 +1125,164 @@
     return effect;
   };
 
+  /**
+   * Handler for the form redirection error.
+   *
+   * @param {object} xmlhttprequest
+   *   Native XMLHttpRequest object.
+   * @param {string} uri
+   *   Ajax Request URI.
+   * @param {string} [customMessage]
+   *   Extra message to print with the Ajax error.
+   */
   Drupal.Ajax.prototype.error = function (xmlhttprequest, uri, customMessage) {
+    // Remove the progress element.
     if (this.progress.element) {
       $(this.progress.element).remove();
     }
-
     if (this.progress.object) {
       this.progress.object.stopMonitoring();
     }
-
+    // Undo hide.
     $(this.wrapper).show();
+    // Re-enable the element.
     $(this.element).prop('disabled', false);
-
+    // Reattach behaviors, if they were detached in beforeSerialize(), and the
+    // form is still part of the document.
     if (this.$form && document.body.contains(this.$form.get(0))) {
       const settings = this.settings || drupalSettings;
       Drupal.attachBehaviors(this.$form.get(0), settings);
     }
-
     throw new Drupal.AjaxError(xmlhttprequest, uri, customMessage);
   };
 
-  Drupal.theme.ajaxWrapperNewContent = ($newContent, ajax, response) => (response.effect || ajax.effect) !== 'none' && $newContent.filter(i => !($newContent[i].nodeName === '#comment' || $newContent[i].nodeName === '#text' && /^(\s|\n|\r)*$/.test($newContent[i].textContent))).length > 1 ? Drupal.theme('ajaxWrapperMultipleRootElements', $newContent) : $newContent;
-
-  Drupal.theme.ajaxWrapperMultipleRootElements = $elements => $('<div></div>').append($elements);
-
+  /**
+   * Provide a wrapper for new content via Ajax.
+   *
+   * Wrap the inserted markup when inserting multiple root elements with an
+   * ajax effect.
+   *
+   * @param {jQuery} $newContent
+   *   Response elements after parsing.
+   * @param {Drupal.Ajax} ajax
+   *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+   * @param {object} response
+   *   The response from the Ajax request.
+   *
+   * @deprecated in drupal:8.6.0 and is removed from drupal:10.0.0.
+   *   Use data with desired wrapper.
+   *
+   * @see https://www.drupal.org/node/2940704
+   *
+   * @todo Add deprecation warning after it is possible. For more information
+   *   see: https://www.drupal.org/project/drupal/issues/2973400
+   */
+  Drupal.theme.ajaxWrapperNewContent = ($newContent, ajax, response) =>
+    (response.effect || ajax.effect) !== 'none' &&
+    $newContent.filter(
+      (i) =>
+        !(
+          // We can not consider HTML comments or whitespace text as separate
+          // roots, since they do not cause visual regression with effect.
+          (
+            $newContent[i].nodeName === '#comment' ||
+            ($newContent[i].nodeName === '#text' &&
+              /^(\s|\n|\r)*$/.test($newContent[i].textContent))
+          )
+        ),
+    ).length > 1
+      ? Drupal.theme('ajaxWrapperMultipleRootElements', $newContent)
+      : $newContent;
+
+  /**
+   * Provide a wrapper for multiple root elements via Ajax.
+   *
+   * @param {jQuery} $elements
+   *   Response elements after parsing.
+   *
+   * @deprecated in drupal:8.6.0 and is removed from drupal:10.0.0.
+   *   Use data with desired wrapper.
+   *
+   * @see https://www.drupal.org/node/2940704
+   *
+   * @todo Add deprecation warning after it is possible. For more information
+   *   see: https://www.drupal.org/project/drupal/issues/2973400
+   */
+  Drupal.theme.ajaxWrapperMultipleRootElements = ($elements) =>
+    $('<div></div>').append($elements);
+
+  /**
+   * @typedef {object} Drupal.AjaxCommands~commandDefinition
+   *
+   * @prop {string} command
+   * @prop {string} [method]
+   * @prop {string} [selector]
+   * @prop {string} [data]
+   * @prop {object} [settings]
+   * @prop {bool} [asterisk]
+   * @prop {string} [text]
+   * @prop {string} [title]
+   * @prop {string} [url]
+   * @prop {object} [argument]
+   * @prop {string} [name]
+   * @prop {string} [value]
+   * @prop {string} [old]
+   * @prop {string} [new]
+   * @prop {bool} [merge]
+   * @prop {Array} [args]
+   *
+   * @see Drupal.AjaxCommands
+   */
+
+  /**
+   * Provide a series of commands that the client will perform.
+   *
+   * @constructor
+   */
   Drupal.AjaxCommands = function () {};
-
   Drupal.AjaxCommands.prototype = {
+    /**
+     * Command to insert new content into the DOM.
+     *
+     * @param {Drupal.Ajax} ajax
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {string} response.data
+     *   The data to use with the jQuery method.
+     * @param {string} [response.method]
+     *   The jQuery DOM manipulation method to be used.
+     * @param {string} [response.selector]
+     *   An optional jQuery selector string.
+     * @param {object} [response.settings]
+     *   An optional array of settings that will be used.
+     */
     insert(ajax, response) {
-      const $wrapper = response.selector ? $(response.selector) : $(ajax.wrapper);
+      // Get information from the response. If it is not there, default to
+      // our presets.
+      const $wrapper = response.selector
+        ? $(response.selector)
+        : $(ajax.wrapper);
       const method = response.method || ajax.method;
       const effect = ajax.getEffect(response);
+
+      // Apply any settings from the returned JSON if available.
       const settings = response.settings || ajax.settings || drupalSettings;
-      let $newContent = $($.parseHTML(response.data, document, true));
-      $newContent = Drupal.theme('ajaxWrapperNewContent', $newContent, ajax, response);
 
+      // Parse response.data into an element collection.
+      let $newContent = $($.parseHTML(response.data, document, true));
+      // For backward compatibility, in some cases a wrapper will be added. This
+      // behavior will be removed before Drupal 9.0.0. If different behavior is
+      // needed, the theme functions can be overridden.
+      // @see https://www.drupal.org/node/2940704
+      $newContent = Drupal.theme(
+        'ajaxWrapperNewContent',
+        $newContent,
+        ajax,
+        response,
+      );
+
+      // If removing content from the wrapper, detach behaviors first.
       switch (method) {
         case 'html':
         case 'replaceWith':
@@ -538,19 +1291,21 @@
         case 'remove':
           Drupal.detachBehaviors($wrapper.get(0), settings);
           break;
-
         default:
           break;
       }
 
+      // Add the new content to the page.
       $wrapper[method]($newContent);
 
+      // Immediately hide the new content if we're using any effects.
       if (effect.showEffect !== 'show') {
         $newContent.hide();
       }
 
+      // Determine which effect to use and what content will receive the
+      // effect, then show the new content.
       const $ajaxNewContent = $newContent.find('.ajax-new-content');
-
       if ($ajaxNewContent.length) {
         $ajaxNewContent.hide();
         $newContent.show();
@@ -559,7 +1314,11 @@
         $newContent[effect.showEffect](effect.showSpeed);
       }
 
+      // Attach all JavaScript behaviors to the new content, if it was
+      // successfully added to the page, this if statement allows
+      // `#ajax['wrapper']` to be optional.
       if ($newContent.parents('html').length) {
+        // Attach behaviors to all element nodes.
         $newContent.each((index, element) => {
           if (element.nodeType === Node.ELEMENT_NODE) {
             Drupal.attachBehaviors(element, settings);
@@ -568,29 +1327,88 @@
       }
     },
 
+    /**
+     * Command to remove a chunk from the page.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {string} response.selector
+     *   A jQuery selector string.
+     * @param {object} [response.settings]
+     *   An optional array of settings that will be used.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     remove(ajax, response, status) {
       const settings = response.settings || ajax.settings || drupalSettings;
-      $(response.selector).each(function () {
-        Drupal.detachBehaviors(this, settings);
-      }).remove();
+      $(response.selector)
+        .each(function () {
+          Drupal.detachBehaviors(this, settings);
+        })
+        .remove();
     },
 
+    /**
+     * Command to mark a chunk changed.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The JSON response object from the Ajax request.
+     * @param {string} response.selector
+     *   A jQuery selector string.
+     * @param {bool} [response.asterisk]
+     *   An optional CSS selector. If specified, an asterisk will be
+     *   appended to the HTML inside the provided selector.
+     * @param {number} [status]
+     *   The request status.
+     */
     changed(ajax, response, status) {
       const $element = $(response.selector);
-
       if (!$element.hasClass('ajax-changed')) {
         $element.addClass('ajax-changed');
-
         if (response.asterisk) {
-          $element.find(response.asterisk).append(` <abbr class="ajax-changed" title="${Drupal.t('Changed')}">*</abbr> `);
+          $element
+            .find(response.asterisk)
+            .append(
+              ` <abbr class="ajax-changed" title="${Drupal.t(
+                'Changed',
+              )}">*</abbr> `,
+            );
         }
       }
     },
 
+    /**
+     * Command to provide an alert.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The JSON response from the Ajax request.
+     * @param {string} response.text
+     *   The text that will be displayed in an alert dialog.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     alert(ajax, response, status) {
       window.alert(response.text);
     },
 
+    /**
+     * Command to provide triggers audio UAs to read the supplied text.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The JSON response from the Ajax request.
+     * @param {string} [response.text]
+     *   The text that will be read.
+     * @param {string} [response.priority]
+     *   An optional priority that will be used for the announcement.
+     */
     announce(ajax, response) {
       if (response.priority) {
         Drupal.announce(response.text, response.priority);
@@ -599,22 +1417,70 @@
       }
     },
 
+    /**
+     * Command to set the window.location, redirecting the browser.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {string} response.url
+     *   The URL to redirect to.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     redirect(ajax, response, status) {
       window.location = response.url;
     },
 
+    /**
+     * Command to provide the jQuery css() function.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {string} response.selector
+     *   A jQuery selector string.
+     * @param {object} response.argument
+     *   An array of key/value pairs to set in the CSS for the selector.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     css(ajax, response, status) {
       $(response.selector).css(response.argument);
     },
 
+    /**
+     * Command to set the settings used for other commands in this response.
+     *
+     * This method will also remove expired `drupalSettings.ajax` settings.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {bool} response.merge
+     *   Determines whether the additional settings should be merged to the
+     *   global settings.
+     * @param {object} response.settings
+     *   Contains additional settings to add to the global settings.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     settings(ajax, response, status) {
       const ajaxSettings = drupalSettings.ajax;
 
+      // Clean up drupalSettings.ajax.
       if (ajaxSettings) {
-        Drupal.ajax.expired().forEach(instance => {
+        Drupal.ajax.expired().forEach((instance) => {
+          // If the Ajax object has been created through drupalSettings.ajax
+          // it will have a selector. When there is no selector the object
+          // has been initialized with a special class name picked up by the
+          // Ajax behavior.
+
           if (instance.selector) {
             const selector = instance.selector.replace('#', '');
-
             if (selector in ajaxSettings) {
               delete ajaxSettings[selector];
             }
@@ -629,96 +1495,246 @@
       }
     },
 
+    /**
+     * Command to attach data using jQuery's data API.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {string} response.name
+     *   The name or key (in the key value pair) of the data attached to this
+     *   selector.
+     * @param {string} response.selector
+     *   A jQuery selector string.
+     * @param {string|object} response.value
+     *   The value of to be attached.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     data(ajax, response, status) {
       $(response.selector).data(response.name, response.value);
     },
 
+    /**
+     * Command to focus the first tabbable element within a container.
+     *
+     * If no tabbable elements are found and the container is focusable, then
+     * focus will move to that container.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {string} response.selector
+     *   A query selector string of the container to focus within.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     focusFirst(ajax, response, status) {
       let focusChanged = false;
       const container = document.querySelector(response.selector);
-
       if (container) {
+        // Find all tabbable elements within the container.
         const tabbableElements = tabbable(container);
 
+        // Move focus to the first tabbable item found.
         if (tabbableElements.length) {
           tabbableElements[0].focus();
           focusChanged = true;
         } else if (isFocusable(container)) {
+          // If no tabbable elements are found, but the container is focusable,
+          // move focus to the container.
           container.focus();
           focusChanged = true;
         }
       }
 
+      // If no items were available to receive focus, return focus to the
+      // triggering element.
       if (ajax.hasOwnProperty('element') && !focusChanged) {
         ajax.element.focus();
       }
     },
 
+    /**
+     * Command to apply a jQuery method.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {Array} response.args
+     *   An array of arguments to the jQuery method, if any.
+     * @param {string} response.method
+     *   The jQuery method to invoke.
+     * @param {string} response.selector
+     *   A jQuery selector string.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     invoke(ajax, response, status) {
       const $element = $(response.selector);
       $element[response.method](...response.args);
     },
 
+    /**
+     * Command to restripe a table.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {string} response.selector
+     *   A jQuery selector string.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     restripe(ajax, response, status) {
-      $(response.selector).find('> tbody > tr:visible, > tr:visible').removeClass('odd even').filter(':even').addClass('odd').end().filter(':odd').addClass('even');
+      // :even and :odd are reversed because jQuery counts from 0 and
+      // we count from 1, so we're out of sync.
+      // Match immediate children of the parent element to allow nesting.
+      $(response.selector)
+        .find('> tbody > tr:visible, > tr:visible')
+        .removeClass('odd even')
+        .filter(':even')
+        .addClass('odd')
+        .end()
+        .filter(':odd')
+        .addClass('even');
     },
 
+    /**
+     * Command to update a form's build ID.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {string} response.old
+     *   The old form build ID.
+     * @param {string} response.new
+     *   The new form build ID.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     update_build_id(ajax, response, status) {
-      document.querySelectorAll(`input[name="form_build_id"][value="${response.old}"]`).forEach(item => {
-        item.value = response.new;
-      });
+      document
+        .querySelectorAll(
+          `input[name="form_build_id"][value="${response.old}"]`,
+        )
+        .forEach((item) => {
+          item.value = response.new;
+        });
     },
 
+    /**
+     * Command to add css.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {string} response.data
+     *   A string that contains the styles to be added.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     add_css(ajax, response, status) {
       $('head').prepend(response.data);
     },
 
+    /**
+     * Command to add a message to the message area.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {string} response.messageWrapperQuerySelector
+     *   The zone where to add the message. If null, the default will be used.
+     * @param {string} response.message
+     *   The message text.
+     * @param {string} response.messageOptions
+     *   The options argument for Drupal.Message().add().
+     * @param {bool} response.clearPrevious
+     *   If true, clear previous messages.
+     */
     message(ajax, response) {
-      const messages = new Drupal.Message(document.querySelector(response.messageWrapperQuerySelector));
-
+      const messages = new Drupal.Message(
+        document.querySelector(response.messageWrapperQuerySelector),
+      );
       if (response.clearPrevious) {
         messages.clear();
       }
-
       messages.add(response.message, response.messageOptions);
     },
 
+    /**
+     * Command to add JS.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+     * @param {object} response
+     *   The response from the Ajax request.
+     * @param {Array} response.data
+     *   An array of objects of script attributes.
+     * @param {number} [status]
+     *   The XMLHttpRequest status.
+     */
     add_js(ajax, response, status) {
       const parentEl = document.querySelector(response.selector || 'body');
       const settings = ajax.settings || drupalSettings;
-      const allUniqueBundleIds = response.data.map(script => {
+      const allUniqueBundleIds = response.data.map((script) => {
+        // loadjs requires a unique ID, and an AJAX instance's `instanceIndex`
+        // is guaranteed to be unique.
+        // @see Drupal.behaviors.AJAX.detach
         const uniqueBundleId = script.src + ajax.instanceIndex;
         loadjs(script.src, uniqueBundleId, {
+          // The default loadjs behavior is to load script with async, in Drupal
+          // we need to explicitly tell scripts to load async, this is set in
+          // the before callback below if necessary.
           async: false,
-
           before(path, scriptEl) {
-            Object.keys(script).forEach(attributeKey => {
+            // This allows all attributes to be added, like defer, async and
+            // crossorigin.
+            Object.keys(script).forEach((attributeKey) => {
               scriptEl.setAttribute(attributeKey, script[attributeKey]);
             });
+
+            // By default, loadjs appends the script to the head. When scripts
+            // are loaded via AJAX, their location has no impact on
+            // functionality. But, since non-AJAX loaded scripts can choose
+            // their parent element, we provide that option here for the sake of
+            // consistency.
             parentEl.appendChild(scriptEl);
+            // Return false to bypass loadjs' default DOM insertion mechanism.
             return false;
-          }
-
+          },
         });
         return uniqueBundleId;
       });
+      // Returns the promise so that the next AJAX command waits on the
+      // completion of this one to execute, ensuring the JS is loaded before
+      // executing.
       return new Promise((resolve, reject) => {
         loadjs.ready(allUniqueBundleIds, {
           success() {
             Drupal.attachBehaviors(parentEl, settings);
+            // All JS files were loaded and new and old behaviors have
+            // been attached. Resolve the promise and let the remaining
+            // commands execute.
             resolve();
           },
-
           error(depsNotFound) {
-            const message = Drupal.t(`The following files could not be loaded: @dependencies`, {
-              '@dependencies': depsNotFound.join(', ')
-            });
+            const message = Drupal.t(
+              `The following files could not be loaded: @dependencies`,
+              { '@dependencies': depsNotFound.join(', ') },
+            );
             reject(message);
-          }
-
+          },
         });
       });
-    }
-
+    },
   };
-})(jQuery, window, Drupal, drupalSettings, loadjs, window.tabbable);
\ No newline at end of file
+})(jQuery, window, Drupal, drupalSettings, loadjs, window.tabbable);
diff --git a/core/misc/announce.es6.js b/core/misc/announce.es6.js
deleted file mode 100644
index 32368b2a0c0a..000000000000
--- a/core/misc/announce.es6.js
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * @file
- * Adds an HTML element and method to trigger audio UAs to read system messages.
- *
- * Use {@link Drupal.announce} to indicate to screen reader users that an
- * element on the page has changed state. For instance, if clicking a link
- * loads 10 more items into a list, one might announce the change like this.
- *
- * @example
- * $('#search-list')
- *   .on('itemInsert', function (event, data) {
- *     // Insert the new items.
- *     $(data.container.el).append(data.items.el);
- *     // Announce the change to the page contents.
- *     Drupal.announce(Drupal.t('@count items added to @container',
- *       {'@count': data.items.length, '@container': data.container.title}
- *     ));
- *   });
- */
-
-(function (Drupal, debounce) {
-  let liveElement;
-  const announcements = [];
-
-  /**
-   * Builds a div element with the aria-live attribute and add it to the DOM.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the behavior for drupalAnnounce.
-   */
-  Drupal.behaviors.drupalAnnounce = {
-    attach(context) {
-      // Create only one aria-live element.
-      if (!liveElement) {
-        liveElement = document.createElement('div');
-        liveElement.id = 'drupal-live-announce';
-        liveElement.className = 'visually-hidden';
-        liveElement.setAttribute('aria-live', 'polite');
-        liveElement.setAttribute('aria-busy', 'false');
-        document.body.appendChild(liveElement);
-      }
-    },
-  };
-
-  /**
-   * Concatenates announcements to a single string; appends to the live region.
-   */
-  function announce() {
-    const text = [];
-    let priority = 'polite';
-    let announcement;
-
-    // Create an array of announcement strings to be joined and appended to the
-    // aria live region.
-    const il = announcements.length;
-    for (let i = 0; i < il; i++) {
-      announcement = announcements.pop();
-      text.unshift(announcement.text);
-      // If any of the announcements has a priority of assertive then the group
-      // of joined announcements will have this priority.
-      if (announcement.priority === 'assertive') {
-        priority = 'assertive';
-      }
-    }
-
-    if (text.length) {
-      // Clear the liveElement so that repeated strings will be read.
-      liveElement.innerHTML = '';
-      // Set the busy state to true until the node changes are complete.
-      liveElement.setAttribute('aria-busy', 'true');
-      // Set the priority to assertive, or default to polite.
-      liveElement.setAttribute('aria-live', priority);
-      // Print the text to the live region. Text should be run through
-      // Drupal.t() before being passed to Drupal.announce().
-      liveElement.innerHTML = text.join('\n');
-      // The live text area is updated. Allow the AT to announce the text.
-      liveElement.setAttribute('aria-busy', 'false');
-    }
-  }
-
-  /**
-   * Triggers audio UAs to read the supplied text.
-   *
-   * The aria-live region will only read the text that currently populates its
-   * text node. Replacing text quickly in rapid calls to announce results in
-   * only the text from the most recent call to {@link Drupal.announce} being
-   * read. By wrapping the call to announce in a debounce function, we allow for
-   * time for multiple calls to {@link Drupal.announce} to queue up their
-   * messages. These messages are then joined and append to the aria-live region
-   * as one text node.
-   *
-   * @param {string} text
-   *   A string to be read by the UA.
-   * @param {string} [priority='polite']
-   *   A string to indicate the priority of the message. Can be either
-   *   'polite' or 'assertive'.
-   *
-   * @return {function}
-   *   The return of the call to debounce.
-   *
-   * @see http://www.w3.org/WAI/PF/aria-practices/#liveprops
-   */
-  Drupal.announce = function (text, priority) {
-    // Save the text and priority into a closure variable. Multiple simultaneous
-    // announcements will be concatenated and read in sequence.
-    announcements.push({
-      text,
-      priority,
-    });
-    // Immediately invoke the function that debounce returns. 200 ms is right at
-    // the cusp where humans notice a pause, so we will wait
-    // at most this much time before the set of queued announcements is read.
-    return debounce(announce, 200)();
-  };
-})(Drupal, Drupal.debounce);
diff --git a/core/misc/announce.js b/core/misc/announce.js
index 859a8817036e..32368b2a0c0a 100644
--- a/core/misc/announce.js
+++ b/core/misc/announce.js
@@ -1,15 +1,38 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Adds an HTML element and method to trigger audio UAs to read system messages.
+ *
+ * Use {@link Drupal.announce} to indicate to screen reader users that an
+ * element on the page has changed state. For instance, if clicking a link
+ * loads 10 more items into a list, one might announce the change like this.
+ *
+ * @example
+ * $('#search-list')
+ *   .on('itemInsert', function (event, data) {
+ *     // Insert the new items.
+ *     $(data.container.el).append(data.items.el);
+ *     // Announce the change to the page contents.
+ *     Drupal.announce(Drupal.t('@count items added to @container',
+ *       {'@count': data.items.length, '@container': data.container.title}
+ *     ));
+ *   });
+ */
 
 (function (Drupal, debounce) {
   let liveElement;
   const announcements = [];
+
+  /**
+   * Builds a div element with the aria-live attribute and add it to the DOM.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the behavior for drupalAnnounce.
+   */
   Drupal.behaviors.drupalAnnounce = {
     attach(context) {
+      // Create only one aria-live element.
       if (!liveElement) {
         liveElement = document.createElement('div');
         liveElement.id = 'drupal-live-announce';
@@ -18,39 +41,77 @@
         liveElement.setAttribute('aria-busy', 'false');
         document.body.appendChild(liveElement);
       }
-    }
-
+    },
   };
 
+  /**
+   * Concatenates announcements to a single string; appends to the live region.
+   */
   function announce() {
     const text = [];
     let priority = 'polite';
     let announcement;
-    const il = announcements.length;
 
+    // Create an array of announcement strings to be joined and appended to the
+    // aria live region.
+    const il = announcements.length;
     for (let i = 0; i < il; i++) {
       announcement = announcements.pop();
       text.unshift(announcement.text);
-
+      // If any of the announcements has a priority of assertive then the group
+      // of joined announcements will have this priority.
       if (announcement.priority === 'assertive') {
         priority = 'assertive';
       }
     }
 
     if (text.length) {
+      // Clear the liveElement so that repeated strings will be read.
       liveElement.innerHTML = '';
+      // Set the busy state to true until the node changes are complete.
       liveElement.setAttribute('aria-busy', 'true');
+      // Set the priority to assertive, or default to polite.
       liveElement.setAttribute('aria-live', priority);
+      // Print the text to the live region. Text should be run through
+      // Drupal.t() before being passed to Drupal.announce().
       liveElement.innerHTML = text.join('\n');
+      // The live text area is updated. Allow the AT to announce the text.
       liveElement.setAttribute('aria-busy', 'false');
     }
   }
 
+  /**
+   * Triggers audio UAs to read the supplied text.
+   *
+   * The aria-live region will only read the text that currently populates its
+   * text node. Replacing text quickly in rapid calls to announce results in
+   * only the text from the most recent call to {@link Drupal.announce} being
+   * read. By wrapping the call to announce in a debounce function, we allow for
+   * time for multiple calls to {@link Drupal.announce} to queue up their
+   * messages. These messages are then joined and append to the aria-live region
+   * as one text node.
+   *
+   * @param {string} text
+   *   A string to be read by the UA.
+   * @param {string} [priority='polite']
+   *   A string to indicate the priority of the message. Can be either
+   *   'polite' or 'assertive'.
+   *
+   * @return {function}
+   *   The return of the call to debounce.
+   *
+   * @see http://www.w3.org/WAI/PF/aria-practices/#liveprops
+   */
   Drupal.announce = function (text, priority) {
+    // Save the text and priority into a closure variable. Multiple simultaneous
+    // announcements will be concatenated and read in sequence.
     announcements.push({
       text,
-      priority
+      priority,
     });
+    // Immediately invoke the function that debounce returns. 200 ms is right at
+    // the cusp where humans notice a pause, so we will wait
+    // at most this much time before the set of queued announcements is read.
     return debounce(announce, 200)();
   };
-})(Drupal, Drupal.debounce);
\ No newline at end of file
+})(Drupal, Drupal.debounce);
diff --git a/core/misc/autocomplete.es6.js b/core/misc/autocomplete.es6.js
deleted file mode 100644
index 56565bf58a39..000000000000
--- a/core/misc/autocomplete.es6.js
+++ /dev/null
@@ -1,286 +0,0 @@
-/**
- * @file
- * Autocomplete based on jQuery UI.
- */
-
-(function ($, Drupal) {
-  let autocomplete;
-
-  /**
-   * Helper splitting terms from the autocomplete value.
-   *
-   * @function Drupal.autocomplete.splitValues
-   *
-   * @param {string} value
-   *   The value being entered by the user.
-   *
-   * @return {Array}
-   *   Array of values, split by comma.
-   */
-  function autocompleteSplitValues(value) {
-    // We will match the value against comma-separated terms.
-    const result = [];
-    let quote = false;
-    let current = '';
-    const valueLength = value.length;
-    let character;
-
-    for (let i = 0; i < valueLength; i++) {
-      character = value.charAt(i);
-      if (character === '"') {
-        current += character;
-        quote = !quote;
-      } else if (character === ',' && !quote) {
-        result.push(current.trim());
-        current = '';
-      } else {
-        current += character;
-      }
-    }
-    if (value.length > 0) {
-      result.push(current.trim());
-    }
-
-    return result;
-  }
-
-  /**
-   * Returns the last value of a multi-value textfield.
-   *
-   * @function Drupal.autocomplete.extractLastTerm
-   *
-   * @param {string} terms
-   *   The value of the field.
-   *
-   * @return {string}
-   *   The last value of the input field.
-   */
-  function extractLastTerm(terms) {
-    return autocomplete.splitValues(terms).pop();
-  }
-
-  /**
-   * The search handler is called before a search is performed.
-   *
-   * @function Drupal.autocomplete.options.search
-   *
-   * @param {object} event
-   *   The event triggered.
-   *
-   * @return {bool}
-   *   Whether to perform a search or not.
-   */
-  function searchHandler(event) {
-    const options = autocomplete.options;
-
-    if (options.isComposing) {
-      return false;
-    }
-
-    const term = autocomplete.extractLastTerm(event.target.value);
-    // Abort search if the first character is in firstCharacterBlacklist.
-    if (
-      term.length > 0 &&
-      options.firstCharacterBlacklist.indexOf(term[0]) !== -1
-    ) {
-      return false;
-    }
-    // Only search when the term is at least the minimum length.
-    return term.length >= options.minLength;
-  }
-
-  /**
-   * JQuery UI autocomplete source callback.
-   *
-   * @param {object} request
-   *   The request object.
-   * @param {function} response
-   *   The function to call with the response.
-   */
-  function sourceData(request, response) {
-    const elementId = this.element.attr('id');
-
-    if (!(elementId in autocomplete.cache)) {
-      autocomplete.cache[elementId] = {};
-    }
-
-    /**
-     * Filter through the suggestions removing all terms already tagged and
-     * display the available terms to the user.
-     *
-     * @param {object} suggestions
-     *   Suggestions returned by the server.
-     */
-    function showSuggestions(suggestions) {
-      const tagged = autocomplete.splitValues(request.term);
-      const il = tagged.length;
-      for (let i = 0; i < il; i++) {
-        const index = suggestions.indexOf(tagged[i]);
-        if (index >= 0) {
-          suggestions.splice(index, 1);
-        }
-      }
-      response(suggestions);
-    }
-
-    // Get the desired term and construct the autocomplete URL for it.
-    const term = autocomplete.extractLastTerm(request.term);
-
-    /**
-     * Transforms the data object into an array and update autocomplete results.
-     *
-     * @param {object} data
-     *   The data sent back from the server.
-     */
-    function sourceCallbackHandler(data) {
-      autocomplete.cache[elementId][term] = data;
-
-      // Send the new string array of terms to the jQuery UI list.
-      showSuggestions(data);
-    }
-
-    // Check if the term is already cached.
-    if (autocomplete.cache[elementId].hasOwnProperty(term)) {
-      showSuggestions(autocomplete.cache[elementId][term]);
-    } else {
-      const options = $.extend(
-        { success: sourceCallbackHandler, data: { q: term } },
-        autocomplete.ajax,
-      );
-      $.ajax(this.element.attr('data-autocomplete-path'), options);
-    }
-  }
-
-  /**
-   * Handles an autocompletefocus event.
-   *
-   * @return {bool}
-   *   Always returns false.
-   */
-  function focusHandler() {
-    return false;
-  }
-
-  /**
-   * Handles an autocompleteselect event.
-   *
-   * @param {jQuery.Event} event
-   *   The event triggered.
-   * @param {object} ui
-   *   The jQuery UI settings object.
-   *
-   * @return {bool}
-   *   Returns false to indicate the event status.
-   */
-  function selectHandler(event, ui) {
-    const terms = autocomplete.splitValues(event.target.value);
-    // Remove the current input.
-    terms.pop();
-    // Add the selected item.
-    terms.push(ui.item.value);
-
-    event.target.value = terms.join(', ');
-    // Return false to tell jQuery UI that we've filled in the value already.
-    return false;
-  }
-
-  /**
-   * Override jQuery UI _renderItem function to output HTML by default.
-   *
-   * @param {jQuery} ul
-   *   jQuery collection of the ul element.
-   * @param {object} item
-   *   The list item to append.
-   *
-   * @return {jQuery}
-   *   jQuery collection of the ul element.
-   */
-  function renderItem(ul, item) {
-    return $('<li>').append($('<a>').html(item.label)).appendTo(ul);
-  }
-
-  /**
-   * Attaches the autocomplete behavior to all required fields.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the autocomplete behaviors.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detaches the autocomplete behaviors.
-   */
-  Drupal.behaviors.autocomplete = {
-    attach(context) {
-      // Act on textfields with the "form-autocomplete" class.
-      const $autocomplete = $(
-        once('autocomplete', 'input.form-autocomplete', context),
-      );
-      if ($autocomplete.length) {
-        // Allow options to be overridden per instance.
-        const blacklist = $autocomplete.attr(
-          'data-autocomplete-first-character-blacklist',
-        );
-        $.extend(autocomplete.options, {
-          firstCharacterBlacklist: blacklist || '',
-        });
-        // Use jQuery UI Autocomplete on the textfield.
-        $autocomplete.autocomplete(autocomplete.options).each(function () {
-          $(this).data('ui-autocomplete')._renderItem =
-            autocomplete.options.renderItem;
-        });
-
-        // Use CompositionEvent to handle IME inputs. It requests remote server on "compositionend" event only.
-        $autocomplete.on('compositionstart.autocomplete', () => {
-          autocomplete.options.isComposing = true;
-        });
-        $autocomplete.on('compositionend.autocomplete', () => {
-          autocomplete.options.isComposing = false;
-        });
-      }
-    },
-    detach(context, settings, trigger) {
-      if (trigger === 'unload') {
-        $(
-          once.remove('autocomplete', 'input.form-autocomplete', context),
-        ).autocomplete('destroy');
-      }
-    },
-  };
-
-  /**
-   * Autocomplete object implementation.
-   *
-   * @namespace Drupal.autocomplete
-   */
-  autocomplete = {
-    cache: {},
-    // Exposes options to allow overriding by contrib.
-    splitValues: autocompleteSplitValues,
-    extractLastTerm,
-    // jQuery UI autocomplete options.
-
-    /**
-     * JQuery UI option object.
-     *
-     * @name Drupal.autocomplete.options
-     */
-    options: {
-      source: sourceData,
-      focus: focusHandler,
-      search: searchHandler,
-      select: selectHandler,
-      renderItem,
-      minLength: 1,
-      // Custom options, used by Drupal.autocomplete.
-      firstCharacterBlacklist: '',
-      // Custom options, indicate IME usage status.
-      isComposing: false,
-    },
-    ajax: {
-      dataType: 'json',
-      jsonp: false,
-    },
-  };
-
-  Drupal.autocomplete = autocomplete;
-})(jQuery, Drupal);
diff --git a/core/misc/autocomplete.js b/core/misc/autocomplete.js
index 131087f63eae..56565bf58a39 100644
--- a/core/misc/autocomplete.js
+++ b/core/misc/autocomplete.js
@@ -1,14 +1,24 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Autocomplete based on jQuery UI.
+ */
 
 (function ($, Drupal) {
   let autocomplete;
 
+  /**
+   * Helper splitting terms from the autocomplete value.
+   *
+   * @function Drupal.autocomplete.splitValues
+   *
+   * @param {string} value
+   *   The value being entered by the user.
+   *
+   * @return {Array}
+   *   Array of values, split by comma.
+   */
   function autocompleteSplitValues(value) {
+    // We will match the value against comma-separated terms.
     const result = [];
     let quote = false;
     let current = '';
@@ -17,7 +27,6 @@
 
     for (let i = 0; i < valueLength; i++) {
       character = value.charAt(i);
-
       if (character === '"') {
         current += character;
         quote = !quote;
@@ -28,7 +37,6 @@
         current += character;
       }
     }
-
     if (value.length > 0) {
       result.push(current.trim());
     }
@@ -36,10 +44,32 @@
     return result;
   }
 
+  /**
+   * Returns the last value of a multi-value textfield.
+   *
+   * @function Drupal.autocomplete.extractLastTerm
+   *
+   * @param {string} terms
+   *   The value of the field.
+   *
+   * @return {string}
+   *   The last value of the input field.
+   */
   function extractLastTerm(terms) {
     return autocomplete.splitValues(terms).pop();
   }
 
+  /**
+   * The search handler is called before a search is performed.
+   *
+   * @function Drupal.autocomplete.options.search
+   *
+   * @param {object} event
+   *   The event triggered.
+   *
+   * @return {bool}
+   *   Whether to perform a search or not.
+   */
   function searchHandler(event) {
     const options = autocomplete.options;
 
@@ -48,14 +78,25 @@
     }
 
     const term = autocomplete.extractLastTerm(event.target.value);
-
-    if (term.length > 0 && options.firstCharacterBlacklist.indexOf(term[0]) !== -1) {
+    // Abort search if the first character is in firstCharacterBlacklist.
+    if (
+      term.length > 0 &&
+      options.firstCharacterBlacklist.indexOf(term[0]) !== -1
+    ) {
       return false;
     }
-
+    // Only search when the term is at least the minimum length.
     return term.length >= options.minLength;
   }
 
+  /**
+   * JQuery UI autocomplete source callback.
+   *
+   * @param {object} request
+   *   The request object.
+   * @param {function} response
+   *   The function to call with the response.
+   */
   function sourceData(request, response) {
     const elementId = this.element.attr('id');
 
@@ -63,69 +104,132 @@
       autocomplete.cache[elementId] = {};
     }
 
+    /**
+     * Filter through the suggestions removing all terms already tagged and
+     * display the available terms to the user.
+     *
+     * @param {object} suggestions
+     *   Suggestions returned by the server.
+     */
     function showSuggestions(suggestions) {
       const tagged = autocomplete.splitValues(request.term);
       const il = tagged.length;
-
       for (let i = 0; i < il; i++) {
         const index = suggestions.indexOf(tagged[i]);
-
         if (index >= 0) {
           suggestions.splice(index, 1);
         }
       }
-
       response(suggestions);
     }
 
+    // Get the desired term and construct the autocomplete URL for it.
     const term = autocomplete.extractLastTerm(request.term);
 
+    /**
+     * Transforms the data object into an array and update autocomplete results.
+     *
+     * @param {object} data
+     *   The data sent back from the server.
+     */
     function sourceCallbackHandler(data) {
       autocomplete.cache[elementId][term] = data;
+
+      // Send the new string array of terms to the jQuery UI list.
       showSuggestions(data);
     }
 
+    // Check if the term is already cached.
     if (autocomplete.cache[elementId].hasOwnProperty(term)) {
       showSuggestions(autocomplete.cache[elementId][term]);
     } else {
-      const options = $.extend({
-        success: sourceCallbackHandler,
-        data: {
-          q: term
-        }
-      }, autocomplete.ajax);
+      const options = $.extend(
+        { success: sourceCallbackHandler, data: { q: term } },
+        autocomplete.ajax,
+      );
       $.ajax(this.element.attr('data-autocomplete-path'), options);
     }
   }
 
+  /**
+   * Handles an autocompletefocus event.
+   *
+   * @return {bool}
+   *   Always returns false.
+   */
   function focusHandler() {
     return false;
   }
 
+  /**
+   * Handles an autocompleteselect event.
+   *
+   * @param {jQuery.Event} event
+   *   The event triggered.
+   * @param {object} ui
+   *   The jQuery UI settings object.
+   *
+   * @return {bool}
+   *   Returns false to indicate the event status.
+   */
   function selectHandler(event, ui) {
     const terms = autocomplete.splitValues(event.target.value);
+    // Remove the current input.
     terms.pop();
+    // Add the selected item.
     terms.push(ui.item.value);
+
     event.target.value = terms.join(', ');
+    // Return false to tell jQuery UI that we've filled in the value already.
     return false;
   }
 
+  /**
+   * Override jQuery UI _renderItem function to output HTML by default.
+   *
+   * @param {jQuery} ul
+   *   jQuery collection of the ul element.
+   * @param {object} item
+   *   The list item to append.
+   *
+   * @return {jQuery}
+   *   jQuery collection of the ul element.
+   */
   function renderItem(ul, item) {
     return $('<li>').append($('<a>').html(item.label)).appendTo(ul);
   }
 
+  /**
+   * Attaches the autocomplete behavior to all required fields.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the autocomplete behaviors.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches the autocomplete behaviors.
+   */
   Drupal.behaviors.autocomplete = {
     attach(context) {
-      const $autocomplete = $(once('autocomplete', 'input.form-autocomplete', context));
-
+      // Act on textfields with the "form-autocomplete" class.
+      const $autocomplete = $(
+        once('autocomplete', 'input.form-autocomplete', context),
+      );
       if ($autocomplete.length) {
-        const blacklist = $autocomplete.attr('data-autocomplete-first-character-blacklist');
+        // Allow options to be overridden per instance.
+        const blacklist = $autocomplete.attr(
+          'data-autocomplete-first-character-blacklist',
+        );
         $.extend(autocomplete.options, {
-          firstCharacterBlacklist: blacklist || ''
+          firstCharacterBlacklist: blacklist || '',
         });
+        // Use jQuery UI Autocomplete on the textfield.
         $autocomplete.autocomplete(autocomplete.options).each(function () {
-          $(this).data('ui-autocomplete')._renderItem = autocomplete.options.renderItem;
+          $(this).data('ui-autocomplete')._renderItem =
+            autocomplete.options.renderItem;
         });
+
+        // Use CompositionEvent to handle IME inputs. It requests remote server on "compositionend" event only.
         $autocomplete.on('compositionstart.autocomplete', () => {
           autocomplete.options.isComposing = true;
         });
@@ -134,18 +238,32 @@
         });
       }
     },
-
     detach(context, settings, trigger) {
       if (trigger === 'unload') {
-        $(once.remove('autocomplete', 'input.form-autocomplete', context)).autocomplete('destroy');
+        $(
+          once.remove('autocomplete', 'input.form-autocomplete', context),
+        ).autocomplete('destroy');
       }
-    }
-
+    },
   };
+
+  /**
+   * Autocomplete object implementation.
+   *
+   * @namespace Drupal.autocomplete
+   */
   autocomplete = {
     cache: {},
+    // Exposes options to allow overriding by contrib.
     splitValues: autocompleteSplitValues,
     extractLastTerm,
+    // jQuery UI autocomplete options.
+
+    /**
+     * JQuery UI option object.
+     *
+     * @name Drupal.autocomplete.options
+     */
     options: {
       source: sourceData,
       focus: focusHandler,
@@ -153,13 +271,16 @@
       select: selectHandler,
       renderItem,
       minLength: 1,
+      // Custom options, used by Drupal.autocomplete.
       firstCharacterBlacklist: '',
-      isComposing: false
+      // Custom options, indicate IME usage status.
+      isComposing: false,
     },
     ajax: {
       dataType: 'json',
-      jsonp: false
-    }
+      jsonp: false,
+    },
   };
+
   Drupal.autocomplete = autocomplete;
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/misc/batch.es6.js b/core/misc/batch.es6.js
deleted file mode 100644
index 2a055157da78..000000000000
--- a/core/misc/batch.es6.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * @file
- * Drupal's batch API.
- */
-
-(function ($, Drupal) {
-  /**
-   * Attaches the batch behavior to progress bars.
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.batch = {
-    attach(context, settings) {
-      const batch = settings.batch;
-      const $progress = $(once('batch', '[data-drupal-progress]'));
-      let progressBar;
-
-      // Success: redirect to the summary.
-      function updateCallback(progress, status, pb) {
-        if (progress === '100') {
-          pb.stopMonitoring();
-          window.location = `${batch.uri}&op=finished`;
-        }
-      }
-
-      function errorCallback(pb) {
-        $progress.prepend($('<p class="error"></p>').html(batch.errorMessage));
-        $('#wait').hide();
-      }
-
-      if ($progress.length) {
-        progressBar = new Drupal.ProgressBar(
-          'updateprogress',
-          updateCallback,
-          'POST',
-          errorCallback,
-        );
-        progressBar.setProgress(-1, batch.initMessage);
-        progressBar.startMonitoring(`${batch.uri}&op=do`, 10);
-        // Remove HTML from no-js progress bar.
-        $progress.empty();
-        // Append the JS progressbar element.
-        $progress.append(progressBar.element);
-      }
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/misc/batch.js b/core/misc/batch.js
index 1b4b7f2cb971..2a055157da78 100644
--- a/core/misc/batch.js
+++ b/core/misc/batch.js
@@ -1,17 +1,21 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Drupal's batch API.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Attaches the batch behavior to progress bars.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.batch = {
     attach(context, settings) {
       const batch = settings.batch;
       const $progress = $(once('batch', '[data-drupal-progress]'));
       let progressBar;
 
+      // Success: redirect to the summary.
       function updateCallback(progress, status, pb) {
         if (progress === '100') {
           pb.stopMonitoring();
@@ -25,13 +29,19 @@
       }
 
       if ($progress.length) {
-        progressBar = new Drupal.ProgressBar('updateprogress', updateCallback, 'POST', errorCallback);
+        progressBar = new Drupal.ProgressBar(
+          'updateprogress',
+          updateCallback,
+          'POST',
+          errorCallback,
+        );
         progressBar.setProgress(-1, batch.initMessage);
         progressBar.startMonitoring(`${batch.uri}&op=do`, 10);
+        // Remove HTML from no-js progress bar.
         $progress.empty();
+        // Append the JS progressbar element.
         $progress.append(progressBar.element);
       }
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/misc/checkbox.es6.js b/core/misc/checkbox.es6.js
deleted file mode 100644
index 0320dd0ddefc..000000000000
--- a/core/misc/checkbox.es6.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * @file
- * Defines checkbox theme functions.
- */
-
-((Drupal) => {
-  /**
-   * Theme function for a checkbox.
-   *
-   * @return {string}
-   *   The HTML markup for the checkbox.
-   */
-  Drupal.theme.checkbox = () =>
-    `<input type="checkbox" class="form-checkbox"/>`;
-})(Drupal);
diff --git a/core/misc/checkbox.js b/core/misc/checkbox.js
index 945c53728663..0320dd0ddefc 100644
--- a/core/misc/checkbox.js
+++ b/core/misc/checkbox.js
@@ -1,10 +1,15 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Defines checkbox theme functions.
+ */
 
-(Drupal => {
-  Drupal.theme.checkbox = () => `<input type="checkbox" class="form-checkbox"/>`;
-})(Drupal);
\ No newline at end of file
+((Drupal) => {
+  /**
+   * Theme function for a checkbox.
+   *
+   * @return {string}
+   *   The HTML markup for the checkbox.
+   */
+  Drupal.theme.checkbox = () =>
+    `<input type="checkbox" class="form-checkbox"/>`;
+})(Drupal);
diff --git a/core/misc/collapse.es6.js b/core/misc/collapse.es6.js
deleted file mode 100644
index f2e07b653292..000000000000
--- a/core/misc/collapse.es6.js
+++ /dev/null
@@ -1,155 +0,0 @@
-/**
- * @file
- * Polyfill for HTML5 details elements.
- */
-
-(function ($, Modernizr, Drupal) {
-  /**
-   * The collapsible details object represents a single details element.
-   *
-   * @constructor Drupal.CollapsibleDetails
-   *
-   * @param {HTMLElement} node
-   *   The details element.
-   */
-  function CollapsibleDetails(node) {
-    this.$node = $(node);
-    this.$node.data('details', this);
-    // Expand details if there are errors inside, or if it contains an
-    // element that is targeted by the URI fragment identifier.
-    const anchor =
-      window.location.hash && window.location.hash !== '#'
-        ? `, ${window.location.hash}`
-        : '';
-    if (this.$node.find(`.error${anchor}`).length) {
-      this.$node.attr('open', true);
-    }
-    // Initialize and set up the summary polyfill.
-    this.setupSummaryPolyfill();
-  }
-
-  $.extend(
-    CollapsibleDetails,
-    /** @lends Drupal.CollapsibleDetails */ {
-      /**
-       * Holds references to instantiated CollapsibleDetails objects.
-       *
-       * @type {Array.<Drupal.CollapsibleDetails>}
-       */
-      instances: [],
-    },
-  );
-
-  $.extend(
-    CollapsibleDetails.prototype,
-    /** @lends Drupal.CollapsibleDetails# */ {
-      /**
-       * Initialize and setup summary markup.
-       */
-      setupSummaryPolyfill() {
-        // Turn the summary into a clickable link.
-        const $summary = this.$node.find('> summary');
-
-        // If this polyfill is in use, the browser does not recognize
-        // <summary> as a focusable element. The tabindex is set to -1 so the
-        // tabbable library does not incorrectly identify it as tabbable.
-        $summary.attr('tabindex', '-1');
-
-        $('<span class="details-summary-prefix visually-hidden"></span>')
-          .append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show'))
-          .prependTo($summary)
-          .after(document.createTextNode(' '));
-
-        // .wrapInner() does not retain bound events.
-        $('<a class="details-title"></a>')
-          .attr('href', `#${this.$node.attr('id')}`)
-          .prepend($summary.contents())
-          .appendTo($summary);
-
-        $summary
-          .append(this.$summary)
-          .on('click', $.proxy(this.onSummaryClick, this));
-      },
-
-      /**
-       * Handle summary clicks.
-       *
-       * @param {jQuery.Event} e
-       *   The event triggered.
-       */
-      onSummaryClick(e) {
-        this.toggle();
-        e.preventDefault();
-      },
-
-      /**
-       * Toggle the visibility of a details element using smooth animations.
-       */
-      toggle() {
-        const isOpen = !!this.$node.attr('open');
-        const $summaryPrefix = this.$node.find(
-          '> summary span.details-summary-prefix',
-        );
-        if (isOpen) {
-          $summaryPrefix.html(Drupal.t('Show'));
-        } else {
-          $summaryPrefix.html(Drupal.t('Hide'));
-        }
-        // Delay setting the attribute to emulate chrome behavior and make
-        // details-aria.js work as expected with this polyfill.
-        setTimeout(() => {
-          this.$node.attr('open', !isOpen);
-        }, 0);
-      },
-    },
-  );
-
-  /**
-   * Polyfill HTML5 details element.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior for the details element.
-   */
-  Drupal.behaviors.collapse = {
-    attach(context) {
-      if (Modernizr.details) {
-        return;
-      }
-      once('collapse', 'details', context).forEach((detail) => {
-        // This class is used for styling purpose only.
-        detail.classList.add('collapse-processed');
-        CollapsibleDetails.instances.push(new CollapsibleDetails(detail));
-      });
-    },
-  };
-
-  /**
-   * Open parent details elements of a targeted page fragment.
-   *
-   * Opens all (nested) details element on a hash change or fragment link click
-   * when the target is a child element, in order to make sure the targeted
-   * element is visible. Aria attributes on the summary
-   * are set by triggering the click event listener in details-aria.js.
-   *
-   * @param {jQuery.Event} e
-   *   The event triggered.
-   * @param {jQuery} $target
-   *   The targeted node as a jQuery object.
-   */
-  const handleFragmentLinkClickOrHashChange = (e, $target) => {
-    $target.parents('details').not('[open]').find('> summary').trigger('click');
-  };
-
-  /**
-   * Binds a listener to handle fragment link clicks and URL hash changes.
-   */
-  $('body').on(
-    'formFragmentLinkClickOrHashChange.details',
-    handleFragmentLinkClickOrHashChange,
-  );
-
-  // Expose constructor in the public space.
-  Drupal.CollapsibleDetails = CollapsibleDetails;
-})(jQuery, Modernizr, Drupal);
diff --git a/core/misc/collapse.js b/core/misc/collapse.js
index 32193ea1730b..f2e07b653292 100644
--- a/core/misc/collapse.js
+++ b/core/misc/collapse.js
@@ -1,74 +1,155 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Polyfill for HTML5 details elements.
+ */
 
 (function ($, Modernizr, Drupal) {
+  /**
+   * The collapsible details object represents a single details element.
+   *
+   * @constructor Drupal.CollapsibleDetails
+   *
+   * @param {HTMLElement} node
+   *   The details element.
+   */
   function CollapsibleDetails(node) {
     this.$node = $(node);
     this.$node.data('details', this);
-    const anchor = window.location.hash && window.location.hash !== '#' ? `, ${window.location.hash}` : '';
-
+    // Expand details if there are errors inside, or if it contains an
+    // element that is targeted by the URI fragment identifier.
+    const anchor =
+      window.location.hash && window.location.hash !== '#'
+        ? `, ${window.location.hash}`
+        : '';
     if (this.$node.find(`.error${anchor}`).length) {
       this.$node.attr('open', true);
     }
-
+    // Initialize and set up the summary polyfill.
     this.setupSummaryPolyfill();
   }
 
-  $.extend(CollapsibleDetails, {
-    instances: []
-  });
-  $.extend(CollapsibleDetails.prototype, {
-    setupSummaryPolyfill() {
-      const $summary = this.$node.find('> summary');
-      $summary.attr('tabindex', '-1');
-      $('<span class="details-summary-prefix visually-hidden"></span>').append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show')).prependTo($summary).after(document.createTextNode(' '));
-      $('<a class="details-title"></a>').attr('href', `#${this.$node.attr('id')}`).prepend($summary.contents()).appendTo($summary);
-      $summary.append(this.$summary).on('click', $.proxy(this.onSummaryClick, this));
+  $.extend(
+    CollapsibleDetails,
+    /** @lends Drupal.CollapsibleDetails */ {
+      /**
+       * Holds references to instantiated CollapsibleDetails objects.
+       *
+       * @type {Array.<Drupal.CollapsibleDetails>}
+       */
+      instances: [],
     },
+  );
 
-    onSummaryClick(e) {
-      this.toggle();
-      e.preventDefault();
-    },
+  $.extend(
+    CollapsibleDetails.prototype,
+    /** @lends Drupal.CollapsibleDetails# */ {
+      /**
+       * Initialize and setup summary markup.
+       */
+      setupSummaryPolyfill() {
+        // Turn the summary into a clickable link.
+        const $summary = this.$node.find('> summary');
 
-    toggle() {
-      const isOpen = !!this.$node.attr('open');
-      const $summaryPrefix = this.$node.find('> summary span.details-summary-prefix');
+        // If this polyfill is in use, the browser does not recognize
+        // <summary> as a focusable element. The tabindex is set to -1 so the
+        // tabbable library does not incorrectly identify it as tabbable.
+        $summary.attr('tabindex', '-1');
 
-      if (isOpen) {
-        $summaryPrefix.html(Drupal.t('Show'));
-      } else {
-        $summaryPrefix.html(Drupal.t('Hide'));
-      }
+        $('<span class="details-summary-prefix visually-hidden"></span>')
+          .append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show'))
+          .prependTo($summary)
+          .after(document.createTextNode(' '));
 
-      setTimeout(() => {
-        this.$node.attr('open', !isOpen);
-      }, 0);
-    }
+        // .wrapInner() does not retain bound events.
+        $('<a class="details-title"></a>')
+          .attr('href', `#${this.$node.attr('id')}`)
+          .prepend($summary.contents())
+          .appendTo($summary);
+
+        $summary
+          .append(this.$summary)
+          .on('click', $.proxy(this.onSummaryClick, this));
+      },
+
+      /**
+       * Handle summary clicks.
+       *
+       * @param {jQuery.Event} e
+       *   The event triggered.
+       */
+      onSummaryClick(e) {
+        this.toggle();
+        e.preventDefault();
+      },
 
-  });
+      /**
+       * Toggle the visibility of a details element using smooth animations.
+       */
+      toggle() {
+        const isOpen = !!this.$node.attr('open');
+        const $summaryPrefix = this.$node.find(
+          '> summary span.details-summary-prefix',
+        );
+        if (isOpen) {
+          $summaryPrefix.html(Drupal.t('Show'));
+        } else {
+          $summaryPrefix.html(Drupal.t('Hide'));
+        }
+        // Delay setting the attribute to emulate chrome behavior and make
+        // details-aria.js work as expected with this polyfill.
+        setTimeout(() => {
+          this.$node.attr('open', !isOpen);
+        }, 0);
+      },
+    },
+  );
+
+  /**
+   * Polyfill HTML5 details element.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior for the details element.
+   */
   Drupal.behaviors.collapse = {
     attach(context) {
       if (Modernizr.details) {
         return;
       }
-
-      once('collapse', 'details', context).forEach(detail => {
+      once('collapse', 'details', context).forEach((detail) => {
+        // This class is used for styling purpose only.
         detail.classList.add('collapse-processed');
         CollapsibleDetails.instances.push(new CollapsibleDetails(detail));
       });
-    }
-
+    },
   };
 
+  /**
+   * Open parent details elements of a targeted page fragment.
+   *
+   * Opens all (nested) details element on a hash change or fragment link click
+   * when the target is a child element, in order to make sure the targeted
+   * element is visible. Aria attributes on the summary
+   * are set by triggering the click event listener in details-aria.js.
+   *
+   * @param {jQuery.Event} e
+   *   The event triggered.
+   * @param {jQuery} $target
+   *   The targeted node as a jQuery object.
+   */
   const handleFragmentLinkClickOrHashChange = (e, $target) => {
     $target.parents('details').not('[open]').find('> summary').trigger('click');
   };
 
-  $('body').on('formFragmentLinkClickOrHashChange.details', handleFragmentLinkClickOrHashChange);
+  /**
+   * Binds a listener to handle fragment link clicks and URL hash changes.
+   */
+  $('body').on(
+    'formFragmentLinkClickOrHashChange.details',
+    handleFragmentLinkClickOrHashChange,
+  );
+
+  // Expose constructor in the public space.
   Drupal.CollapsibleDetails = CollapsibleDetails;
-})(jQuery, Modernizr, Drupal);
\ No newline at end of file
+})(jQuery, Modernizr, Drupal);
diff --git a/core/misc/debounce.es6.js b/core/misc/debounce.es6.js
deleted file mode 100644
index e77940b9efa3..000000000000
--- a/core/misc/debounce.es6.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * @file
- * Adapted from underscore.js with the addition Drupal namespace.
- */
-
-/**
- * Limits the invocations of a function in a given time frame.
- *
- * The debounce function wrapper should be used sparingly. One clear use case
- * is limiting the invocation of a callback attached to the window resize event.
- *
- * Before using the debounce function wrapper, consider first whether the
- * callback could be attached to an event that fires less frequently or if the
- * function can be written in such a way that it is only invoked under specific
- * conditions.
- *
- * @param {function} func
- *   The function to be invoked.
- * @param {number} wait
- *   The time period within which the callback function should only be
- *   invoked once. For example if the wait period is 250ms, then the callback
- *   will only be called at most 4 times per second.
- * @param {bool} immediate
- *   Whether we wait at the beginning or end to execute the function.
- *
- * @return {function}
- *   The debounced function.
- */
-Drupal.debounce = function (func, wait, immediate) {
-  let timeout;
-  let result;
-  return function (...args) {
-    const context = this;
-    const later = function () {
-      timeout = null;
-      if (!immediate) {
-        result = func.apply(context, args);
-      }
-    };
-    const callNow = immediate && !timeout;
-    clearTimeout(timeout);
-    timeout = setTimeout(later, wait);
-    if (callNow) {
-      result = func.apply(context, args);
-    }
-    return result;
-  };
-};
diff --git a/core/misc/debounce.js b/core/misc/debounce.js
index eb1f069e0dea..e77940b9efa3 100644
--- a/core/misc/debounce.js
+++ b/core/misc/debounce.js
@@ -1,36 +1,48 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Adapted from underscore.js with the addition Drupal namespace.
+ */
 
+/**
+ * Limits the invocations of a function in a given time frame.
+ *
+ * The debounce function wrapper should be used sparingly. One clear use case
+ * is limiting the invocation of a callback attached to the window resize event.
+ *
+ * Before using the debounce function wrapper, consider first whether the
+ * callback could be attached to an event that fires less frequently or if the
+ * function can be written in such a way that it is only invoked under specific
+ * conditions.
+ *
+ * @param {function} func
+ *   The function to be invoked.
+ * @param {number} wait
+ *   The time period within which the callback function should only be
+ *   invoked once. For example if the wait period is 250ms, then the callback
+ *   will only be called at most 4 times per second.
+ * @param {bool} immediate
+ *   Whether we wait at the beginning or end to execute the function.
+ *
+ * @return {function}
+ *   The debounced function.
+ */
 Drupal.debounce = function (func, wait, immediate) {
   let timeout;
   let result;
-  return function () {
-    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
-      args[_key] = arguments[_key];
-    }
-
+  return function (...args) {
     const context = this;
-
     const later = function () {
       timeout = null;
-
       if (!immediate) {
         result = func.apply(context, args);
       }
     };
-
     const callNow = immediate && !timeout;
     clearTimeout(timeout);
     timeout = setTimeout(later, wait);
-
     if (callNow) {
       result = func.apply(context, args);
     }
-
     return result;
   };
-};
\ No newline at end of file
+};
diff --git a/core/misc/details-aria.es6.js b/core/misc/details-aria.es6.js
deleted file mode 100644
index 1d0ef555586c..000000000000
--- a/core/misc/details-aria.es6.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * @file
- * Add aria attribute handling for details and summary elements.
- */
-
-(function ($, Drupal) {
-  /**
-   * Handles `aria-expanded` and `aria-pressed` attributes on details elements.
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.detailsAria = {
-    attach() {
-      $(once('detailsAria', 'body')).on(
-        'click.detailsAria',
-        'summary',
-        (event) => {
-          const $summary = $(event.currentTarget);
-          const open =
-            $(event.currentTarget.parentNode).attr('open') === 'open'
-              ? 'false'
-              : 'true';
-
-          $summary.attr({
-            'aria-expanded': open,
-            'aria-pressed': open,
-          });
-        },
-      );
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/misc/details-aria.js b/core/misc/details-aria.js
index 451f17e32919..1d0ef555586c 100644
--- a/core/misc/details-aria.js
+++ b/core/misc/details-aria.js
@@ -1,22 +1,32 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Add aria attribute handling for details and summary elements.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Handles `aria-expanded` and `aria-pressed` attributes on details elements.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.detailsAria = {
     attach() {
-      $(once('detailsAria', 'body')).on('click.detailsAria', 'summary', event => {
-        const $summary = $(event.currentTarget);
-        const open = $(event.currentTarget.parentNode).attr('open') === 'open' ? 'false' : 'true';
-        $summary.attr({
-          'aria-expanded': open,
-          'aria-pressed': open
-        });
-      });
-    }
+      $(once('detailsAria', 'body')).on(
+        'click.detailsAria',
+        'summary',
+        (event) => {
+          const $summary = $(event.currentTarget);
+          const open =
+            $(event.currentTarget.parentNode).attr('open') === 'open'
+              ? 'false'
+              : 'true';
 
+          $summary.attr({
+            'aria-expanded': open,
+            'aria-pressed': open,
+          });
+        },
+      );
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/misc/details-summarized-content.es6.js b/core/misc/details-summarized-content.es6.js
deleted file mode 100644
index 79f87cf321eb..000000000000
--- a/core/misc/details-summarized-content.es6.js
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * @file
- * Adds a summary of a details element's contents to its summary element.
- */
-(($, Drupal) => {
-  /**
-   * The DetailsSummarizedContent object represents a single details element.
-   *
-   * @constructor Drupal.DetailsSummarizedContent
-   *
-   * @param {HTMLElement} node
-   *   A details element, the summary of which may have supplemental text.
-   *   The supplemental text summarizes the details element's contents.
-   */
-  function DetailsSummarizedContent(node) {
-    this.$node = $(node);
-    this.setupSummary();
-  }
-
-  $.extend(
-    DetailsSummarizedContent,
-    /** @lends Drupal.DetailsSummarizedContent */ {
-      /**
-       * Holds references to instantiated DetailsSummarizedContent objects.
-       *
-       * @type {Array.<Drupal.DetailsSummarizedContent>}
-       */
-      instances: [],
-    },
-  );
-
-  $.extend(
-    DetailsSummarizedContent.prototype,
-    /** @lends Drupal.DetailsSummarizedContent# */ {
-      /**
-       * Initialize and setup summary events and markup.
-       *
-       * @fires event:summaryUpdated
-       *
-       * @listens event:summaryUpdated
-       */
-      setupSummary() {
-        this.$detailsSummarizedContentWrapper = $(
-          Drupal.theme('detailsSummarizedContentWrapper'),
-        );
-        this.$node
-          .on('summaryUpdated', $.proxy(this.onSummaryUpdated, this))
-          .trigger('summaryUpdated')
-          .find('> summary')
-          .append(this.$detailsSummarizedContentWrapper);
-      },
-
-      /**
-       * Update summary.
-       */
-      onSummaryUpdated() {
-        const text = this.$node.drupalGetSummary();
-        this.$detailsSummarizedContentWrapper.html(
-          Drupal.theme('detailsSummarizedContentText', text),
-        );
-      },
-    },
-  );
-
-  /**
-   * Adds a summary of a details element's contents to its summary element.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior for the details element.
-   */
-  Drupal.behaviors.detailsSummary = {
-    attach(context) {
-      DetailsSummarizedContent.instances =
-        DetailsSummarizedContent.instances.concat(
-          once('details', 'details', context).map(
-            (details) => new DetailsSummarizedContent(details),
-          ),
-        );
-    },
-  };
-
-  Drupal.DetailsSummarizedContent = DetailsSummarizedContent;
-
-  /**
-   * The element containing a wrapper for summarized details content.
-   *
-   * @return {string}
-   *   The markup for the element that will contain the summarized content.
-   */
-  Drupal.theme.detailsSummarizedContentWrapper = () =>
-    `<span class="summary"></span>`;
-
-  /**
-   * Formats the summarized details content text.
-   *
-   * @param {string|null} [text]
-   *   (optional) The summarized content text displayed in the summary.
-   * @return {string}
-   *   The formatted summarized content text.
-   */
-  Drupal.theme.detailsSummarizedContentText = (text) =>
-    text ? ` (${text})` : '';
-})(jQuery, Drupal);
diff --git a/core/misc/details-summarized-content.js b/core/misc/details-summarized-content.js
index c0f022bbbf26..79f87cf321eb 100644
--- a/core/misc/details-summarized-content.js
+++ b/core/misc/details-summarized-content.js
@@ -1,40 +1,105 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * @file
+ * Adds a summary of a details element's contents to its summary element.
+ */
 (($, Drupal) => {
+  /**
+   * The DetailsSummarizedContent object represents a single details element.
+   *
+   * @constructor Drupal.DetailsSummarizedContent
+   *
+   * @param {HTMLElement} node
+   *   A details element, the summary of which may have supplemental text.
+   *   The supplemental text summarizes the details element's contents.
+   */
   function DetailsSummarizedContent(node) {
     this.$node = $(node);
     this.setupSummary();
   }
 
-  $.extend(DetailsSummarizedContent, {
-    instances: []
-  });
-  $.extend(DetailsSummarizedContent.prototype, {
-    setupSummary() {
-      this.$detailsSummarizedContentWrapper = $(Drupal.theme('detailsSummarizedContentWrapper'));
-      this.$node.on('summaryUpdated', $.proxy(this.onSummaryUpdated, this)).trigger('summaryUpdated').find('> summary').append(this.$detailsSummarizedContentWrapper);
+  $.extend(
+    DetailsSummarizedContent,
+    /** @lends Drupal.DetailsSummarizedContent */ {
+      /**
+       * Holds references to instantiated DetailsSummarizedContent objects.
+       *
+       * @type {Array.<Drupal.DetailsSummarizedContent>}
+       */
+      instances: [],
     },
+  );
+
+  $.extend(
+    DetailsSummarizedContent.prototype,
+    /** @lends Drupal.DetailsSummarizedContent# */ {
+      /**
+       * Initialize and setup summary events and markup.
+       *
+       * @fires event:summaryUpdated
+       *
+       * @listens event:summaryUpdated
+       */
+      setupSummary() {
+        this.$detailsSummarizedContentWrapper = $(
+          Drupal.theme('detailsSummarizedContentWrapper'),
+        );
+        this.$node
+          .on('summaryUpdated', $.proxy(this.onSummaryUpdated, this))
+          .trigger('summaryUpdated')
+          .find('> summary')
+          .append(this.$detailsSummarizedContentWrapper);
+      },
 
-    onSummaryUpdated() {
-      const text = this.$node.drupalGetSummary();
-      this.$detailsSummarizedContentWrapper.html(Drupal.theme('detailsSummarizedContentText', text));
-    }
+      /**
+       * Update summary.
+       */
+      onSummaryUpdated() {
+        const text = this.$node.drupalGetSummary();
+        this.$detailsSummarizedContentWrapper.html(
+          Drupal.theme('detailsSummarizedContentText', text),
+        );
+      },
+    },
+  );
 
-  });
+  /**
+   * Adds a summary of a details element's contents to its summary element.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior for the details element.
+   */
   Drupal.behaviors.detailsSummary = {
     attach(context) {
-      DetailsSummarizedContent.instances = DetailsSummarizedContent.instances.concat(once('details', 'details', context).map(details => new DetailsSummarizedContent(details)));
-    }
-
+      DetailsSummarizedContent.instances =
+        DetailsSummarizedContent.instances.concat(
+          once('details', 'details', context).map(
+            (details) => new DetailsSummarizedContent(details),
+          ),
+        );
+    },
   };
+
   Drupal.DetailsSummarizedContent = DetailsSummarizedContent;
 
-  Drupal.theme.detailsSummarizedContentWrapper = () => `<span class="summary"></span>`;
+  /**
+   * The element containing a wrapper for summarized details content.
+   *
+   * @return {string}
+   *   The markup for the element that will contain the summarized content.
+   */
+  Drupal.theme.detailsSummarizedContentWrapper = () =>
+    `<span class="summary"></span>`;
 
-  Drupal.theme.detailsSummarizedContentText = text => text ? ` (${text})` : '';
-})(jQuery, Drupal);
\ No newline at end of file
+  /**
+   * Formats the summarized details content text.
+   *
+   * @param {string|null} [text]
+   *   (optional) The summarized content text displayed in the summary.
+   * @return {string}
+   *   The formatted summarized content text.
+   */
+  Drupal.theme.detailsSummarizedContentText = (text) =>
+    text ? ` (${text})` : '';
+})(jQuery, Drupal);
diff --git a/core/misc/dialog/dialog.ajax.es6.js b/core/misc/dialog/dialog.ajax.es6.js
deleted file mode 100644
index 8dca37201b38..000000000000
--- a/core/misc/dialog/dialog.ajax.es6.js
+++ /dev/null
@@ -1,249 +0,0 @@
-/**
- * @file
- * Extends the Drupal AJAX functionality to integrate the dialog API.
- */
-
-(function ($, Drupal) {
-  /**
-   * Initialize dialogs for Ajax purposes.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the behaviors for dialog ajax functionality.
-   */
-  Drupal.behaviors.dialog = {
-    attach(context, settings) {
-      const $context = $(context);
-
-      // Provide a known 'drupal-modal' DOM element for Drupal-based modal
-      // dialogs. Non-modal dialogs are responsible for creating their own
-      // elements, since there can be multiple non-modal dialogs at a time.
-      if (!$('#drupal-modal').length) {
-        // Add 'ui-front' jQuery UI class so jQuery UI widgets like autocomplete
-        // sit on top of dialogs. For more information see
-        // http://api.jqueryui.com/theming/stacking-elements/.
-        $('<div id="drupal-modal" class="ui-front"></div>')
-          .hide()
-          .appendTo('body');
-      }
-
-      // Special behaviors specific when attaching content within a dialog.
-      // These behaviors usually fire after a validation error inside a dialog.
-      const $dialog = $context.closest('.ui-dialog-content');
-      if ($dialog.length) {
-        // Remove and replace the dialog buttons with those from the new form.
-        if ($dialog.dialog('option', 'drupalAutoButtons')) {
-          // Trigger an event to detect/sync changes to buttons.
-          $dialog.trigger('dialogButtonsChange');
-        }
-
-        // Force focus on the modal when the behavior is run.
-        $dialog.dialog('widget').trigger('focus');
-      }
-
-      const originalClose = settings.dialog.close;
-      // Overwrite the close method to remove the dialog on closing.
-      settings.dialog.close = function (event, ...args) {
-        originalClose.apply(settings.dialog, [event, ...args]);
-        $(event.target).remove();
-      };
-    },
-
-    /**
-     * Scan a dialog for any primary buttons and move them to the button area.
-     *
-     * @param {jQuery} $dialog
-     *   A jQuery object containing the element that is the dialog target.
-     *
-     * @return {Array}
-     *   An array of buttons that need to be added to the button area.
-     */
-    prepareDialogButtons($dialog) {
-      const buttons = [];
-      const $buttons = $dialog.find(
-        '.form-actions input[type=submit], .form-actions a.button',
-      );
-      $buttons.each(function () {
-        const $originalButton = $(this).css({ display: 'none' });
-        buttons.push({
-          text: $originalButton.html() || $originalButton.attr('value'),
-          class: $originalButton.attr('class'),
-          click(e) {
-            // If the original button is an anchor tag, triggering the "click"
-            // event will not simulate a click. Use the click method instead.
-            if ($originalButton.is('a')) {
-              $originalButton[0].click();
-            } else {
-              $originalButton
-                .trigger('mousedown')
-                .trigger('mouseup')
-                .trigger('click');
-              e.preventDefault();
-            }
-          },
-        });
-      });
-      return buttons;
-    },
-  };
-
-  /**
-   * Command to open a dialog.
-   *
-   * @param {Drupal.Ajax} ajax
-   *   The Drupal Ajax object.
-   * @param {object} response
-   *   Object holding the server response.
-   * @param {number} [status]
-   *   The HTTP status code.
-   *
-   * @return {bool|undefined}
-   *   Returns false if there was no selector property in the response object.
-   */
-  Drupal.AjaxCommands.prototype.openDialog = function (ajax, response, status) {
-    if (!response.selector) {
-      return false;
-    }
-    let $dialog = $(response.selector);
-    if (!$dialog.length) {
-      // Create the element if needed.
-      $dialog = $(
-        `<div id="${response.selector.replace(
-          /^#/,
-          '',
-        )}" class="ui-front"></div>`,
-      ).appendTo('body');
-    }
-    // Set up the wrapper, if there isn't one.
-    if (!ajax.wrapper) {
-      ajax.wrapper = $dialog.attr('id');
-    }
-
-    // Use the ajax.js insert command to populate the dialog contents.
-    response.command = 'insert';
-    response.method = 'html';
-    ajax.commands.insert(ajax, response, status);
-
-    // Move the buttons to the jQuery UI dialog buttons area.
-    if (!response.dialogOptions.buttons) {
-      response.dialogOptions.drupalAutoButtons = true;
-      response.dialogOptions.buttons =
-        Drupal.behaviors.dialog.prepareDialogButtons($dialog);
-    }
-
-    // Bind dialogButtonsChange.
-    $dialog.on('dialogButtonsChange', () => {
-      const buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
-      $dialog.dialog('option', 'buttons', buttons);
-    });
-
-    // Open the dialog itself.
-    response.dialogOptions = response.dialogOptions || {};
-    const dialog = Drupal.dialog($dialog.get(0), response.dialogOptions);
-    if (response.dialogOptions.modal) {
-      dialog.showModal();
-    } else {
-      dialog.show();
-    }
-
-    // Add the standard Drupal class for buttons for style consistency.
-    $dialog.parent().find('.ui-dialog-buttonset').addClass('form-actions');
-  };
-
-  /**
-   * Command to close a dialog.
-   *
-   * If no selector is given, it defaults to trying to close the modal.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   The ajax object.
-   * @param {object} response
-   *   Object holding the server response.
-   * @param {string} response.selector
-   *   The selector of the dialog.
-   * @param {bool} response.persist
-   *   Whether to persist the dialog element or not.
-   * @param {number} [status]
-   *   The HTTP status code.
-   */
-  Drupal.AjaxCommands.prototype.closeDialog = function (
-    ajax,
-    response,
-    status,
-  ) {
-    const $dialog = $(response.selector);
-    if ($dialog.length) {
-      Drupal.dialog($dialog.get(0)).close();
-      if (!response.persist) {
-        $dialog.remove();
-      }
-    }
-
-    // Unbind dialogButtonsChange.
-    $dialog.off('dialogButtonsChange');
-  };
-
-  /**
-   * Command to set a dialog property.
-   *
-   * JQuery UI specific way of setting dialog options.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   The Drupal Ajax object.
-   * @param {object} response
-   *   Object holding the server response.
-   * @param {string} response.selector
-   *   Selector for the dialog element.
-   * @param {string} response.optionsName
-   *   Name of a key to set.
-   * @param {string} response.optionValue
-   *   Value to set.
-   * @param {number} [status]
-   *   The HTTP status code.
-   */
-  Drupal.AjaxCommands.prototype.setDialogOption = function (
-    ajax,
-    response,
-    status,
-  ) {
-    const $dialog = $(response.selector);
-    if ($dialog.length) {
-      $dialog.dialog('option', response.optionName, response.optionValue);
-    }
-  };
-
-  /**
-   * Binds a listener on dialog creation to handle the cancel link.
-   *
-   * @param {jQuery.Event} e
-   *   The event triggered.
-   * @param {Drupal.dialog~dialogDefinition} dialog
-   *   The dialog instance.
-   * @param {jQuery} $element
-   *   The jQuery collection of the dialog element.
-   * @param {object} [settings]
-   *   Dialog settings.
-   */
-  $(window).on('dialog:aftercreate', (e, dialog, $element, settings) => {
-    $element.on('click.dialog', '.dialog-cancel', (e) => {
-      dialog.close('cancel');
-      e.preventDefault();
-      e.stopPropagation();
-    });
-  });
-
-  /**
-   * Removes all 'dialog' listeners.
-   *
-   * @param {jQuery.Event} e
-   *   The event triggered.
-   * @param {Drupal.dialog~dialogDefinition} dialog
-   *   The dialog instance.
-   * @param {jQuery} $element
-   *   jQuery collection of the dialog element.
-   */
-  $(window).on('dialog:beforeclose', (e, dialog, $element) => {
-    $element.off('.dialog');
-  });
-})(jQuery, Drupal);
diff --git a/core/misc/dialog/dialog.ajax.js b/core/misc/dialog/dialog.ajax.js
index f77299a0b5f5..8dca37201b38 100644
--- a/core/misc/dialog/dialog.ajax.js
+++ b/core/misc/dialog/dialog.ajax.js
@@ -1,138 +1,249 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Extends the Drupal AJAX functionality to integrate the dialog API.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Initialize dialogs for Ajax purposes.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the behaviors for dialog ajax functionality.
+   */
   Drupal.behaviors.dialog = {
     attach(context, settings) {
       const $context = $(context);
 
+      // Provide a known 'drupal-modal' DOM element for Drupal-based modal
+      // dialogs. Non-modal dialogs are responsible for creating their own
+      // elements, since there can be multiple non-modal dialogs at a time.
       if (!$('#drupal-modal').length) {
-        $('<div id="drupal-modal" class="ui-front"></div>').hide().appendTo('body');
+        // Add 'ui-front' jQuery UI class so jQuery UI widgets like autocomplete
+        // sit on top of dialogs. For more information see
+        // http://api.jqueryui.com/theming/stacking-elements/.
+        $('<div id="drupal-modal" class="ui-front"></div>')
+          .hide()
+          .appendTo('body');
       }
 
+      // Special behaviors specific when attaching content within a dialog.
+      // These behaviors usually fire after a validation error inside a dialog.
       const $dialog = $context.closest('.ui-dialog-content');
-
       if ($dialog.length) {
+        // Remove and replace the dialog buttons with those from the new form.
         if ($dialog.dialog('option', 'drupalAutoButtons')) {
+          // Trigger an event to detect/sync changes to buttons.
           $dialog.trigger('dialogButtonsChange');
         }
 
+        // Force focus on the modal when the behavior is run.
         $dialog.dialog('widget').trigger('focus');
       }
 
       const originalClose = settings.dialog.close;
-
-      settings.dialog.close = function (event) {
-        for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
-          args[_key - 1] = arguments[_key];
-        }
-
+      // Overwrite the close method to remove the dialog on closing.
+      settings.dialog.close = function (event, ...args) {
         originalClose.apply(settings.dialog, [event, ...args]);
         $(event.target).remove();
       };
     },
 
+    /**
+     * Scan a dialog for any primary buttons and move them to the button area.
+     *
+     * @param {jQuery} $dialog
+     *   A jQuery object containing the element that is the dialog target.
+     *
+     * @return {Array}
+     *   An array of buttons that need to be added to the button area.
+     */
     prepareDialogButtons($dialog) {
       const buttons = [];
-      const $buttons = $dialog.find('.form-actions input[type=submit], .form-actions a.button');
+      const $buttons = $dialog.find(
+        '.form-actions input[type=submit], .form-actions a.button',
+      );
       $buttons.each(function () {
-        const $originalButton = $(this).css({
-          display: 'none'
-        });
+        const $originalButton = $(this).css({ display: 'none' });
         buttons.push({
           text: $originalButton.html() || $originalButton.attr('value'),
           class: $originalButton.attr('class'),
-
           click(e) {
+            // If the original button is an anchor tag, triggering the "click"
+            // event will not simulate a click. Use the click method instead.
             if ($originalButton.is('a')) {
               $originalButton[0].click();
             } else {
-              $originalButton.trigger('mousedown').trigger('mouseup').trigger('click');
+              $originalButton
+                .trigger('mousedown')
+                .trigger('mouseup')
+                .trigger('click');
               e.preventDefault();
             }
-          }
-
+          },
         });
       });
       return buttons;
-    }
-
+    },
   };
 
+  /**
+   * Command to open a dialog.
+   *
+   * @param {Drupal.Ajax} ajax
+   *   The Drupal Ajax object.
+   * @param {object} response
+   *   Object holding the server response.
+   * @param {number} [status]
+   *   The HTTP status code.
+   *
+   * @return {bool|undefined}
+   *   Returns false if there was no selector property in the response object.
+   */
   Drupal.AjaxCommands.prototype.openDialog = function (ajax, response, status) {
     if (!response.selector) {
       return false;
     }
-
     let $dialog = $(response.selector);
-
     if (!$dialog.length) {
-      $dialog = $(`<div id="${response.selector.replace(/^#/, '')}" class="ui-front"></div>`).appendTo('body');
+      // Create the element if needed.
+      $dialog = $(
+        `<div id="${response.selector.replace(
+          /^#/,
+          '',
+        )}" class="ui-front"></div>`,
+      ).appendTo('body');
     }
-
+    // Set up the wrapper, if there isn't one.
     if (!ajax.wrapper) {
       ajax.wrapper = $dialog.attr('id');
     }
 
+    // Use the ajax.js insert command to populate the dialog contents.
     response.command = 'insert';
     response.method = 'html';
     ajax.commands.insert(ajax, response, status);
 
+    // Move the buttons to the jQuery UI dialog buttons area.
     if (!response.dialogOptions.buttons) {
       response.dialogOptions.drupalAutoButtons = true;
-      response.dialogOptions.buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
+      response.dialogOptions.buttons =
+        Drupal.behaviors.dialog.prepareDialogButtons($dialog);
     }
 
+    // Bind dialogButtonsChange.
     $dialog.on('dialogButtonsChange', () => {
       const buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
       $dialog.dialog('option', 'buttons', buttons);
     });
+
+    // Open the dialog itself.
     response.dialogOptions = response.dialogOptions || {};
     const dialog = Drupal.dialog($dialog.get(0), response.dialogOptions);
-
     if (response.dialogOptions.modal) {
       dialog.showModal();
     } else {
       dialog.show();
     }
 
+    // Add the standard Drupal class for buttons for style consistency.
     $dialog.parent().find('.ui-dialog-buttonset').addClass('form-actions');
   };
 
-  Drupal.AjaxCommands.prototype.closeDialog = function (ajax, response, status) {
+  /**
+   * Command to close a dialog.
+   *
+   * If no selector is given, it defaults to trying to close the modal.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   The ajax object.
+   * @param {object} response
+   *   Object holding the server response.
+   * @param {string} response.selector
+   *   The selector of the dialog.
+   * @param {bool} response.persist
+   *   Whether to persist the dialog element or not.
+   * @param {number} [status]
+   *   The HTTP status code.
+   */
+  Drupal.AjaxCommands.prototype.closeDialog = function (
+    ajax,
+    response,
+    status,
+  ) {
     const $dialog = $(response.selector);
-
     if ($dialog.length) {
       Drupal.dialog($dialog.get(0)).close();
-
       if (!response.persist) {
         $dialog.remove();
       }
     }
 
+    // Unbind dialogButtonsChange.
     $dialog.off('dialogButtonsChange');
   };
 
-  Drupal.AjaxCommands.prototype.setDialogOption = function (ajax, response, status) {
+  /**
+   * Command to set a dialog property.
+   *
+   * JQuery UI specific way of setting dialog options.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   The Drupal Ajax object.
+   * @param {object} response
+   *   Object holding the server response.
+   * @param {string} response.selector
+   *   Selector for the dialog element.
+   * @param {string} response.optionsName
+   *   Name of a key to set.
+   * @param {string} response.optionValue
+   *   Value to set.
+   * @param {number} [status]
+   *   The HTTP status code.
+   */
+  Drupal.AjaxCommands.prototype.setDialogOption = function (
+    ajax,
+    response,
+    status,
+  ) {
     const $dialog = $(response.selector);
-
     if ($dialog.length) {
       $dialog.dialog('option', response.optionName, response.optionValue);
     }
   };
 
+  /**
+   * Binds a listener on dialog creation to handle the cancel link.
+   *
+   * @param {jQuery.Event} e
+   *   The event triggered.
+   * @param {Drupal.dialog~dialogDefinition} dialog
+   *   The dialog instance.
+   * @param {jQuery} $element
+   *   The jQuery collection of the dialog element.
+   * @param {object} [settings]
+   *   Dialog settings.
+   */
   $(window).on('dialog:aftercreate', (e, dialog, $element, settings) => {
-    $element.on('click.dialog', '.dialog-cancel', e => {
+    $element.on('click.dialog', '.dialog-cancel', (e) => {
       dialog.close('cancel');
       e.preventDefault();
       e.stopPropagation();
     });
   });
+
+  /**
+   * Removes all 'dialog' listeners.
+   *
+   * @param {jQuery.Event} e
+   *   The event triggered.
+   * @param {Drupal.dialog~dialogDefinition} dialog
+   *   The dialog instance.
+   * @param {jQuery} $element
+   *   jQuery collection of the dialog element.
+   */
   $(window).on('dialog:beforeclose', (e, dialog, $element) => {
     $element.off('.dialog');
   });
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/misc/dialog/dialog.es6.js b/core/misc/dialog/dialog.es6.js
deleted file mode 100644
index 60e339b96915..000000000000
--- a/core/misc/dialog/dialog.es6.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * @file
- * Dialog API inspired by HTML5 dialog element.
- *
- * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#the-dialog-element
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Default dialog options.
-   *
-   * @type {object}
-   *
-   * @prop {bool} [autoOpen=true]
-   * @prop {string} [dialogClass='']
-   * @prop {string} [buttonClass='button']
-   * @prop {string} [buttonPrimaryClass='button--primary']
-   * @prop {function} close
-   */
-  drupalSettings.dialog = {
-    autoOpen: true,
-    dialogClass: '',
-    // Drupal-specific extensions: see dialog.jquery-ui.js.
-    buttonClass: 'button',
-    buttonPrimaryClass: 'button--primary',
-    // When using this API directly (when generating dialogs on the client
-    // side), you may want to override this method and do
-    // `jQuery(event.target).remove()` as well, to remove the dialog on
-    // closing.
-    close(event) {
-      Drupal.dialog(event.target).close();
-      Drupal.detachBehaviors(event.target, null, 'unload');
-    },
-  };
-
-  /**
-   * @typedef {object} Drupal.dialog~dialogDefinition
-   *
-   * @prop {boolean} open
-   *   Is the dialog open or not.
-   * @prop {*} returnValue
-   *   Return value of the dialog.
-   * @prop {function} show
-   *   Method to display the dialog on the page.
-   * @prop {function} showModal
-   *   Method to display the dialog as a modal on the page.
-   * @prop {function} close
-   *   Method to hide the dialog from the page.
-   */
-
-  /**
-   * Polyfill HTML5 dialog element with jQueryUI.
-   *
-   * @param {HTMLElement} element
-   *   The element that holds the dialog.
-   * @param {object} options
-   *   jQuery UI options to be passed to the dialog.
-   *
-   * @return {Drupal.dialog~dialogDefinition}
-   *   The dialog instance.
-   */
-  Drupal.dialog = function (element, options) {
-    let undef;
-    const $element = $(element);
-    const dialog = {
-      open: false,
-      returnValue: undef,
-    };
-
-    function openDialog(settings) {
-      settings = $.extend({}, drupalSettings.dialog, options, settings);
-      // Trigger a global event to allow scripts to bind events to the dialog.
-      $(window).trigger('dialog:beforecreate', [dialog, $element, settings]);
-      $element.dialog(settings);
-      dialog.open = true;
-      $(window).trigger('dialog:aftercreate', [dialog, $element, settings]);
-    }
-
-    function closeDialog(value) {
-      $(window).trigger('dialog:beforeclose', [dialog, $element]);
-      $element.dialog('close');
-      dialog.returnValue = value;
-      dialog.open = false;
-      $(window).trigger('dialog:afterclose', [dialog, $element]);
-    }
-
-    dialog.show = () => {
-      openDialog({ modal: false });
-    };
-    dialog.showModal = () => {
-      openDialog({ modal: true });
-    };
-    dialog.close = closeDialog;
-
-    return dialog;
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/misc/dialog/dialog.jquery-ui.es6.js b/core/misc/dialog/dialog.jquery-ui.es6.js
deleted file mode 100644
index 783797d1a148..000000000000
--- a/core/misc/dialog/dialog.jquery-ui.es6.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * @file
- * Adds default classes to buttons for styling purposes.
- */
-
-(function ($, { tabbable, isTabbable }) {
-  $.widget('ui.dialog', $.ui.dialog, {
-    options: {
-      buttonClass: 'button',
-      buttonPrimaryClass: 'button--primary',
-    },
-    _createButtons() {
-      const opts = this.options;
-      let primaryIndex;
-      let index;
-      const il = opts.buttons.length;
-      for (index = 0; index < il; index++) {
-        if (
-          opts.buttons[index].primary &&
-          opts.buttons[index].primary === true
-        ) {
-          primaryIndex = index;
-          delete opts.buttons[index].primary;
-          break;
-        }
-      }
-      this._super();
-      const $buttons = this.uiButtonSet.children().addClass(opts.buttonClass);
-      if (typeof primaryIndex !== 'undefined') {
-        $buttons.eq(index).addClass(opts.buttonPrimaryClass);
-      }
-    },
-    // Override jQuery UI's `_focusTabbable()` so finding tabbable elements uses
-    // the core/tabbable library instead of jQuery UI's `:tabbable` selector.
-    _focusTabbable() {
-      // Set focus to the first match:
-
-      // 1. An element that was focused previously.
-      let hasFocus = this._focusedElement ? this._focusedElement.get(0) : null;
-
-      // 2. First element inside the dialog matching [autofocus].
-      if (!hasFocus) {
-        hasFocus = this.element.find('[autofocus]').get(0);
-      }
-
-      // 3. Tabbable element inside the content element.
-      // 4. Tabbable element inside the buttonpane.
-      if (!hasFocus) {
-        const $elements = [this.element, this.uiDialogButtonPane];
-        for (let i = 0; i < $elements.length; i++) {
-          const element = $elements[i].get(0);
-          if (element) {
-            const elementTabbable = tabbable(element);
-            hasFocus = elementTabbable.length ? elementTabbable[0] : null;
-          }
-          if (hasFocus) {
-            break;
-          }
-        }
-      }
-
-      // 5. The close button.
-      if (!hasFocus) {
-        const closeBtn = this.uiDialogTitlebarClose.get(0);
-        hasFocus = closeBtn && isTabbable(closeBtn) ? closeBtn : null;
-      }
-
-      // 6. The dialog itself.
-      if (!hasFocus) {
-        hasFocus = this.uiDialog.get(0);
-      }
-      $(hasFocus).eq(0).trigger('focus');
-    },
-  });
-})(jQuery, window.tabbable);
diff --git a/core/misc/dialog/dialog.jquery-ui.js b/core/misc/dialog/dialog.jquery-ui.js
index defb2155da4c..783797d1a148 100644
--- a/core/misc/dialog/dialog.jquery-ui.js
+++ b/core/misc/dialog/dialog.jquery-ui.js
@@ -1,79 +1,75 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Adds default classes to buttons for styling purposes.
+ */
 
-(function ($, _ref) {
-  let {
-    tabbable,
-    isTabbable
-  } = _ref;
+(function ($, { tabbable, isTabbable }) {
   $.widget('ui.dialog', $.ui.dialog, {
     options: {
       buttonClass: 'button',
-      buttonPrimaryClass: 'button--primary'
+      buttonPrimaryClass: 'button--primary',
     },
-
     _createButtons() {
       const opts = this.options;
       let primaryIndex;
       let index;
       const il = opts.buttons.length;
-
       for (index = 0; index < il; index++) {
-        if (opts.buttons[index].primary && opts.buttons[index].primary === true) {
+        if (
+          opts.buttons[index].primary &&
+          opts.buttons[index].primary === true
+        ) {
           primaryIndex = index;
           delete opts.buttons[index].primary;
           break;
         }
       }
-
       this._super();
-
       const $buttons = this.uiButtonSet.children().addClass(opts.buttonClass);
-
       if (typeof primaryIndex !== 'undefined') {
         $buttons.eq(index).addClass(opts.buttonPrimaryClass);
       }
     },
-
+    // Override jQuery UI's `_focusTabbable()` so finding tabbable elements uses
+    // the core/tabbable library instead of jQuery UI's `:tabbable` selector.
     _focusTabbable() {
+      // Set focus to the first match:
+
+      // 1. An element that was focused previously.
       let hasFocus = this._focusedElement ? this._focusedElement.get(0) : null;
 
+      // 2. First element inside the dialog matching [autofocus].
       if (!hasFocus) {
         hasFocus = this.element.find('[autofocus]').get(0);
       }
 
+      // 3. Tabbable element inside the content element.
+      // 4. Tabbable element inside the buttonpane.
       if (!hasFocus) {
         const $elements = [this.element, this.uiDialogButtonPane];
-
         for (let i = 0; i < $elements.length; i++) {
           const element = $elements[i].get(0);
-
           if (element) {
             const elementTabbable = tabbable(element);
             hasFocus = elementTabbable.length ? elementTabbable[0] : null;
           }
-
           if (hasFocus) {
             break;
           }
         }
       }
 
+      // 5. The close button.
       if (!hasFocus) {
         const closeBtn = this.uiDialogTitlebarClose.get(0);
         hasFocus = closeBtn && isTabbable(closeBtn) ? closeBtn : null;
       }
 
+      // 6. The dialog itself.
       if (!hasFocus) {
         hasFocus = this.uiDialog.get(0);
       }
-
       $(hasFocus).eq(0).trigger('focus');
-    }
-
+    },
   });
-})(jQuery, window.tabbable);
\ No newline at end of file
+})(jQuery, window.tabbable);
diff --git a/core/misc/dialog/dialog.js b/core/misc/dialog/dialog.js
index 4062242a66eb..60e339b96915 100644
--- a/core/misc/dialog/dialog.js
+++ b/core/misc/dialog/dialog.js
@@ -1,34 +1,75 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Dialog API inspired by HTML5 dialog element.
+ *
+ * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#the-dialog-element
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * Default dialog options.
+   *
+   * @type {object}
+   *
+   * @prop {bool} [autoOpen=true]
+   * @prop {string} [dialogClass='']
+   * @prop {string} [buttonClass='button']
+   * @prop {string} [buttonPrimaryClass='button--primary']
+   * @prop {function} close
+   */
   drupalSettings.dialog = {
     autoOpen: true,
     dialogClass: '',
+    // Drupal-specific extensions: see dialog.jquery-ui.js.
     buttonClass: 'button',
     buttonPrimaryClass: 'button--primary',
-
+    // When using this API directly (when generating dialogs on the client
+    // side), you may want to override this method and do
+    // `jQuery(event.target).remove()` as well, to remove the dialog on
+    // closing.
     close(event) {
       Drupal.dialog(event.target).close();
       Drupal.detachBehaviors(event.target, null, 'unload');
-    }
-
+    },
   };
 
+  /**
+   * @typedef {object} Drupal.dialog~dialogDefinition
+   *
+   * @prop {boolean} open
+   *   Is the dialog open or not.
+   * @prop {*} returnValue
+   *   Return value of the dialog.
+   * @prop {function} show
+   *   Method to display the dialog on the page.
+   * @prop {function} showModal
+   *   Method to display the dialog as a modal on the page.
+   * @prop {function} close
+   *   Method to hide the dialog from the page.
+   */
+
+  /**
+   * Polyfill HTML5 dialog element with jQueryUI.
+   *
+   * @param {HTMLElement} element
+   *   The element that holds the dialog.
+   * @param {object} options
+   *   jQuery UI options to be passed to the dialog.
+   *
+   * @return {Drupal.dialog~dialogDefinition}
+   *   The dialog instance.
+   */
   Drupal.dialog = function (element, options) {
     let undef;
     const $element = $(element);
     const dialog = {
       open: false,
-      returnValue: undef
+      returnValue: undef,
     };
 
     function openDialog(settings) {
       settings = $.extend({}, drupalSettings.dialog, options, settings);
+      // Trigger a global event to allow scripts to bind events to the dialog.
       $(window).trigger('dialog:beforecreate', [dialog, $element, settings]);
       $element.dialog(settings);
       dialog.open = true;
@@ -44,18 +85,13 @@
     }
 
     dialog.show = () => {
-      openDialog({
-        modal: false
-      });
+      openDialog({ modal: false });
     };
-
     dialog.showModal = () => {
-      openDialog({
-        modal: true
-      });
+      openDialog({ modal: true });
     };
-
     dialog.close = closeDialog;
+
     return dialog;
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/misc/dialog/dialog.position.es6.js b/core/misc/dialog/dialog.position.es6.js
deleted file mode 100644
index d6394c471f0c..000000000000
--- a/core/misc/dialog/dialog.position.es6.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/**
- * @file
- * Positioning extensions for dialogs.
- */
-
-/**
- * Triggers when content inside a dialog changes.
- *
- * @event dialogContentResize
- */
-
-(function ($, Drupal, drupalSettings, debounce, displace) {
-  // autoResize option will turn off resizable and draggable.
-  drupalSettings.dialog = $.extend(
-    { autoResize: true, maxHeight: '95%' },
-    drupalSettings.dialog,
-  );
-
-  /**
-   * Position the dialog's center at the center of displace.offsets boundaries.
-   *
-   * @function Drupal.dialog~resetPosition
-   *
-   * @param {object} options
-   *   Options object.
-   *
-   * @return {object}
-   *   Altered options object.
-   */
-  function resetPosition(options) {
-    const offsets = displace.offsets;
-    const left = offsets.left - offsets.right;
-    const top = offsets.top - offsets.bottom;
-
-    const leftString = `${
-      (left > 0 ? '+' : '-') + Math.abs(Math.round(left / 2))
-    }px`;
-    const topString = `${
-      (top > 0 ? '+' : '-') + Math.abs(Math.round(top / 2))
-    }px`;
-    options.position = {
-      my: `center${left !== 0 ? leftString : ''} center${
-        top !== 0 ? topString : ''
-      }`,
-      of: window,
-    };
-    return options;
-  }
-
-  /**
-   * Resets the current options for positioning.
-   *
-   * This is used as a window resize and scroll callback to reposition the
-   * jQuery UI dialog. Although not a built-in jQuery UI option, this can
-   * be disabled by setting autoResize: false in the options array when creating
-   * a new {@link Drupal.dialog}.
-   *
-   * @function Drupal.dialog~resetSize
-   *
-   * @param {jQuery.Event} event
-   *   The event triggered.
-   *
-   * @fires event:dialogContentResize
-   */
-  function resetSize(event) {
-    const positionOptions = [
-      'width',
-      'height',
-      'minWidth',
-      'minHeight',
-      'maxHeight',
-      'maxWidth',
-      'position',
-    ];
-    let adjustedOptions = {};
-    let windowHeight = $(window).height();
-    let option;
-    let optionValue;
-    let adjustedValue;
-    for (let n = 0; n < positionOptions.length; n++) {
-      option = positionOptions[n];
-      optionValue = event.data.settings[option];
-      if (optionValue) {
-        // jQuery UI does not support percentages on heights, convert to pixels.
-        if (
-          typeof optionValue === 'string' &&
-          /%$/.test(optionValue) &&
-          /height/i.test(option)
-        ) {
-          // Take offsets in account.
-          windowHeight -= displace.offsets.top + displace.offsets.bottom;
-          adjustedValue = parseInt(
-            0.01 * parseInt(optionValue, 10) * windowHeight,
-            10,
-          );
-          // Don't force the dialog to be bigger vertically than needed.
-          if (
-            option === 'height' &&
-            event.data.$element.parent().outerHeight() < adjustedValue
-          ) {
-            adjustedValue = 'auto';
-          }
-          adjustedOptions[option] = adjustedValue;
-        }
-      }
-    }
-    // Offset the dialog center to be at the center of Drupal.displace.offsets.
-    if (!event.data.settings.modal) {
-      adjustedOptions = resetPosition(adjustedOptions);
-    }
-    event.data.$element
-      .dialog('option', adjustedOptions)
-      .trigger('dialogContentResize');
-  }
-
-  $(window).on({
-    'dialog:aftercreate': function (event, dialog, $element, settings) {
-      const autoResize = debounce(resetSize, 20);
-      const eventData = { settings, $element };
-      if (settings.autoResize === true || settings.autoResize === 'true') {
-        $element
-          .dialog('option', { resizable: false, draggable: false })
-          .dialog('widget')
-          .css('position', 'fixed');
-        $(window)
-          .on('resize.dialogResize scroll.dialogResize', eventData, autoResize)
-          .trigger('resize.dialogResize');
-        $(document).on(
-          'drupalViewportOffsetChange.dialogResize',
-          eventData,
-          autoResize,
-        );
-      }
-    },
-    'dialog:beforeclose': function (event, dialog, $element) {
-      $(window).off('.dialogResize');
-      $(document).off('.dialogResize');
-    },
-  });
-})(jQuery, Drupal, drupalSettings, Drupal.debounce, Drupal.displace);
diff --git a/core/misc/dialog/dialog.position.js b/core/misc/dialog/dialog.position.js
index cbda0c294b79..d6394c471f0c 100644
--- a/core/misc/dialog/dialog.position.js
+++ b/core/misc/dialog/dialog.position.js
@@ -1,82 +1,140 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Positioning extensions for dialogs.
+ */
+
+/**
+ * Triggers when content inside a dialog changes.
+ *
+ * @event dialogContentResize
+ */
 
 (function ($, Drupal, drupalSettings, debounce, displace) {
-  drupalSettings.dialog = $.extend({
-    autoResize: true,
-    maxHeight: '95%'
-  }, drupalSettings.dialog);
+  // autoResize option will turn off resizable and draggable.
+  drupalSettings.dialog = $.extend(
+    { autoResize: true, maxHeight: '95%' },
+    drupalSettings.dialog,
+  );
 
+  /**
+   * Position the dialog's center at the center of displace.offsets boundaries.
+   *
+   * @function Drupal.dialog~resetPosition
+   *
+   * @param {object} options
+   *   Options object.
+   *
+   * @return {object}
+   *   Altered options object.
+   */
   function resetPosition(options) {
     const offsets = displace.offsets;
     const left = offsets.left - offsets.right;
     const top = offsets.top - offsets.bottom;
-    const leftString = `${(left > 0 ? '+' : '-') + Math.abs(Math.round(left / 2))}px`;
-    const topString = `${(top > 0 ? '+' : '-') + Math.abs(Math.round(top / 2))}px`;
+
+    const leftString = `${
+      (left > 0 ? '+' : '-') + Math.abs(Math.round(left / 2))
+    }px`;
+    const topString = `${
+      (top > 0 ? '+' : '-') + Math.abs(Math.round(top / 2))
+    }px`;
     options.position = {
-      my: `center${left !== 0 ? leftString : ''} center${top !== 0 ? topString : ''}`,
-      of: window
+      my: `center${left !== 0 ? leftString : ''} center${
+        top !== 0 ? topString : ''
+      }`,
+      of: window,
     };
     return options;
   }
 
+  /**
+   * Resets the current options for positioning.
+   *
+   * This is used as a window resize and scroll callback to reposition the
+   * jQuery UI dialog. Although not a built-in jQuery UI option, this can
+   * be disabled by setting autoResize: false in the options array when creating
+   * a new {@link Drupal.dialog}.
+   *
+   * @function Drupal.dialog~resetSize
+   *
+   * @param {jQuery.Event} event
+   *   The event triggered.
+   *
+   * @fires event:dialogContentResize
+   */
   function resetSize(event) {
-    const positionOptions = ['width', 'height', 'minWidth', 'minHeight', 'maxHeight', 'maxWidth', 'position'];
+    const positionOptions = [
+      'width',
+      'height',
+      'minWidth',
+      'minHeight',
+      'maxHeight',
+      'maxWidth',
+      'position',
+    ];
     let adjustedOptions = {};
     let windowHeight = $(window).height();
     let option;
     let optionValue;
     let adjustedValue;
-
     for (let n = 0; n < positionOptions.length; n++) {
       option = positionOptions[n];
       optionValue = event.data.settings[option];
-
       if (optionValue) {
-        if (typeof optionValue === 'string' && /%$/.test(optionValue) && /height/i.test(option)) {
+        // jQuery UI does not support percentages on heights, convert to pixels.
+        if (
+          typeof optionValue === 'string' &&
+          /%$/.test(optionValue) &&
+          /height/i.test(option)
+        ) {
+          // Take offsets in account.
           windowHeight -= displace.offsets.top + displace.offsets.bottom;
-          adjustedValue = parseInt(0.01 * parseInt(optionValue, 10) * windowHeight, 10);
-
-          if (option === 'height' && event.data.$element.parent().outerHeight() < adjustedValue) {
+          adjustedValue = parseInt(
+            0.01 * parseInt(optionValue, 10) * windowHeight,
+            10,
+          );
+          // Don't force the dialog to be bigger vertically than needed.
+          if (
+            option === 'height' &&
+            event.data.$element.parent().outerHeight() < adjustedValue
+          ) {
             adjustedValue = 'auto';
           }
-
           adjustedOptions[option] = adjustedValue;
         }
       }
     }
-
+    // Offset the dialog center to be at the center of Drupal.displace.offsets.
     if (!event.data.settings.modal) {
       adjustedOptions = resetPosition(adjustedOptions);
     }
-
-    event.data.$element.dialog('option', adjustedOptions).trigger('dialogContentResize');
+    event.data.$element
+      .dialog('option', adjustedOptions)
+      .trigger('dialogContentResize');
   }
 
   $(window).on({
     'dialog:aftercreate': function (event, dialog, $element, settings) {
       const autoResize = debounce(resetSize, 20);
-      const eventData = {
-        settings,
-        $element
-      };
-
+      const eventData = { settings, $element };
       if (settings.autoResize === true || settings.autoResize === 'true') {
-        $element.dialog('option', {
-          resizable: false,
-          draggable: false
-        }).dialog('widget').css('position', 'fixed');
-        $(window).on('resize.dialogResize scroll.dialogResize', eventData, autoResize).trigger('resize.dialogResize');
-        $(document).on('drupalViewportOffsetChange.dialogResize', eventData, autoResize);
+        $element
+          .dialog('option', { resizable: false, draggable: false })
+          .dialog('widget')
+          .css('position', 'fixed');
+        $(window)
+          .on('resize.dialogResize scroll.dialogResize', eventData, autoResize)
+          .trigger('resize.dialogResize');
+        $(document).on(
+          'drupalViewportOffsetChange.dialogResize',
+          eventData,
+          autoResize,
+        );
       }
     },
     'dialog:beforeclose': function (event, dialog, $element) {
       $(window).off('.dialogResize');
       $(document).off('.dialogResize');
-    }
+    },
   });
-})(jQuery, Drupal, drupalSettings, Drupal.debounce, Drupal.displace);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings, Drupal.debounce, Drupal.displace);
diff --git a/core/misc/dialog/off-canvas/js/off-canvas.es6.js b/core/misc/dialog/off-canvas/js/off-canvas.es6.js
deleted file mode 100644
index dedd04907770..000000000000
--- a/core/misc/dialog/off-canvas/js/off-canvas.es6.js
+++ /dev/null
@@ -1,361 +0,0 @@
-/**
- * @file
- * Drupal's off-canvas library.
- */
-
-(($, Drupal, debounce, displace) => {
-  /**
-   * Off-canvas dialog implementation using jQuery Dialog.
-   *
-   * Transforms the regular dialogs created using Drupal.dialog when the dialog
-   * element equals '#drupal-off-canvas' into a side-loading dialog.
-   *
-   * @namespace
-   */
-  Drupal.offCanvas = {
-    /**
-     * Storage for position information about the tray.
-     *
-     * @type {?String}
-     */
-    position: null,
-
-    /**
-     * The minimum height of the tray when opened at the top of the page.
-     *
-     * @type {Number}
-     */
-    minimumHeight: 30,
-
-    /**
-     * The minimum width to use body displace needs to match the width at which
-     * the tray will be 100% width. @see core/misc/dialog/off-canvas.css
-     *
-     * @type {Number}
-     */
-    minDisplaceWidth: 768,
-
-    /**
-     * Wrapper used to position off-canvas dialog.
-     *
-     * @type {jQuery}
-     */
-    $mainCanvasWrapper: $('[data-off-canvas-main-canvas]'),
-
-    /**
-     * Determines if an element is an off-canvas dialog.
-     *
-     * @param {jQuery} $element
-     *   The dialog element.
-     *
-     * @return {bool}
-     *   True this is currently an off-canvas dialog.
-     */
-    isOffCanvas($element) {
-      return $element.is('#drupal-off-canvas');
-    },
-
-    /**
-     * Remove off-canvas dialog events.
-     *
-     * @param {jQuery} $element
-     *   The target element.
-     */
-    removeOffCanvasEvents($element) {
-      $element.off('.off-canvas');
-      $(document).off('.off-canvas');
-      $(window).off('.off-canvas');
-    },
-
-    /**
-     * Handler fired before an off-canvas dialog has been opened.
-     *
-     * @param {Object} settings
-     *   Settings related to the composition of the dialog.
-     *
-     * @return {undefined}
-     */
-    beforeCreate({ settings, $element }) {
-      // Clean up previous dialog event handlers.
-      Drupal.offCanvas.removeOffCanvasEvents($element);
-
-      $('body').addClass('js-off-canvas-dialog-open');
-      // @see http://api.jqueryui.com/position/
-      settings.position = {
-        my: 'left top',
-        at: `${Drupal.offCanvas.getEdge()} top`,
-        of: window,
-      };
-
-      /**
-       * Applies initial height and with to dialog based depending on position.
-       * @see http://api.jqueryui.com/dialog for all dialog options.
-       */
-      const position = settings.drupalOffCanvasPosition;
-      const height = position === 'side' ? $(window).height() : settings.height;
-      const width = position === 'side' ? settings.width : '100%';
-      settings.height = height;
-      settings.width = width;
-    },
-
-    /**
-     * Handler fired after an off-canvas dialog has been closed.
-     *
-     * @return {undefined}
-     */
-    beforeClose({ $element }) {
-      $('body').removeClass('js-off-canvas-dialog-open');
-      // Remove all *.off-canvas events
-      Drupal.offCanvas.removeOffCanvasEvents($element);
-      Drupal.offCanvas.resetPadding();
-    },
-
-    /**
-     * Handler fired when an off-canvas dialog has been opened.
-     *
-     * @param {jQuery} $element
-     *   The off-canvas dialog element.
-     * @param {Object} settings
-     *   Settings related to the composition of the dialog.
-     *
-     * @return {undefined}
-     */
-    afterCreate({ $element, settings }) {
-      const eventData = { settings, $element, offCanvasDialog: this };
-
-      $element
-        .on(
-          'dialogContentResize.off-canvas',
-          eventData,
-          Drupal.offCanvas.handleDialogResize,
-        )
-        .on(
-          'dialogContentResize.off-canvas',
-          eventData,
-          Drupal.offCanvas.bodyPadding,
-        );
-
-      Drupal.offCanvas
-        .getContainer($element)
-        .attr(`data-offset-${Drupal.offCanvas.getEdge()}`, '');
-
-      $(window)
-        .on(
-          'resize.off-canvas',
-          eventData,
-          debounce(Drupal.offCanvas.resetSize, 100),
-        )
-        .trigger('resize.off-canvas');
-    },
-
-    /**
-     * Toggle classes based on title existence.
-     * Called with Drupal.offCanvas.afterCreate.
-     *
-     * @param {Object} settings
-     *   Settings related to the composition of the dialog.
-     *
-     * @return {undefined}
-     */
-    render({ settings }) {
-      $(
-        '.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar',
-      ).toggleClass('ui-dialog-empty-title', !settings.title);
-      $('.ui-dialog-off-canvas').attr('id', 'drupal-off-canvas-wrapper');
-    },
-
-    /**
-     * Adjusts the dialog on resize.
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered.
-     * @param {object} event.data
-     *   Data attached to the event.
-     */
-    handleDialogResize(event) {
-      const $element = event.data.$element;
-      const $container = Drupal.offCanvas.getContainer($element);
-
-      const $offsets = $container.find(
-        '> :not(#drupal-off-canvas, .ui-resizable-handle)',
-      );
-      let offset = 0;
-
-      // Let scroll element take all the height available.
-      $element.css({ height: 'auto' });
-      const modalHeight = $container.height();
-
-      $offsets.each((i, e) => {
-        offset += $(e).outerHeight();
-      });
-
-      // Take internal padding into account.
-      const scrollOffset = $element.outerHeight() - $element.height();
-      $element.height(modalHeight - offset - scrollOffset);
-    },
-
-    /**
-     * Resets the size of the dialog.
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered.
-     * @param {object} event.data
-     *   Data attached to the event.
-     */
-    resetSize(event) {
-      const $element = event.data.$element;
-      const container = Drupal.offCanvas.getContainer($element);
-      const position = event.data.settings.drupalOffCanvasPosition;
-
-      // Only remove the `data-offset-*` attribute if the value previously
-      // exists and the orientation is changing.
-      if (Drupal.offCanvas.position && Drupal.offCanvas.position !== position) {
-        container.removeAttr(`data-offset-${Drupal.offCanvas.position}`);
-      }
-      // Set a minimum height on $element
-      if (position === 'top') {
-        $element.css('min-height', `${Drupal.offCanvas.minimumHeight}px`);
-      }
-
-      displace();
-
-      const offsets = displace.offsets;
-
-      const topPosition =
-        position === 'side' && offsets.top !== 0 ? `+${offsets.top}` : '';
-      const adjustedOptions = {
-        // @see http://api.jqueryui.com/position/
-        position: {
-          my: `${Drupal.offCanvas.getEdge()} top`,
-          at: `${Drupal.offCanvas.getEdge()} top${topPosition}`,
-          of: window,
-        },
-      };
-
-      const height =
-        position === 'side'
-          ? `${$(window).height() - (offsets.top + offsets.bottom)}px`
-          : event.data.settings.height;
-      container.css({
-        position: 'fixed',
-        height,
-      });
-
-      $element
-        .dialog('option', adjustedOptions)
-        .trigger('dialogContentResize.off-canvas');
-
-      Drupal.offCanvas.position = position;
-    },
-
-    /**
-     * Adjusts the body padding when the dialog is resized.
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered.
-     * @param {object} event.data
-     *   Data attached to the event.
-     */
-    bodyPadding(event) {
-      const position = event.data.settings.drupalOffCanvasPosition;
-      if (
-        position === 'side' &&
-        $('body').outerWidth() < Drupal.offCanvas.minDisplaceWidth
-      ) {
-        return;
-      }
-      Drupal.offCanvas.resetPadding();
-      const $element = event.data.$element;
-      const $container = Drupal.offCanvas.getContainer($element);
-      const $mainCanvasWrapper = Drupal.offCanvas.$mainCanvasWrapper;
-
-      const width = $container.outerWidth();
-      const mainCanvasPadding = $mainCanvasWrapper.css(
-        `padding-${Drupal.offCanvas.getEdge()}`,
-      );
-      if (position === 'side' && width !== mainCanvasPadding) {
-        $mainCanvasWrapper.css(
-          `padding-${Drupal.offCanvas.getEdge()}`,
-          `${width}px`,
-        );
-        $container.attr(`data-offset-${Drupal.offCanvas.getEdge()}`, width);
-        displace();
-      }
-
-      const height = $container.outerHeight();
-      if (position === 'top') {
-        $mainCanvasWrapper.css('padding-top', `${height}px`);
-        $container.attr('data-offset-top', height);
-        displace();
-      }
-    },
-
-    /**
-     * The HTML element that surrounds the dialog.
-     * @param {HTMLElement} $element
-     *   The dialog element.
-     *
-     * @return {HTMLElement}
-     *   The containing element.
-     */
-    getContainer($element) {
-      return $element.dialog('widget');
-    },
-
-    /**
-     * The edge of the screen that the dialog should appear on.
-     *
-     * @return {string}
-     *   The edge the tray will be shown on, left or right.
-     */
-    getEdge() {
-      return document.documentElement.dir === 'rtl' ? 'left' : 'right';
-    },
-
-    /**
-     * Resets main canvas wrapper and toolbar padding / margin.
-     */
-    resetPadding() {
-      Drupal.offCanvas.$mainCanvasWrapper.css(
-        `padding-${Drupal.offCanvas.getEdge()}`,
-        0,
-      );
-      Drupal.offCanvas.$mainCanvasWrapper.css('padding-top', 0);
-      displace();
-    },
-  };
-
-  /**
-   * Attaches off-canvas dialog behaviors.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches event listeners for off-canvas dialogs.
-   */
-  Drupal.behaviors.offCanvasEvents = {
-    attach: () => {
-      if (!once('off-canvas', 'html').length) {
-        return;
-      }
-      $(window).on({
-        'dialog:beforecreate': (event, dialog, $element, settings) => {
-          if (Drupal.offCanvas.isOffCanvas($element)) {
-            Drupal.offCanvas.beforeCreate({ dialog, $element, settings });
-          }
-        },
-        'dialog:aftercreate': (event, dialog, $element, settings) => {
-          if (Drupal.offCanvas.isOffCanvas($element)) {
-            Drupal.offCanvas.render({ dialog, $element, settings });
-            Drupal.offCanvas.afterCreate({ $element, settings });
-          }
-        },
-        'dialog:beforeclose': (event, dialog, $element) => {
-          if (Drupal.offCanvas.isOffCanvas($element)) {
-            Drupal.offCanvas.beforeClose({ dialog, $element });
-          }
-        },
-      });
-    },
-  };
-})(jQuery, Drupal, Drupal.debounce, Drupal.displace);
diff --git a/core/misc/dialog/off-canvas/js/off-canvas.js b/core/misc/dialog/off-canvas/js/off-canvas.js
index 99e5741949b1..dedd04907770 100644
--- a/core/misc/dialog/off-canvas/js/off-canvas.js
+++ b/core/misc/dialog/off-canvas/js/off-canvas.js
@@ -1,39 +1,96 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Drupal's off-canvas library.
+ */
 
 (($, Drupal, debounce, displace) => {
+  /**
+   * Off-canvas dialog implementation using jQuery Dialog.
+   *
+   * Transforms the regular dialogs created using Drupal.dialog when the dialog
+   * element equals '#drupal-off-canvas' into a side-loading dialog.
+   *
+   * @namespace
+   */
   Drupal.offCanvas = {
+    /**
+     * Storage for position information about the tray.
+     *
+     * @type {?String}
+     */
     position: null,
+
+    /**
+     * The minimum height of the tray when opened at the top of the page.
+     *
+     * @type {Number}
+     */
     minimumHeight: 30,
+
+    /**
+     * The minimum width to use body displace needs to match the width at which
+     * the tray will be 100% width. @see core/misc/dialog/off-canvas.css
+     *
+     * @type {Number}
+     */
     minDisplaceWidth: 768,
+
+    /**
+     * Wrapper used to position off-canvas dialog.
+     *
+     * @type {jQuery}
+     */
     $mainCanvasWrapper: $('[data-off-canvas-main-canvas]'),
 
+    /**
+     * Determines if an element is an off-canvas dialog.
+     *
+     * @param {jQuery} $element
+     *   The dialog element.
+     *
+     * @return {bool}
+     *   True this is currently an off-canvas dialog.
+     */
     isOffCanvas($element) {
       return $element.is('#drupal-off-canvas');
     },
 
+    /**
+     * Remove off-canvas dialog events.
+     *
+     * @param {jQuery} $element
+     *   The target element.
+     */
     removeOffCanvasEvents($element) {
       $element.off('.off-canvas');
       $(document).off('.off-canvas');
       $(window).off('.off-canvas');
     },
 
-    beforeCreate(_ref) {
-      let {
-        settings,
-        $element
-      } = _ref;
+    /**
+     * Handler fired before an off-canvas dialog has been opened.
+     *
+     * @param {Object} settings
+     *   Settings related to the composition of the dialog.
+     *
+     * @return {undefined}
+     */
+    beforeCreate({ settings, $element }) {
+      // Clean up previous dialog event handlers.
       Drupal.offCanvas.removeOffCanvasEvents($element);
+
       $('body').addClass('js-off-canvas-dialog-open');
+      // @see http://api.jqueryui.com/position/
       settings.position = {
         my: 'left top',
         at: `${Drupal.offCanvas.getEdge()} top`,
-        of: window
+        of: window,
       };
+
+      /**
+       * Applies initial height and with to dialog based depending on position.
+       * @see http://api.jqueryui.com/dialog for all dialog options.
+       */
       const position = settings.drupalOffCanvasPosition;
       const height = position === 'side' ? $(window).height() : settings.height;
       const width = position === 'side' ? settings.width : '100%';
@@ -41,108 +98,191 @@
       settings.width = width;
     },
 
-    beforeClose(_ref2) {
-      let {
-        $element
-      } = _ref2;
+    /**
+     * Handler fired after an off-canvas dialog has been closed.
+     *
+     * @return {undefined}
+     */
+    beforeClose({ $element }) {
       $('body').removeClass('js-off-canvas-dialog-open');
+      // Remove all *.off-canvas events
       Drupal.offCanvas.removeOffCanvasEvents($element);
       Drupal.offCanvas.resetPadding();
     },
 
-    afterCreate(_ref3) {
-      let {
-        $element,
-        settings
-      } = _ref3;
-      const eventData = {
-        settings,
-        $element,
-        offCanvasDialog: this
-      };
-      $element.on('dialogContentResize.off-canvas', eventData, Drupal.offCanvas.handleDialogResize).on('dialogContentResize.off-canvas', eventData, Drupal.offCanvas.bodyPadding);
-      Drupal.offCanvas.getContainer($element).attr(`data-offset-${Drupal.offCanvas.getEdge()}`, '');
-      $(window).on('resize.off-canvas', eventData, debounce(Drupal.offCanvas.resetSize, 100)).trigger('resize.off-canvas');
+    /**
+     * Handler fired when an off-canvas dialog has been opened.
+     *
+     * @param {jQuery} $element
+     *   The off-canvas dialog element.
+     * @param {Object} settings
+     *   Settings related to the composition of the dialog.
+     *
+     * @return {undefined}
+     */
+    afterCreate({ $element, settings }) {
+      const eventData = { settings, $element, offCanvasDialog: this };
+
+      $element
+        .on(
+          'dialogContentResize.off-canvas',
+          eventData,
+          Drupal.offCanvas.handleDialogResize,
+        )
+        .on(
+          'dialogContentResize.off-canvas',
+          eventData,
+          Drupal.offCanvas.bodyPadding,
+        );
+
+      Drupal.offCanvas
+        .getContainer($element)
+        .attr(`data-offset-${Drupal.offCanvas.getEdge()}`, '');
+
+      $(window)
+        .on(
+          'resize.off-canvas',
+          eventData,
+          debounce(Drupal.offCanvas.resetSize, 100),
+        )
+        .trigger('resize.off-canvas');
     },
 
-    render(_ref4) {
-      let {
-        settings
-      } = _ref4;
-      $('.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title);
+    /**
+     * Toggle classes based on title existence.
+     * Called with Drupal.offCanvas.afterCreate.
+     *
+     * @param {Object} settings
+     *   Settings related to the composition of the dialog.
+     *
+     * @return {undefined}
+     */
+    render({ settings }) {
+      $(
+        '.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar',
+      ).toggleClass('ui-dialog-empty-title', !settings.title);
       $('.ui-dialog-off-canvas').attr('id', 'drupal-off-canvas-wrapper');
     },
 
+    /**
+     * Adjusts the dialog on resize.
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered.
+     * @param {object} event.data
+     *   Data attached to the event.
+     */
     handleDialogResize(event) {
       const $element = event.data.$element;
       const $container = Drupal.offCanvas.getContainer($element);
-      const $offsets = $container.find('> :not(#drupal-off-canvas, .ui-resizable-handle)');
+
+      const $offsets = $container.find(
+        '> :not(#drupal-off-canvas, .ui-resizable-handle)',
+      );
       let offset = 0;
-      $element.css({
-        height: 'auto'
-      });
+
+      // Let scroll element take all the height available.
+      $element.css({ height: 'auto' });
       const modalHeight = $container.height();
+
       $offsets.each((i, e) => {
         offset += $(e).outerHeight();
       });
+
+      // Take internal padding into account.
       const scrollOffset = $element.outerHeight() - $element.height();
       $element.height(modalHeight - offset - scrollOffset);
     },
 
+    /**
+     * Resets the size of the dialog.
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered.
+     * @param {object} event.data
+     *   Data attached to the event.
+     */
     resetSize(event) {
       const $element = event.data.$element;
       const container = Drupal.offCanvas.getContainer($element);
       const position = event.data.settings.drupalOffCanvasPosition;
 
+      // Only remove the `data-offset-*` attribute if the value previously
+      // exists and the orientation is changing.
       if (Drupal.offCanvas.position && Drupal.offCanvas.position !== position) {
         container.removeAttr(`data-offset-${Drupal.offCanvas.position}`);
       }
-
+      // Set a minimum height on $element
       if (position === 'top') {
         $element.css('min-height', `${Drupal.offCanvas.minimumHeight}px`);
       }
 
       displace();
+
       const offsets = displace.offsets;
-      const topPosition = position === 'side' && offsets.top !== 0 ? `+${offsets.top}` : '';
+
+      const topPosition =
+        position === 'side' && offsets.top !== 0 ? `+${offsets.top}` : '';
       const adjustedOptions = {
+        // @see http://api.jqueryui.com/position/
         position: {
           my: `${Drupal.offCanvas.getEdge()} top`,
           at: `${Drupal.offCanvas.getEdge()} top${topPosition}`,
-          of: window
-        }
+          of: window,
+        },
       };
-      const height = position === 'side' ? `${$(window).height() - (offsets.top + offsets.bottom)}px` : event.data.settings.height;
+
+      const height =
+        position === 'side'
+          ? `${$(window).height() - (offsets.top + offsets.bottom)}px`
+          : event.data.settings.height;
       container.css({
         position: 'fixed',
-        height
+        height,
       });
-      $element.dialog('option', adjustedOptions).trigger('dialogContentResize.off-canvas');
+
+      $element
+        .dialog('option', adjustedOptions)
+        .trigger('dialogContentResize.off-canvas');
+
       Drupal.offCanvas.position = position;
     },
 
+    /**
+     * Adjusts the body padding when the dialog is resized.
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered.
+     * @param {object} event.data
+     *   Data attached to the event.
+     */
     bodyPadding(event) {
       const position = event.data.settings.drupalOffCanvasPosition;
-
-      if (position === 'side' && $('body').outerWidth() < Drupal.offCanvas.minDisplaceWidth) {
+      if (
+        position === 'side' &&
+        $('body').outerWidth() < Drupal.offCanvas.minDisplaceWidth
+      ) {
         return;
       }
-
       Drupal.offCanvas.resetPadding();
       const $element = event.data.$element;
       const $container = Drupal.offCanvas.getContainer($element);
       const $mainCanvasWrapper = Drupal.offCanvas.$mainCanvasWrapper;
-      const width = $container.outerWidth();
-      const mainCanvasPadding = $mainCanvasWrapper.css(`padding-${Drupal.offCanvas.getEdge()}`);
 
+      const width = $container.outerWidth();
+      const mainCanvasPadding = $mainCanvasWrapper.css(
+        `padding-${Drupal.offCanvas.getEdge()}`,
+      );
       if (position === 'side' && width !== mainCanvasPadding) {
-        $mainCanvasWrapper.css(`padding-${Drupal.offCanvas.getEdge()}`, `${width}px`);
+        $mainCanvasWrapper.css(
+          `padding-${Drupal.offCanvas.getEdge()}`,
+          `${width}px`,
+        );
         $container.attr(`data-offset-${Drupal.offCanvas.getEdge()}`, width);
         displace();
       }
 
       const height = $container.outerHeight();
-
       if (position === 'top') {
         $mainCanvasWrapper.css('padding-top', `${height}px`);
         $container.attr('data-offset-top', height);
@@ -150,59 +290,72 @@
       }
     },
 
+    /**
+     * The HTML element that surrounds the dialog.
+     * @param {HTMLElement} $element
+     *   The dialog element.
+     *
+     * @return {HTMLElement}
+     *   The containing element.
+     */
     getContainer($element) {
       return $element.dialog('widget');
     },
 
+    /**
+     * The edge of the screen that the dialog should appear on.
+     *
+     * @return {string}
+     *   The edge the tray will be shown on, left or right.
+     */
     getEdge() {
       return document.documentElement.dir === 'rtl' ? 'left' : 'right';
     },
 
+    /**
+     * Resets main canvas wrapper and toolbar padding / margin.
+     */
     resetPadding() {
-      Drupal.offCanvas.$mainCanvasWrapper.css(`padding-${Drupal.offCanvas.getEdge()}`, 0);
+      Drupal.offCanvas.$mainCanvasWrapper.css(
+        `padding-${Drupal.offCanvas.getEdge()}`,
+        0,
+      );
       Drupal.offCanvas.$mainCanvasWrapper.css('padding-top', 0);
       displace();
-    }
-
+    },
   };
+
+  /**
+   * Attaches off-canvas dialog behaviors.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches event listeners for off-canvas dialogs.
+   */
   Drupal.behaviors.offCanvasEvents = {
     attach: () => {
       if (!once('off-canvas', 'html').length) {
         return;
       }
-
       $(window).on({
         'dialog:beforecreate': (event, dialog, $element, settings) => {
           if (Drupal.offCanvas.isOffCanvas($element)) {
-            Drupal.offCanvas.beforeCreate({
-              dialog,
-              $element,
-              settings
-            });
+            Drupal.offCanvas.beforeCreate({ dialog, $element, settings });
           }
         },
         'dialog:aftercreate': (event, dialog, $element, settings) => {
           if (Drupal.offCanvas.isOffCanvas($element)) {
-            Drupal.offCanvas.render({
-              dialog,
-              $element,
-              settings
-            });
-            Drupal.offCanvas.afterCreate({
-              $element,
-              settings
-            });
+            Drupal.offCanvas.render({ dialog, $element, settings });
+            Drupal.offCanvas.afterCreate({ $element, settings });
           }
         },
         'dialog:beforeclose': (event, dialog, $element) => {
           if (Drupal.offCanvas.isOffCanvas($element)) {
-            Drupal.offCanvas.beforeClose({
-              dialog,
-              $element
-            });
+            Drupal.offCanvas.beforeClose({ dialog, $element });
           }
-        }
+        },
       });
-    }
+    },
   };
-})(jQuery, Drupal, Drupal.debounce, Drupal.displace);
\ No newline at end of file
+})(jQuery, Drupal, Drupal.debounce, Drupal.displace);
diff --git a/core/misc/displace.es6.js b/core/misc/displace.es6.js
deleted file mode 100644
index 6e673d2c949f..000000000000
--- a/core/misc/displace.es6.js
+++ /dev/null
@@ -1,267 +0,0 @@
-/**
- * @file
- * Manages elements that can offset the size of the viewport.
- *
- * Measures and reports viewport offset dimensions from elements like the
- * toolbar that can potentially displace the positioning of other elements.
- */
-
-/**
- * @typedef {object} Drupal~displaceOffset
- *
- * @prop {number} top
- * @prop {number} left
- * @prop {number} right
- * @prop {number} bottom
- */
-
-/**
- * Triggers when layout of the page changes.
- *
- * This is used to position fixed element on the page during page resize and
- * Toolbar toggling.
- *
- * @event drupalViewportOffsetChange
- */
-(function ($, Drupal, debounce) {
-  /**
-   *
-   * @type {Drupal~displaceOffset}
-   */
-  const cache = {
-    right: 0,
-    left: 0,
-    bottom: 0,
-    top: 0,
-  };
-  /**
-   * The prefix used for the css custom variable name.
-   *
-   * @type {string}
-   */
-  const cssVarPrefix = '--drupal-displace-offset';
-  const documentStyle = document.documentElement.style;
-  const offsetKeys = Object.keys(cache);
-  /**
-   * The object with accessors that update the CSS variable on value update.
-   *
-   * @type {Drupal~displaceOffset}
-   */
-  const offsetProps = {};
-  offsetKeys.forEach((edge) => {
-    offsetProps[edge] = {
-      // Show this property when using Object.keys().
-      enumerable: true,
-      get() {
-        return cache[edge];
-      },
-      set(value) {
-        // Only update the CSS custom variable when the value changed.
-        if (value !== cache[edge]) {
-          documentStyle.setProperty(`${cssVarPrefix}-${edge}`, `${value}px`);
-        }
-        cache[edge] = value;
-      },
-    };
-  });
-
-  /**
-   * Current value of the size of margins on the page.
-   *
-   * This property is read-only and the object is sealed to prevent key name
-   * modifications since key names are used to dynamically construct CSS custom
-   * variable names.
-   *
-   * @name Drupal.displace.offsets
-   *
-   * @type {Drupal~displaceOffset}
-   */
-  const offsets = Object.seal(Object.defineProperties({}, offsetProps));
-
-  /**
-   * Calculates displacement for element based on its dimensions and placement.
-   *
-   * @param {HTMLElement} el
-   *   The element whose dimensions and placement will be measured.
-   *
-   * @param {string} edge
-   *   The name of the edge of the viewport that the element is associated
-   *   with.
-   *
-   * @return {number}
-   *   The viewport displacement distance for the requested edge.
-   */
-  function getRawOffset(el, edge) {
-    const $el = $(el);
-    const documentElement = document.documentElement;
-    let displacement = 0;
-    const horizontal = edge === 'left' || edge === 'right';
-    // Get the offset of the element itself.
-    let placement = $el.offset()[horizontal ? 'left' : 'top'];
-    // Subtract scroll distance from placement to get the distance
-    // to the edge of the viewport.
-    placement -=
-      window[`scroll${horizontal ? 'X' : 'Y'}`] ||
-      document.documentElement[`scroll${horizontal ? 'Left' : 'Top'}`] ||
-      0;
-    // Find the displacement value according to the edge.
-    switch (edge) {
-      // Left and top elements displace as a sum of their own offset value
-      // plus their size.
-      case 'top':
-        // Total displacement is the sum of the elements placement and size.
-        displacement = placement + $el.outerHeight();
-        break;
-
-      case 'left':
-        // Total displacement is the sum of the elements placement and size.
-        displacement = placement + $el.outerWidth();
-        break;
-
-      // Right and bottom elements displace according to their left and
-      // top offset. Their size isn't important.
-      case 'bottom':
-        displacement = documentElement.clientHeight - placement;
-        break;
-
-      case 'right':
-        displacement = documentElement.clientWidth - placement;
-        break;
-
-      default:
-        displacement = 0;
-    }
-    return displacement;
-  }
-
-  /**
-   * Gets a specific edge's offset.
-   *
-   * Any element with the attribute data-offset-{edge} e.g. data-offset-top will
-   * be considered in the viewport offset calculations. If the attribute has a
-   * numeric value, that value will be used. If no value is provided, one will
-   * be calculated using the element's dimensions and placement.
-   *
-   * @function Drupal.displace.calculateOffset
-   *
-   * @param {string} edge
-   *   The name of the edge to calculate. Can be 'top', 'right',
-   *   'bottom' or 'left'.
-   *
-   * @return {number}
-   *   The viewport displacement distance for the requested edge.
-   */
-  function calculateOffset(edge) {
-    let edgeOffset = 0;
-    const displacingElements = document.querySelectorAll(
-      `[data-offset-${edge}]`,
-    );
-    const n = displacingElements.length;
-    for (let i = 0; i < n; i++) {
-      const el = displacingElements[i];
-      // If the element is not visible, do consider its dimensions.
-      if (el.style.display === 'none') {
-        continue;
-      }
-      // If the offset data attribute contains a displacing value, use it.
-      let displacement = parseInt(el.getAttribute(`data-offset-${edge}`), 10);
-      // If the element's offset data attribute exits
-      // but is not a valid number then get the displacement
-      // dimensions directly from the element.
-      // eslint-disable-next-line no-restricted-globals
-      if (isNaN(displacement)) {
-        displacement = getRawOffset(el, edge);
-      }
-      // If the displacement value is larger than the current value for this
-      // edge, use the displacement value.
-      edgeOffset = Math.max(edgeOffset, displacement);
-    }
-
-    return edgeOffset;
-  }
-
-  /**
-   * Informs listeners of the current offset dimensions.
-   *
-   * Corresponding CSS custom variables are also updated.
-   * Corresponding CSS custom variables names are:
-   *  - `--drupal-displace-offset-top`
-   *  - `--drupal-displace-offset-right`
-   *  - `--drupal-displace-offset-bottom`
-   *  - `--drupal-displace-offset-left`
-   *
-   * @function Drupal.displace
-   *
-   * @prop {Drupal~displaceOffset} offsets
-   *
-   * @param {bool} [broadcast=true]
-   *   When true, causes the recalculated offsets values to be
-   *   broadcast to listeners. If none is given, defaults to true.
-   *
-   * @return {Drupal~displaceOffset}
-   *   An object whose keys are the for sides an element -- top, right, bottom
-   *   and left. The value of each key is the viewport displacement distance for
-   *   that edge.
-   *
-   * @fires event:drupalViewportOffsetChange
-   */
-  function displace(broadcast = true) {
-    const newOffsets = {};
-    // Getting the offset and setting the offset needs to be separated because
-    // of performance concerns. Only do DOM/style reading happening here.
-    offsetKeys.forEach((edge) => {
-      newOffsets[edge] = calculateOffset(edge);
-    });
-    // Once we have all the values, write to the DOM/style.
-    offsetKeys.forEach((edge) => {
-      // Updating the value in place also update Drupal.displace.offsets.
-      offsets[edge] = newOffsets[edge];
-    });
-
-    if (broadcast) {
-      $(document).trigger('drupalViewportOffsetChange', offsets);
-    }
-    return offsets;
-  }
-
-  /**
-   * Registers a resize handler on the window.
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.drupalDisplace = {
-    attach() {
-      // Mark this behavior as processed on the first pass.
-      if (this.displaceProcessed) {
-        return;
-      }
-      this.displaceProcessed = true;
-      $(window).on('resize.drupalDisplace', debounce(displace, 200));
-    },
-  };
-
-  /**
-   * Assign the displace function to a property of the Drupal global object.
-   *
-   * @ignore
-   */
-  Drupal.displace = displace;
-
-  /**
-   * Expose offsets to other scripts to avoid having to recalculate offsets.
-   *
-   * @ignore
-   */
-  Object.defineProperty(Drupal.displace, 'offsets', {
-    value: offsets,
-    // Make sure other scripts don't replace this object.
-    writable: false,
-  });
-
-  /**
-   * Expose method to compute a single edge offsets.
-   *
-   * @ignore
-   */
-  Drupal.displace.calculateOffset = calculateOffset;
-})(jQuery, Drupal, Drupal.debounce);
diff --git a/core/misc/displace.js b/core/misc/displace.js
index ac1902b71302..6e673d2c949f 100644
--- a/core/misc/displace.js
+++ b/core/misc/displace.js
@@ -1,58 +1,125 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Manages elements that can offset the size of the viewport.
+ *
+ * Measures and reports viewport offset dimensions from elements like the
+ * toolbar that can potentially displace the positioning of other elements.
+ */
 
+/**
+ * @typedef {object} Drupal~displaceOffset
+ *
+ * @prop {number} top
+ * @prop {number} left
+ * @prop {number} right
+ * @prop {number} bottom
+ */
+
+/**
+ * Triggers when layout of the page changes.
+ *
+ * This is used to position fixed element on the page during page resize and
+ * Toolbar toggling.
+ *
+ * @event drupalViewportOffsetChange
+ */
 (function ($, Drupal, debounce) {
+  /**
+   *
+   * @type {Drupal~displaceOffset}
+   */
   const cache = {
     right: 0,
     left: 0,
     bottom: 0,
-    top: 0
+    top: 0,
   };
+  /**
+   * The prefix used for the css custom variable name.
+   *
+   * @type {string}
+   */
   const cssVarPrefix = '--drupal-displace-offset';
   const documentStyle = document.documentElement.style;
   const offsetKeys = Object.keys(cache);
+  /**
+   * The object with accessors that update the CSS variable on value update.
+   *
+   * @type {Drupal~displaceOffset}
+   */
   const offsetProps = {};
-  offsetKeys.forEach(edge => {
+  offsetKeys.forEach((edge) => {
     offsetProps[edge] = {
+      // Show this property when using Object.keys().
       enumerable: true,
-
       get() {
         return cache[edge];
       },
-
       set(value) {
+        // Only update the CSS custom variable when the value changed.
         if (value !== cache[edge]) {
           documentStyle.setProperty(`${cssVarPrefix}-${edge}`, `${value}px`);
         }
-
         cache[edge] = value;
-      }
-
+      },
     };
   });
+
+  /**
+   * Current value of the size of margins on the page.
+   *
+   * This property is read-only and the object is sealed to prevent key name
+   * modifications since key names are used to dynamically construct CSS custom
+   * variable names.
+   *
+   * @name Drupal.displace.offsets
+   *
+   * @type {Drupal~displaceOffset}
+   */
   const offsets = Object.seal(Object.defineProperties({}, offsetProps));
 
+  /**
+   * Calculates displacement for element based on its dimensions and placement.
+   *
+   * @param {HTMLElement} el
+   *   The element whose dimensions and placement will be measured.
+   *
+   * @param {string} edge
+   *   The name of the edge of the viewport that the element is associated
+   *   with.
+   *
+   * @return {number}
+   *   The viewport displacement distance for the requested edge.
+   */
   function getRawOffset(el, edge) {
     const $el = $(el);
     const documentElement = document.documentElement;
     let displacement = 0;
     const horizontal = edge === 'left' || edge === 'right';
+    // Get the offset of the element itself.
     let placement = $el.offset()[horizontal ? 'left' : 'top'];
-    placement -= window[`scroll${horizontal ? 'X' : 'Y'}`] || document.documentElement[`scroll${horizontal ? 'Left' : 'Top'}`] || 0;
-
+    // Subtract scroll distance from placement to get the distance
+    // to the edge of the viewport.
+    placement -=
+      window[`scroll${horizontal ? 'X' : 'Y'}`] ||
+      document.documentElement[`scroll${horizontal ? 'Left' : 'Top'}`] ||
+      0;
+    // Find the displacement value according to the edge.
     switch (edge) {
+      // Left and top elements displace as a sum of their own offset value
+      // plus their size.
       case 'top':
+        // Total displacement is the sum of the elements placement and size.
         displacement = placement + $el.outerHeight();
         break;
 
       case 'left':
+        // Total displacement is the sum of the elements placement and size.
         displacement = placement + $el.outerWidth();
         break;
 
+      // Right and bottom elements displace according to their left and
+      // top offset. Their size isn't important.
       case 'bottom':
         displacement = documentElement.clientHeight - placement;
         break;
@@ -64,66 +131,137 @@
       default:
         displacement = 0;
     }
-
     return displacement;
   }
 
+  /**
+   * Gets a specific edge's offset.
+   *
+   * Any element with the attribute data-offset-{edge} e.g. data-offset-top will
+   * be considered in the viewport offset calculations. If the attribute has a
+   * numeric value, that value will be used. If no value is provided, one will
+   * be calculated using the element's dimensions and placement.
+   *
+   * @function Drupal.displace.calculateOffset
+   *
+   * @param {string} edge
+   *   The name of the edge to calculate. Can be 'top', 'right',
+   *   'bottom' or 'left'.
+   *
+   * @return {number}
+   *   The viewport displacement distance for the requested edge.
+   */
   function calculateOffset(edge) {
     let edgeOffset = 0;
-    const displacingElements = document.querySelectorAll(`[data-offset-${edge}]`);
+    const displacingElements = document.querySelectorAll(
+      `[data-offset-${edge}]`,
+    );
     const n = displacingElements.length;
-
     for (let i = 0; i < n; i++) {
       const el = displacingElements[i];
-
+      // If the element is not visible, do consider its dimensions.
       if (el.style.display === 'none') {
         continue;
       }
-
+      // If the offset data attribute contains a displacing value, use it.
       let displacement = parseInt(el.getAttribute(`data-offset-${edge}`), 10);
-
+      // If the element's offset data attribute exits
+      // but is not a valid number then get the displacement
+      // dimensions directly from the element.
+      // eslint-disable-next-line no-restricted-globals
       if (isNaN(displacement)) {
         displacement = getRawOffset(el, edge);
       }
-
+      // If the displacement value is larger than the current value for this
+      // edge, use the displacement value.
       edgeOffset = Math.max(edgeOffset, displacement);
     }
 
     return edgeOffset;
   }
 
-  function displace() {
-    let broadcast = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
+  /**
+   * Informs listeners of the current offset dimensions.
+   *
+   * Corresponding CSS custom variables are also updated.
+   * Corresponding CSS custom variables names are:
+   *  - `--drupal-displace-offset-top`
+   *  - `--drupal-displace-offset-right`
+   *  - `--drupal-displace-offset-bottom`
+   *  - `--drupal-displace-offset-left`
+   *
+   * @function Drupal.displace
+   *
+   * @prop {Drupal~displaceOffset} offsets
+   *
+   * @param {bool} [broadcast=true]
+   *   When true, causes the recalculated offsets values to be
+   *   broadcast to listeners. If none is given, defaults to true.
+   *
+   * @return {Drupal~displaceOffset}
+   *   An object whose keys are the for sides an element -- top, right, bottom
+   *   and left. The value of each key is the viewport displacement distance for
+   *   that edge.
+   *
+   * @fires event:drupalViewportOffsetChange
+   */
+  function displace(broadcast = true) {
     const newOffsets = {};
-    offsetKeys.forEach(edge => {
+    // Getting the offset and setting the offset needs to be separated because
+    // of performance concerns. Only do DOM/style reading happening here.
+    offsetKeys.forEach((edge) => {
       newOffsets[edge] = calculateOffset(edge);
     });
-    offsetKeys.forEach(edge => {
+    // Once we have all the values, write to the DOM/style.
+    offsetKeys.forEach((edge) => {
+      // Updating the value in place also update Drupal.displace.offsets.
       offsets[edge] = newOffsets[edge];
     });
 
     if (broadcast) {
       $(document).trigger('drupalViewportOffsetChange', offsets);
     }
-
     return offsets;
   }
 
+  /**
+   * Registers a resize handler on the window.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.drupalDisplace = {
     attach() {
+      // Mark this behavior as processed on the first pass.
       if (this.displaceProcessed) {
         return;
       }
-
       this.displaceProcessed = true;
       $(window).on('resize.drupalDisplace', debounce(displace, 200));
-    }
-
+    },
   };
+
+  /**
+   * Assign the displace function to a property of the Drupal global object.
+   *
+   * @ignore
+   */
   Drupal.displace = displace;
+
+  /**
+   * Expose offsets to other scripts to avoid having to recalculate offsets.
+   *
+   * @ignore
+   */
   Object.defineProperty(Drupal.displace, 'offsets', {
     value: offsets,
-    writable: false
+    // Make sure other scripts don't replace this object.
+    writable: false,
   });
+
+  /**
+   * Expose method to compute a single edge offsets.
+   *
+   * @ignore
+   */
   Drupal.displace.calculateOffset = calculateOffset;
-})(jQuery, Drupal, Drupal.debounce);
\ No newline at end of file
+})(jQuery, Drupal, Drupal.debounce);
diff --git a/core/misc/dropbutton/dropbutton.es6.js b/core/misc/dropbutton/dropbutton.es6.js
deleted file mode 100644
index 5339cb700f03..000000000000
--- a/core/misc/dropbutton/dropbutton.es6.js
+++ /dev/null
@@ -1,236 +0,0 @@
-/**
- * @file
- * Dropbutton feature.
- */
-
-(function ($, Drupal) {
-  /**
-   * A DropButton presents an HTML list as a button with a primary action.
-   *
-   * All secondary actions beyond the first in the list are presented in a
-   * dropdown list accessible through a toggle arrow associated with the button.
-   *
-   * @constructor Drupal.DropButton
-   *
-   * @param {HTMLElement} dropbutton
-   *   A DOM element.
-   * @param {object} settings
-   *   A list of options including:
-   * @param {string} settings.title
-   *   The text inside the toggle link element. This text is hidden
-   *   from visual UAs.
-   */
-  function DropButton(dropbutton, settings) {
-    // Merge defaults with settings.
-    const options = $.extend(
-      { title: Drupal.t('List additional actions') },
-      settings,
-    );
-    const $dropbutton = $(dropbutton);
-
-    /**
-     * @type {jQuery}
-     */
-    this.$dropbutton = $dropbutton;
-
-    /**
-     * @type {jQuery}
-     */
-    this.$list = $dropbutton.find('.dropbutton');
-
-    /**
-     * Find actions and mark them.
-     *
-     * @type {jQuery}
-     */
-    this.$actions = this.$list.find('li').addClass('dropbutton-action');
-
-    // Add the special dropdown only if there are hidden actions.
-    if (this.$actions.length > 1) {
-      // Identify the first element of the collection.
-      const $primary = this.$actions.slice(0, 1);
-      // Identify the secondary actions.
-      const $secondary = this.$actions.slice(1);
-      $secondary.addClass('secondary-action');
-      // Add toggle link.
-      $primary.after(Drupal.theme('dropbuttonToggle', options));
-      // Bind mouse events.
-      this.$dropbutton.addClass('dropbutton-multiple').on({
-        /**
-         * Adds a timeout to close the dropdown on mouseleave.
-         *
-         * @ignore
-         */
-        'mouseleave.dropbutton': $.proxy(this.hoverOut, this),
-
-        /**
-         * Clears timeout when mouseout of the dropdown.
-         *
-         * @ignore
-         */
-        'mouseenter.dropbutton': $.proxy(this.hoverIn, this),
-
-        /**
-         * Similar to mouseleave/mouseenter, but for keyboard navigation.
-         *
-         * @ignore
-         */
-        'focusout.dropbutton': $.proxy(this.focusOut, this),
-
-        /**
-         * @ignore
-         */
-        'focusin.dropbutton': $.proxy(this.focusIn, this),
-      });
-    } else {
-      this.$dropbutton.addClass('dropbutton-single');
-    }
-  }
-
-  /**
-   * Delegated callback for opening and closing dropbutton secondary actions.
-   *
-   * @function Drupal.DropButton~dropbuttonClickHandler
-   *
-   * @param {jQuery.Event} e
-   *   The event triggered.
-   */
-  function dropbuttonClickHandler(e) {
-    e.preventDefault();
-    $(e.target).closest('.dropbutton-wrapper').toggleClass('open');
-  }
-
-  /**
-   * Process elements with the .dropbutton class on page load.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches dropButton behaviors.
-   */
-  Drupal.behaviors.dropButton = {
-    attach(context, settings) {
-      const dropbuttons = once('dropbutton', '.dropbutton-wrapper', context);
-      if (dropbuttons.length) {
-        // Adds the delegated handler that will toggle dropdowns on click.
-        const body = once('dropbutton-click', 'body');
-        if (body.length) {
-          $(body).on('click', '.dropbutton-toggle', dropbuttonClickHandler);
-        }
-        // Initialize all buttons.
-        dropbuttons.forEach((dropbutton) => {
-          DropButton.dropbuttons.push(
-            new DropButton(dropbutton, settings.dropbutton),
-          );
-        });
-      }
-    },
-  };
-
-  /**
-   * Extend the DropButton constructor.
-   */
-  $.extend(
-    DropButton,
-    /** @lends Drupal.DropButton */ {
-      /**
-       * Store all processed DropButtons.
-       *
-       * @type {Array.<Drupal.DropButton>}
-       */
-      dropbuttons: [],
-    },
-  );
-
-  /**
-   * Extend the DropButton prototype.
-   */
-  $.extend(
-    DropButton.prototype,
-    /** @lends Drupal.DropButton# */ {
-      /**
-       * Toggle the dropbutton open and closed.
-       *
-       * @param {bool} [show]
-       *   Force the dropbutton to open by passing true or to close by
-       *   passing false.
-       */
-      toggle(show) {
-        const isBool = typeof show === 'boolean';
-        show = isBool ? show : !this.$dropbutton.hasClass('open');
-        this.$dropbutton.toggleClass('open', show);
-      },
-
-      /**
-       * @method
-       */
-      hoverIn() {
-        // Clear any previous timer we were using.
-        if (this.timerID) {
-          window.clearTimeout(this.timerID);
-        }
-      },
-
-      /**
-       * @method
-       */
-      hoverOut() {
-        // Wait half a second before closing.
-        this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
-      },
-
-      /**
-       * @method
-       */
-      open() {
-        this.toggle(true);
-      },
-
-      /**
-       * @method
-       */
-      close() {
-        this.toggle(false);
-      },
-
-      /**
-       * @param {jQuery.Event} e
-       *   The event triggered.
-       */
-      focusOut(e) {
-        this.hoverOut.call(this, e);
-      },
-
-      /**
-       * @param {jQuery.Event} e
-       *   The event triggered.
-       */
-      focusIn(e) {
-        this.hoverIn.call(this, e);
-      },
-    },
-  );
-
-  $.extend(
-    Drupal.theme,
-    /** @lends Drupal.theme */ {
-      /**
-       * A toggle is an interactive element often bound to a click handler.
-       *
-       * @param {object} options
-       *   Options object.
-       * @param {string} [options.title]
-       *   The button text.
-       *
-       * @return {string}
-       *   A string representing a DOM fragment.
-       */
-      dropbuttonToggle(options) {
-        return `<li class="dropbutton-toggle"><button type="button"><span class="dropbutton-arrow"><span class="visually-hidden">${options.title}</span></span></button></li>`;
-      },
-    },
-  );
-
-  // Expose constructor in the public space.
-  Drupal.DropButton = DropButton;
-})(jQuery, Drupal);
diff --git a/core/misc/dropbutton/dropbutton.js b/core/misc/dropbutton/dropbutton.js
index bf11cefef003..5339cb700f03 100644
--- a/core/misc/dropbutton/dropbutton.js
+++ b/core/misc/dropbutton/dropbutton.js
@@ -1,101 +1,236 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Dropbutton feature.
+ */
 
 (function ($, Drupal) {
+  /**
+   * A DropButton presents an HTML list as a button with a primary action.
+   *
+   * All secondary actions beyond the first in the list are presented in a
+   * dropdown list accessible through a toggle arrow associated with the button.
+   *
+   * @constructor Drupal.DropButton
+   *
+   * @param {HTMLElement} dropbutton
+   *   A DOM element.
+   * @param {object} settings
+   *   A list of options including:
+   * @param {string} settings.title
+   *   The text inside the toggle link element. This text is hidden
+   *   from visual UAs.
+   */
   function DropButton(dropbutton, settings) {
-    const options = $.extend({
-      title: Drupal.t('List additional actions')
-    }, settings);
+    // Merge defaults with settings.
+    const options = $.extend(
+      { title: Drupal.t('List additional actions') },
+      settings,
+    );
     const $dropbutton = $(dropbutton);
+
+    /**
+     * @type {jQuery}
+     */
     this.$dropbutton = $dropbutton;
+
+    /**
+     * @type {jQuery}
+     */
     this.$list = $dropbutton.find('.dropbutton');
+
+    /**
+     * Find actions and mark them.
+     *
+     * @type {jQuery}
+     */
     this.$actions = this.$list.find('li').addClass('dropbutton-action');
 
+    // Add the special dropdown only if there are hidden actions.
     if (this.$actions.length > 1) {
+      // Identify the first element of the collection.
       const $primary = this.$actions.slice(0, 1);
+      // Identify the secondary actions.
       const $secondary = this.$actions.slice(1);
       $secondary.addClass('secondary-action');
+      // Add toggle link.
       $primary.after(Drupal.theme('dropbuttonToggle', options));
+      // Bind mouse events.
       this.$dropbutton.addClass('dropbutton-multiple').on({
+        /**
+         * Adds a timeout to close the dropdown on mouseleave.
+         *
+         * @ignore
+         */
         'mouseleave.dropbutton': $.proxy(this.hoverOut, this),
+
+        /**
+         * Clears timeout when mouseout of the dropdown.
+         *
+         * @ignore
+         */
         'mouseenter.dropbutton': $.proxy(this.hoverIn, this),
+
+        /**
+         * Similar to mouseleave/mouseenter, but for keyboard navigation.
+         *
+         * @ignore
+         */
         'focusout.dropbutton': $.proxy(this.focusOut, this),
-        'focusin.dropbutton': $.proxy(this.focusIn, this)
+
+        /**
+         * @ignore
+         */
+        'focusin.dropbutton': $.proxy(this.focusIn, this),
       });
     } else {
       this.$dropbutton.addClass('dropbutton-single');
     }
   }
 
+  /**
+   * Delegated callback for opening and closing dropbutton secondary actions.
+   *
+   * @function Drupal.DropButton~dropbuttonClickHandler
+   *
+   * @param {jQuery.Event} e
+   *   The event triggered.
+   */
   function dropbuttonClickHandler(e) {
     e.preventDefault();
     $(e.target).closest('.dropbutton-wrapper').toggleClass('open');
   }
 
+  /**
+   * Process elements with the .dropbutton class on page load.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches dropButton behaviors.
+   */
   Drupal.behaviors.dropButton = {
     attach(context, settings) {
       const dropbuttons = once('dropbutton', '.dropbutton-wrapper', context);
-
       if (dropbuttons.length) {
+        // Adds the delegated handler that will toggle dropdowns on click.
         const body = once('dropbutton-click', 'body');
-
         if (body.length) {
           $(body).on('click', '.dropbutton-toggle', dropbuttonClickHandler);
         }
-
-        dropbuttons.forEach(dropbutton => {
-          DropButton.dropbuttons.push(new DropButton(dropbutton, settings.dropbutton));
+        // Initialize all buttons.
+        dropbuttons.forEach((dropbutton) => {
+          DropButton.dropbuttons.push(
+            new DropButton(dropbutton, settings.dropbutton),
+          );
         });
       }
-    }
-
-  };
-  $.extend(DropButton, {
-    dropbuttons: []
-  });
-  $.extend(DropButton.prototype, {
-    toggle(show) {
-      const isBool = typeof show === 'boolean';
-      show = isBool ? show : !this.$dropbutton.hasClass('open');
-      this.$dropbutton.toggleClass('open', show);
-    },
-
-    hoverIn() {
-      if (this.timerID) {
-        window.clearTimeout(this.timerID);
-      }
-    },
-
-    hoverOut() {
-      this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
     },
+  };
 
-    open() {
-      this.toggle(true);
+  /**
+   * Extend the DropButton constructor.
+   */
+  $.extend(
+    DropButton,
+    /** @lends Drupal.DropButton */ {
+      /**
+       * Store all processed DropButtons.
+       *
+       * @type {Array.<Drupal.DropButton>}
+       */
+      dropbuttons: [],
     },
-
-    close() {
-      this.toggle(false);
+  );
+
+  /**
+   * Extend the DropButton prototype.
+   */
+  $.extend(
+    DropButton.prototype,
+    /** @lends Drupal.DropButton# */ {
+      /**
+       * Toggle the dropbutton open and closed.
+       *
+       * @param {bool} [show]
+       *   Force the dropbutton to open by passing true or to close by
+       *   passing false.
+       */
+      toggle(show) {
+        const isBool = typeof show === 'boolean';
+        show = isBool ? show : !this.$dropbutton.hasClass('open');
+        this.$dropbutton.toggleClass('open', show);
+      },
+
+      /**
+       * @method
+       */
+      hoverIn() {
+        // Clear any previous timer we were using.
+        if (this.timerID) {
+          window.clearTimeout(this.timerID);
+        }
+      },
+
+      /**
+       * @method
+       */
+      hoverOut() {
+        // Wait half a second before closing.
+        this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
+      },
+
+      /**
+       * @method
+       */
+      open() {
+        this.toggle(true);
+      },
+
+      /**
+       * @method
+       */
+      close() {
+        this.toggle(false);
+      },
+
+      /**
+       * @param {jQuery.Event} e
+       *   The event triggered.
+       */
+      focusOut(e) {
+        this.hoverOut.call(this, e);
+      },
+
+      /**
+       * @param {jQuery.Event} e
+       *   The event triggered.
+       */
+      focusIn(e) {
+        this.hoverIn.call(this, e);
+      },
     },
-
-    focusOut(e) {
-      this.hoverOut.call(this, e);
+  );
+
+  $.extend(
+    Drupal.theme,
+    /** @lends Drupal.theme */ {
+      /**
+       * A toggle is an interactive element often bound to a click handler.
+       *
+       * @param {object} options
+       *   Options object.
+       * @param {string} [options.title]
+       *   The button text.
+       *
+       * @return {string}
+       *   A string representing a DOM fragment.
+       */
+      dropbuttonToggle(options) {
+        return `<li class="dropbutton-toggle"><button type="button"><span class="dropbutton-arrow"><span class="visually-hidden">${options.title}</span></span></button></li>`;
+      },
     },
+  );
 
-    focusIn(e) {
-      this.hoverIn.call(this, e);
-    }
-
-  });
-  $.extend(Drupal.theme, {
-    dropbuttonToggle(options) {
-      return `<li class="dropbutton-toggle"><button type="button"><span class="dropbutton-arrow"><span class="visually-hidden">${options.title}</span></span></button></li>`;
-    }
-
-  });
+  // Expose constructor in the public space.
   Drupal.DropButton = DropButton;
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/misc/drupal.es6.js b/core/misc/drupal.es6.js
deleted file mode 100644
index 86359715dfd1..000000000000
--- a/core/misc/drupal.es6.js
+++ /dev/null
@@ -1,655 +0,0 @@
-/**
- * @file
- * Defines the Drupal JavaScript API.
- */
-
-/**
- * A jQuery object, typically the return value from a `$(selector)` call.
- *
- * Holds an HTMLElement or a collection of HTMLElements.
- *
- * @typedef {object} jQuery
- *
- * @prop {number} length=0
- *   Number of elements contained in the jQuery object.
- */
-
-/**
- * Variable generated by Drupal that holds all translated strings from PHP.
- *
- * Content of this variable is automatically created by Drupal when using the
- * Interface Translation module. It holds the translation of strings used on
- * the page.
- *
- * This variable is used to pass data from the backend to the frontend. Data
- * contained in `drupalSettings` is used during behavior initialization.
- *
- * @global
- *
- * @var {object} drupalTranslations
- */
-
-/**
- * Global Drupal object.
- *
- * All Drupal JavaScript APIs are contained in this namespace.
- *
- * @global
- *
- * @namespace
- */
-window.Drupal = { behaviors: {}, locale: {} };
-
-// JavaScript should be made compatible with libraries other than jQuery by
-// wrapping it in an anonymous closure.
-(function (
-  Drupal,
-  drupalSettings,
-  drupalTranslations,
-  console,
-  Proxy,
-  Reflect,
-) {
-  /**
-   * Helper to rethrow errors asynchronously.
-   *
-   * This way Errors bubbles up outside of the original callstack, making it
-   * easier to debug errors in the browser.
-   *
-   * @param {Error|string} error
-   *   The error to be thrown.
-   */
-  Drupal.throwError = function (error) {
-    setTimeout(() => {
-      throw error;
-    }, 0);
-  };
-
-  /**
-   * Custom error thrown after attach/detach if one or more behaviors failed.
-   * Initializes the JavaScript behaviors for page loads and Ajax requests.
-   *
-   * @callback Drupal~behaviorAttach
-   *
-   * @param {HTMLDocument|HTMLElement} context
-   *   An element to detach behaviors from.
-   * @param {?object} settings
-   *   An object containing settings for the current context. It is rarely used.
-   *
-   * @see Drupal.attachBehaviors
-   */
-
-  /**
-   * Reverts and cleans up JavaScript behavior initialization.
-   *
-   * @callback Drupal~behaviorDetach
-   *
-   * @param {HTMLDocument|HTMLElement} context
-   *   An element to attach behaviors to.
-   * @param {object} settings
-   *   An object containing settings for the current context.
-   * @param {string} trigger
-   *   One of `'unload'`, `'move'`, or `'serialize'`.
-   *
-   * @see Drupal.detachBehaviors
-   */
-
-  /**
-   * @typedef {object} Drupal~behavior
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Function run on page load and after an Ajax call.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Function run when content is serialized or removed from the page.
-   */
-
-  /**
-   * Holds all initialization methods.
-   *
-   * @namespace Drupal.behaviors
-   *
-   * @type {Object.<string, Drupal~behavior>}
-   */
-
-  /**
-   * Defines a behavior to be run during attach and detach phases.
-   *
-   * Attaches all registered behaviors to a page element.
-   *
-   * Behaviors are event-triggered actions that attach to page elements,
-   * enhancing default non-JavaScript UIs. Behaviors are registered in the
-   * {@link Drupal.behaviors} object using the method 'attach' and optionally
-   * also 'detach'.
-   *
-   * {@link Drupal.attachBehaviors} is added below to the `jQuery.ready` event
-   * and therefore runs on initial page load. Developers implementing Ajax in
-   * their solutions should also call this function after new page content has
-   * been loaded, feeding in an element to be processed, in order to attach all
-   * behaviors to the new content.
-   *
-   * Behaviors should use `var elements =
-   * once('behavior-name', selector, context);` to ensure the behavior is
-   * attached only once to a given element. (Doing so enables the reprocessing
-   * of given elements, which may be needed on occasion despite the ability to
-   * limit behavior attachment to a particular element.)
-   *
-   * @example
-   * Drupal.behaviors.behaviorName = {
-   *   attach: function (context, settings) {
-   *     // ...
-   *   },
-   *   detach: function (context, settings, trigger) {
-   *     // ...
-   *   }
-   * };
-   *
-   * @param {HTMLDocument|HTMLElement} [context=document]
-   *   An element to attach behaviors to.
-   * @param {object} [settings=drupalSettings]
-   *   An object containing settings for the current context. If none is given,
-   *   the global {@link drupalSettings} object is used.
-   *
-   * @see Drupal~behaviorAttach
-   * @see Drupal.detachBehaviors
-   *
-   * @throws {Drupal~DrupalBehaviorError}
-   */
-  Drupal.attachBehaviors = function (context, settings) {
-    context = context || document;
-    settings = settings || drupalSettings;
-    const behaviors = Drupal.behaviors;
-    // Execute all of them.
-    Object.keys(behaviors || {}).forEach((i) => {
-      if (typeof behaviors[i].attach === 'function') {
-        // Don't stop the execution of behaviors in case of an error.
-        try {
-          behaviors[i].attach(context, settings);
-        } catch (e) {
-          Drupal.throwError(e);
-        }
-      }
-    });
-  };
-
-  /**
-   * Detaches registered behaviors from a page element.
-   *
-   * Developers implementing Ajax in their solutions should call this function
-   * before page content is about to be removed, feeding in an element to be
-   * processed, in order to allow special behaviors to detach from the content.
-   *
-   * Such implementations should use `once.filter()` and `once.remove()` to find
-   * elements with their corresponding `Drupal.behaviors.behaviorName.attach`
-   * implementation, i.e. `once.remove('behaviorName', selector, context)`,
-   * to ensure the behavior is detached only from previously processed elements.
-   *
-   * @param {HTMLDocument|HTMLElement} [context=document]
-   *   An element to detach behaviors from.
-   * @param {object} [settings=drupalSettings]
-   *   An object containing settings for the current context. If none given,
-   *   the global {@link drupalSettings} object is used.
-   * @param {string} [trigger='unload']
-   *   A string containing what's causing the behaviors to be detached. The
-   *   possible triggers are:
-   *   - `'unload'`: The context element is being removed from the DOM.
-   *   - `'move'`: The element is about to be moved within the DOM (for example,
-   *     during a tabledrag row swap). After the move is completed,
-   *     {@link Drupal.attachBehaviors} is called, so that the behavior can undo
-   *     whatever it did in response to the move. Many behaviors won't need to
-   *     do anything simply in response to the element being moved, but because
-   *     IFRAME elements reload their "src" when being moved within the DOM,
-   *     behaviors bound to IFRAME elements (like WYSIWYG editors) may need to
-   *     take some action.
-   *   - `'serialize'`: When an Ajax form is submitted, this is called with the
-   *     form as the context. This provides every behavior within the form an
-   *     opportunity to ensure that the field elements have correct content
-   *     in them before the form is serialized. The canonical use-case is so
-   *     that WYSIWYG editors can update the hidden textarea to which they are
-   *     bound.
-   *
-   * @throws {Drupal~DrupalBehaviorError}
-   *
-   * @see Drupal~behaviorDetach
-   * @see Drupal.attachBehaviors
-   */
-  Drupal.detachBehaviors = function (context, settings, trigger) {
-    context = context || document;
-    settings = settings || drupalSettings;
-    trigger = trigger || 'unload';
-    const behaviors = Drupal.behaviors;
-    // Execute all of them.
-    Object.keys(behaviors || {}).forEach((i) => {
-      if (typeof behaviors[i].detach === 'function') {
-        // Don't stop the execution of behaviors in case of an error.
-        try {
-          behaviors[i].detach(context, settings, trigger);
-        } catch (e) {
-          Drupal.throwError(e);
-        }
-      }
-    });
-  };
-
-  /**
-   * Encodes special characters in a plain-text string for display as HTML.
-   *
-   * @param {string} str
-   *   The string to be encoded.
-   *
-   * @return {string}
-   *   The encoded string.
-   *
-   * @ingroup sanitization
-   */
-  Drupal.checkPlain = function (str) {
-    str = str
-      .toString()
-      .replace(/&/g, '&amp;')
-      .replace(/</g, '&lt;')
-      .replace(/>/g, '&gt;')
-      .replace(/"/g, '&quot;')
-      .replace(/'/g, '&#39;');
-    return str;
-  };
-
-  /**
-   * Replaces placeholders with sanitized values in a string.
-   *
-   * @param {string} str
-   *   A string with placeholders.
-   * @param {object} args
-   *   An object of replacements pairs to make. Incidences of any key in this
-   *   array are replaced with the corresponding value. Based on the first
-   *   character of the key, the value is escaped and/or themed:
-   *    - `'!variable'`: inserted as is.
-   *    - `'@variable'`: escape plain text to HTML ({@link Drupal.checkPlain}).
-   *    - `'%variable'`: escape text and theme as a placeholder for user-
-   *      submitted content ({@link Drupal.checkPlain} +
-   *      `{@link Drupal.theme}('placeholder')`).
-   *
-   * @return {string}
-   *   The formatted string.
-   *
-   * @see Drupal.t
-   */
-  Drupal.formatString = function (str, args) {
-    // Keep args intact.
-    const processedArgs = {};
-    // Transform arguments before inserting them.
-    Object.keys(args || {}).forEach((key) => {
-      switch (key.charAt(0)) {
-        // Escaped only.
-        case '@':
-          processedArgs[key] = Drupal.checkPlain(args[key]);
-          break;
-
-        // Pass-through.
-        case '!':
-          processedArgs[key] = args[key];
-          break;
-
-        // Escaped and placeholder.
-        default:
-          processedArgs[key] = Drupal.theme('placeholder', args[key]);
-          break;
-      }
-    });
-
-    return Drupal.stringReplace(str, processedArgs, null);
-  };
-
-  /**
-   * Replaces substring.
-   *
-   * The longest keys will be tried first. Once a substring has been replaced,
-   * its new value will not be searched again.
-   *
-   * @param {string} str
-   *   A string with placeholders.
-   * @param {object} args
-   *   Key-value pairs.
-   * @param {Array|null} keys
-   *   Array of keys from `args`. Internal use only.
-   *
-   * @return {string}
-   *   The replaced string.
-   */
-  Drupal.stringReplace = function (str, args, keys) {
-    if (str.length === 0) {
-      return str;
-    }
-
-    // If the array of keys is not passed then collect the keys from the args.
-    if (!Array.isArray(keys)) {
-      keys = Object.keys(args || {});
-
-      // Order the keys by the character length. The shortest one is the first.
-      keys.sort((a, b) => a.length - b.length);
-    }
-
-    if (keys.length === 0) {
-      return str;
-    }
-
-    // Take next longest one from the end.
-    const key = keys.pop();
-    const fragments = str.split(key);
-
-    if (keys.length) {
-      for (let i = 0; i < fragments.length; i++) {
-        // Process each fragment with a copy of remaining keys.
-        fragments[i] = Drupal.stringReplace(fragments[i], args, keys.slice(0));
-      }
-    }
-
-    return fragments.join(args[key]);
-  };
-
-  /**
-   * Translates strings to the page language, or a given language.
-   *
-   * See the documentation of the server-side t() function for further details.
-   *
-   * @param {string} str
-   *   A string containing the English text to translate.
-   * @param {Object.<string, string>} [args]
-   *   An object of replacements pairs to make after translation. Incidences
-   *   of any key in this array are replaced with the corresponding value.
-   *   See {@link Drupal.formatString}.
-   * @param {object} [options]
-   *   Additional options for translation.
-   * @param {string} [options.context='']
-   *   The context the source string belongs to.
-   *
-   * @return {string}
-   *   The formatted string.
-   *   The translated string.
-   */
-  Drupal.t = function (str, args, options) {
-    options = options || {};
-    options.context = options.context || '';
-
-    // Fetch the localized version of the string.
-    if (
-      typeof drupalTranslations !== 'undefined' &&
-      drupalTranslations.strings &&
-      drupalTranslations.strings[options.context] &&
-      drupalTranslations.strings[options.context][str]
-    ) {
-      str = drupalTranslations.strings[options.context][str];
-    }
-
-    if (args) {
-      str = Drupal.formatString(str, args);
-    }
-    return str;
-  };
-
-  /**
-   * Returns the URL to a Drupal page.
-   *
-   * @param {string} path
-   *   Drupal path to transform to URL.
-   *
-   * @return {string}
-   *   The full URL.
-   */
-  Drupal.url = function (path) {
-    return drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix + path;
-  };
-
-  /**
-   * Returns the passed in URL as an absolute URL.
-   *
-   * @param {string} url
-   *   The URL string to be normalized to an absolute URL.
-   *
-   * @return {string}
-   *   The normalized, absolute URL.
-   *
-   * @see https://github.com/angular/angular.js/blob/v1.4.4/src/ng/urlUtils.js
-   * @see https://grack.com/blog/2009/11/17/absolutizing-url-in-javascript
-   * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L53
-   */
-  Drupal.url.toAbsolute = function (url) {
-    const urlParsingNode = document.createElement('a');
-
-    // Decode the URL first; this is required by IE <= 6. Decoding non-UTF-8
-    // strings may throw an exception.
-    try {
-      url = decodeURIComponent(url);
-    } catch (e) {
-      // Empty.
-    }
-
-    urlParsingNode.setAttribute('href', url);
-
-    // IE <= 7 normalizes the URL when assigned to the anchor node similar to
-    // the other browsers.
-    return urlParsingNode.cloneNode(false).href;
-  };
-
-  /**
-   * Returns true if the URL is within Drupal's base path.
-   *
-   * @param {string} url
-   *   The URL string to be tested.
-   *
-   * @return {bool}
-   *   `true` if local.
-   *
-   * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L58
-   */
-  Drupal.url.isLocal = function (url) {
-    // Always use browser-derived absolute URLs in the comparison, to avoid
-    // attempts to break out of the base path using directory traversal.
-    let absoluteUrl = Drupal.url.toAbsolute(url);
-    let { protocol } = window.location;
-
-    // Consider URLs that match this site's base URL but use HTTPS instead of HTTP
-    // as local as well.
-    if (protocol === 'http:' && absoluteUrl.indexOf('https:') === 0) {
-      protocol = 'https:';
-    }
-    let baseUrl = `${protocol}//${
-      window.location.host
-    }${drupalSettings.path.baseUrl.slice(0, -1)}`;
-
-    // Decoding non-UTF-8 strings may throw an exception.
-    try {
-      absoluteUrl = decodeURIComponent(absoluteUrl);
-    } catch (e) {
-      // Empty.
-    }
-    try {
-      baseUrl = decodeURIComponent(baseUrl);
-    } catch (e) {
-      // Empty.
-    }
-
-    // The given URL matches the site's base URL, or has a path under the site's
-    // base URL.
-    return absoluteUrl === baseUrl || absoluteUrl.indexOf(`${baseUrl}/`) === 0;
-  };
-
-  /**
-   * Formats a string containing a count of items.
-   *
-   * This function ensures that the string is pluralized correctly. Since
-   * {@link Drupal.t} is called by this function, make sure not to pass
-   * already-localized strings to it.
-   *
-   * See the documentation of the server-side
-   * \Drupal\Core\StringTranslation\TranslationInterface::formatPlural()
-   * function for more details.
-   *
-   * @param {number} count
-   *   The item count to display.
-   * @param {string} singular
-   *   The string for the singular case. Please make sure it is clear this is
-   *   singular, to ease translation (e.g. use "1 new comment" instead of "1
-   *   new"). Do not use @count in the singular string.
-   * @param {string} plural
-   *   The string for the plural case. Please make sure it is clear this is
-   *   plural, to ease translation. Use @count in place of the item count, as in
-   *   "@count new comments".
-   * @param {object} [args]
-   *   An object of replacements pairs to make after translation. Incidences
-   *   of any key in this array are replaced with the corresponding value.
-   *   See {@link Drupal.formatString}.
-   *   Note that you do not need to include @count in this array.
-   *   This replacement is done automatically for the plural case.
-   * @param {object} [options]
-   *   The options to pass to the {@link Drupal.t} function.
-   *
-   * @return {string}
-   *   A translated string.
-   */
-  Drupal.formatPlural = function (count, singular, plural, args, options) {
-    args = args || {};
-    args['@count'] = count;
-
-    const pluralDelimiter = drupalSettings.pluralDelimiter;
-    const translations = Drupal.t(
-      singular + pluralDelimiter + plural,
-      args,
-      options,
-    ).split(pluralDelimiter);
-    let index = 0;
-
-    // Determine the index of the plural form.
-    if (
-      typeof drupalTranslations !== 'undefined' &&
-      drupalTranslations.pluralFormula
-    ) {
-      index =
-        count in drupalTranslations.pluralFormula
-          ? drupalTranslations.pluralFormula[count]
-          : drupalTranslations.pluralFormula.default;
-    } else if (args['@count'] !== 1) {
-      index = 1;
-    }
-
-    return translations[index];
-  };
-
-  /**
-   * Encodes a Drupal path for use in a URL.
-   *
-   * For aesthetic reasons slashes are not escaped.
-   *
-   * @param {string} item
-   *   Unencoded path.
-   *
-   * @return {string}
-   *   The encoded path.
-   */
-  Drupal.encodePath = function (item) {
-    return window.encodeURIComponent(item).replace(/%2F/g, '/');
-  };
-
-  /**
-   * Triggers deprecation error.
-   *
-   * Deprecation errors are only triggered if deprecation errors haven't
-   * been suppressed.
-   *
-   * @param {Object} deprecation
-   *   The deprecation options.
-   * @param {string} deprecation.message
-   *   The deprecation message.
-   *
-   * @see https://www.drupal.org/core/deprecation#javascript
-   */
-  Drupal.deprecationError = ({ message }) => {
-    if (
-      drupalSettings.suppressDeprecationErrors === false &&
-      typeof console !== 'undefined' &&
-      console.warn
-    ) {
-      console.warn(`[Deprecation] ${message}`);
-    }
-  };
-
-  /**
-   * Triggers deprecation error when object property is being used.
-   *
-   * @param {Object} deprecation
-   *   The deprecation options.
-   * @param {Object} deprecation.target
-   *   The targeted object.
-   * @param {string} deprecation.deprecatedProperty
-   *   A key of the deprecated property.
-   * @param {string} deprecation.message
-   *   The deprecation message.
-   * @returns {Object}
-   *
-   * @see https://www.drupal.org/core/deprecation#javascript
-   */
-  Drupal.deprecatedProperty = ({ target, deprecatedProperty, message }) => {
-    // Proxy and Reflect are not supported by all browsers. Unsupported browsers
-    // are ignored since this is a development feature.
-    if (!Proxy || !Reflect) {
-      return target;
-    }
-
-    return new Proxy(target, {
-      get: (target, key, ...rest) => {
-        if (key === deprecatedProperty) {
-          Drupal.deprecationError({ message });
-        }
-        return Reflect.get(target, key, ...rest);
-      },
-    });
-  };
-
-  /**
-   * Generates the themed representation of a Drupal object.
-   *
-   * All requests for themed output must go through this function. It examines
-   * the request and routes it to the appropriate theme function. If the current
-   * theme does not provide an override function, the generic theme function is
-   * called.
-   *
-   * @example
-   * <caption>To retrieve the HTML for text that should be emphasized and
-   * displayed as a placeholder inside a sentence.</caption>
-   * Drupal.theme('placeholder', text);
-   *
-   * @namespace
-   *
-   * @param {function} func
-   *   The name of the theme function to call.
-   * @param {...args}
-   *   Additional arguments to pass along to the theme function.
-   *
-   * @return {string|object|HTMLElement|jQuery}
-   *   Any data the theme function returns. This could be a plain HTML string,
-   *   but also a complex object.
-   */
-  Drupal.theme = function (func, ...args) {
-    if (func in Drupal.theme) {
-      return Drupal.theme[func](...args);
-    }
-  };
-
-  /**
-   * Formats text for emphasized display in a placeholder inside a sentence.
-   *
-   * @param {string} str
-   *   The text to format (plain-text).
-   *
-   * @return {string}
-   *   The formatted text (html).
-   */
-  Drupal.theme.placeholder = function (str) {
-    return `<em class="placeholder">${Drupal.checkPlain(str)}</em>`;
-  };
-})(
-  Drupal,
-  window.drupalSettings,
-  window.drupalTranslations,
-  window.console,
-  window.Proxy,
-  window.Reflect,
-);
diff --git a/core/misc/drupal.init.es6.js b/core/misc/drupal.init.es6.js
deleted file mode 100644
index c3d961550d53..000000000000
--- a/core/misc/drupal.init.es6.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// Allow other JavaScript libraries to use $.
-if (window.jQuery) {
-  jQuery.noConflict();
-}
-
-// Class indicating that JS is enabled; used for styling purpose.
-document.documentElement.className += ' js';
-
-// JavaScript should be made compatible with libraries other than jQuery by
-// wrapping it in an anonymous closure.
-(function (Drupal, drupalSettings) {
-  /**
-   * Calls callback when document ready.
-   *
-   * @param {function} callback
-   *   The function to be called on document ready.
-   */
-  const domReady = (callback) => {
-    const listener = () => {
-      callback();
-      document.removeEventListener('DOMContentLoaded', listener);
-    };
-    if (document.readyState !== 'loading') {
-      setTimeout(callback, 0);
-    } else {
-      document.addEventListener('DOMContentLoaded', listener);
-    }
-  };
-
-  // Attach all behaviors.
-  domReady(() => {
-    Drupal.attachBehaviors(document, drupalSettings);
-  });
-})(Drupal, window.drupalSettings);
diff --git a/core/misc/drupal.init.js b/core/misc/drupal.init.js
index be0cae2fcdd5..c3d961550d53 100644
--- a/core/misc/drupal.init.js
+++ b/core/misc/drupal.init.js
@@ -1,23 +1,25 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+// Allow other JavaScript libraries to use $.
 if (window.jQuery) {
   jQuery.noConflict();
 }
 
+// Class indicating that JS is enabled; used for styling purpose.
 document.documentElement.className += ' js';
 
+// JavaScript should be made compatible with libraries other than jQuery by
+// wrapping it in an anonymous closure.
 (function (Drupal, drupalSettings) {
-  const domReady = callback => {
+  /**
+   * Calls callback when document ready.
+   *
+   * @param {function} callback
+   *   The function to be called on document ready.
+   */
+  const domReady = (callback) => {
     const listener = () => {
       callback();
       document.removeEventListener('DOMContentLoaded', listener);
     };
-
     if (document.readyState !== 'loading') {
       setTimeout(callback, 0);
     } else {
@@ -25,7 +27,8 @@ document.documentElement.className += ' js';
     }
   };
 
+  // Attach all behaviors.
   domReady(() => {
     Drupal.attachBehaviors(document, drupalSettings);
   });
-})(Drupal, window.drupalSettings);
\ No newline at end of file
+})(Drupal, window.drupalSettings);
diff --git a/core/misc/drupal.js b/core/misc/drupal.js
index 79e64d06a67a..86359715dfd1 100644
--- a/core/misc/drupal.js
+++ b/core/misc/drupal.js
@@ -1,28 +1,167 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-window.Drupal = {
-  behaviors: {},
-  locale: {}
-};
-
-(function (Drupal, drupalSettings, drupalTranslations, console, Proxy, Reflect) {
+ * @file
+ * Defines the Drupal JavaScript API.
+ */
+
+/**
+ * A jQuery object, typically the return value from a `$(selector)` call.
+ *
+ * Holds an HTMLElement or a collection of HTMLElements.
+ *
+ * @typedef {object} jQuery
+ *
+ * @prop {number} length=0
+ *   Number of elements contained in the jQuery object.
+ */
+
+/**
+ * Variable generated by Drupal that holds all translated strings from PHP.
+ *
+ * Content of this variable is automatically created by Drupal when using the
+ * Interface Translation module. It holds the translation of strings used on
+ * the page.
+ *
+ * This variable is used to pass data from the backend to the frontend. Data
+ * contained in `drupalSettings` is used during behavior initialization.
+ *
+ * @global
+ *
+ * @var {object} drupalTranslations
+ */
+
+/**
+ * Global Drupal object.
+ *
+ * All Drupal JavaScript APIs are contained in this namespace.
+ *
+ * @global
+ *
+ * @namespace
+ */
+window.Drupal = { behaviors: {}, locale: {} };
+
+// JavaScript should be made compatible with libraries other than jQuery by
+// wrapping it in an anonymous closure.
+(function (
+  Drupal,
+  drupalSettings,
+  drupalTranslations,
+  console,
+  Proxy,
+  Reflect,
+) {
+  /**
+   * Helper to rethrow errors asynchronously.
+   *
+   * This way Errors bubbles up outside of the original callstack, making it
+   * easier to debug errors in the browser.
+   *
+   * @param {Error|string} error
+   *   The error to be thrown.
+   */
   Drupal.throwError = function (error) {
     setTimeout(() => {
       throw error;
     }, 0);
   };
 
+  /**
+   * Custom error thrown after attach/detach if one or more behaviors failed.
+   * Initializes the JavaScript behaviors for page loads and Ajax requests.
+   *
+   * @callback Drupal~behaviorAttach
+   *
+   * @param {HTMLDocument|HTMLElement} context
+   *   An element to detach behaviors from.
+   * @param {?object} settings
+   *   An object containing settings for the current context. It is rarely used.
+   *
+   * @see Drupal.attachBehaviors
+   */
+
+  /**
+   * Reverts and cleans up JavaScript behavior initialization.
+   *
+   * @callback Drupal~behaviorDetach
+   *
+   * @param {HTMLDocument|HTMLElement} context
+   *   An element to attach behaviors to.
+   * @param {object} settings
+   *   An object containing settings for the current context.
+   * @param {string} trigger
+   *   One of `'unload'`, `'move'`, or `'serialize'`.
+   *
+   * @see Drupal.detachBehaviors
+   */
+
+  /**
+   * @typedef {object} Drupal~behavior
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Function run on page load and after an Ajax call.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Function run when content is serialized or removed from the page.
+   */
+
+  /**
+   * Holds all initialization methods.
+   *
+   * @namespace Drupal.behaviors
+   *
+   * @type {Object.<string, Drupal~behavior>}
+   */
+
+  /**
+   * Defines a behavior to be run during attach and detach phases.
+   *
+   * Attaches all registered behaviors to a page element.
+   *
+   * Behaviors are event-triggered actions that attach to page elements,
+   * enhancing default non-JavaScript UIs. Behaviors are registered in the
+   * {@link Drupal.behaviors} object using the method 'attach' and optionally
+   * also 'detach'.
+   *
+   * {@link Drupal.attachBehaviors} is added below to the `jQuery.ready` event
+   * and therefore runs on initial page load. Developers implementing Ajax in
+   * their solutions should also call this function after new page content has
+   * been loaded, feeding in an element to be processed, in order to attach all
+   * behaviors to the new content.
+   *
+   * Behaviors should use `var elements =
+   * once('behavior-name', selector, context);` to ensure the behavior is
+   * attached only once to a given element. (Doing so enables the reprocessing
+   * of given elements, which may be needed on occasion despite the ability to
+   * limit behavior attachment to a particular element.)
+   *
+   * @example
+   * Drupal.behaviors.behaviorName = {
+   *   attach: function (context, settings) {
+   *     // ...
+   *   },
+   *   detach: function (context, settings, trigger) {
+   *     // ...
+   *   }
+   * };
+   *
+   * @param {HTMLDocument|HTMLElement} [context=document]
+   *   An element to attach behaviors to.
+   * @param {object} [settings=drupalSettings]
+   *   An object containing settings for the current context. If none is given,
+   *   the global {@link drupalSettings} object is used.
+   *
+   * @see Drupal~behaviorAttach
+   * @see Drupal.detachBehaviors
+   *
+   * @throws {Drupal~DrupalBehaviorError}
+   */
   Drupal.attachBehaviors = function (context, settings) {
     context = context || document;
     settings = settings || drupalSettings;
     const behaviors = Drupal.behaviors;
-    Object.keys(behaviors || {}).forEach(i => {
+    // Execute all of them.
+    Object.keys(behaviors || {}).forEach((i) => {
       if (typeof behaviors[i].attach === 'function') {
+        // Don't stop the execution of behaviors in case of an error.
         try {
           behaviors[i].attach(context, settings);
         } catch (e) {
@@ -32,13 +171,56 @@ window.Drupal = {
     });
   };
 
+  /**
+   * Detaches registered behaviors from a page element.
+   *
+   * Developers implementing Ajax in their solutions should call this function
+   * before page content is about to be removed, feeding in an element to be
+   * processed, in order to allow special behaviors to detach from the content.
+   *
+   * Such implementations should use `once.filter()` and `once.remove()` to find
+   * elements with their corresponding `Drupal.behaviors.behaviorName.attach`
+   * implementation, i.e. `once.remove('behaviorName', selector, context)`,
+   * to ensure the behavior is detached only from previously processed elements.
+   *
+   * @param {HTMLDocument|HTMLElement} [context=document]
+   *   An element to detach behaviors from.
+   * @param {object} [settings=drupalSettings]
+   *   An object containing settings for the current context. If none given,
+   *   the global {@link drupalSettings} object is used.
+   * @param {string} [trigger='unload']
+   *   A string containing what's causing the behaviors to be detached. The
+   *   possible triggers are:
+   *   - `'unload'`: The context element is being removed from the DOM.
+   *   - `'move'`: The element is about to be moved within the DOM (for example,
+   *     during a tabledrag row swap). After the move is completed,
+   *     {@link Drupal.attachBehaviors} is called, so that the behavior can undo
+   *     whatever it did in response to the move. Many behaviors won't need to
+   *     do anything simply in response to the element being moved, but because
+   *     IFRAME elements reload their "src" when being moved within the DOM,
+   *     behaviors bound to IFRAME elements (like WYSIWYG editors) may need to
+   *     take some action.
+   *   - `'serialize'`: When an Ajax form is submitted, this is called with the
+   *     form as the context. This provides every behavior within the form an
+   *     opportunity to ensure that the field elements have correct content
+   *     in them before the form is serialized. The canonical use-case is so
+   *     that WYSIWYG editors can update the hidden textarea to which they are
+   *     bound.
+   *
+   * @throws {Drupal~DrupalBehaviorError}
+   *
+   * @see Drupal~behaviorDetach
+   * @see Drupal.attachBehaviors
+   */
   Drupal.detachBehaviors = function (context, settings, trigger) {
     context = context || document;
     settings = settings || drupalSettings;
     trigger = trigger || 'unload';
     const behaviors = Drupal.behaviors;
-    Object.keys(behaviors || {}).forEach(i => {
+    // Execute all of them.
+    Object.keys(behaviors || {}).forEach((i) => {
       if (typeof behaviors[i].detach === 'function') {
+        // Don't stop the execution of behaviors in case of an error.
         try {
           behaviors[i].detach(context, settings, trigger);
         } catch (e) {
@@ -48,38 +230,100 @@ window.Drupal = {
     });
   };
 
+  /**
+   * Encodes special characters in a plain-text string for display as HTML.
+   *
+   * @param {string} str
+   *   The string to be encoded.
+   *
+   * @return {string}
+   *   The encoded string.
+   *
+   * @ingroup sanitization
+   */
   Drupal.checkPlain = function (str) {
-    str = str.toString().replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
+    str = str
+      .toString()
+      .replace(/&/g, '&amp;')
+      .replace(/</g, '&lt;')
+      .replace(/>/g, '&gt;')
+      .replace(/"/g, '&quot;')
+      .replace(/'/g, '&#39;');
     return str;
   };
 
+  /**
+   * Replaces placeholders with sanitized values in a string.
+   *
+   * @param {string} str
+   *   A string with placeholders.
+   * @param {object} args
+   *   An object of replacements pairs to make. Incidences of any key in this
+   *   array are replaced with the corresponding value. Based on the first
+   *   character of the key, the value is escaped and/or themed:
+   *    - `'!variable'`: inserted as is.
+   *    - `'@variable'`: escape plain text to HTML ({@link Drupal.checkPlain}).
+   *    - `'%variable'`: escape text and theme as a placeholder for user-
+   *      submitted content ({@link Drupal.checkPlain} +
+   *      `{@link Drupal.theme}('placeholder')`).
+   *
+   * @return {string}
+   *   The formatted string.
+   *
+   * @see Drupal.t
+   */
   Drupal.formatString = function (str, args) {
+    // Keep args intact.
     const processedArgs = {};
-    Object.keys(args || {}).forEach(key => {
+    // Transform arguments before inserting them.
+    Object.keys(args || {}).forEach((key) => {
       switch (key.charAt(0)) {
+        // Escaped only.
         case '@':
           processedArgs[key] = Drupal.checkPlain(args[key]);
           break;
 
+        // Pass-through.
         case '!':
           processedArgs[key] = args[key];
           break;
 
+        // Escaped and placeholder.
         default:
           processedArgs[key] = Drupal.theme('placeholder', args[key]);
           break;
       }
     });
+
     return Drupal.stringReplace(str, processedArgs, null);
   };
 
+  /**
+   * Replaces substring.
+   *
+   * The longest keys will be tried first. Once a substring has been replaced,
+   * its new value will not be searched again.
+   *
+   * @param {string} str
+   *   A string with placeholders.
+   * @param {object} args
+   *   Key-value pairs.
+   * @param {Array|null} keys
+   *   Array of keys from `args`. Internal use only.
+   *
+   * @return {string}
+   *   The replaced string.
+   */
   Drupal.stringReplace = function (str, args, keys) {
     if (str.length === 0) {
       return str;
     }
 
+    // If the array of keys is not passed then collect the keys from the args.
     if (!Array.isArray(keys)) {
       keys = Object.keys(args || {});
+
+      // Order the keys by the character length. The shortest one is the first.
       keys.sort((a, b) => a.length - b.length);
     }
 
@@ -87,11 +331,13 @@ window.Drupal = {
       return str;
     }
 
+    // Take next longest one from the end.
     const key = keys.pop();
     const fragments = str.split(key);
 
     if (keys.length) {
       for (let i = 0; i < fragments.length; i++) {
+        // Process each fragment with a copy of remaining keys.
         fragments[i] = Drupal.stringReplace(fragments[i], args, keys.slice(0));
       }
     }
@@ -99,68 +345,187 @@ window.Drupal = {
     return fragments.join(args[key]);
   };
 
+  /**
+   * Translates strings to the page language, or a given language.
+   *
+   * See the documentation of the server-side t() function for further details.
+   *
+   * @param {string} str
+   *   A string containing the English text to translate.
+   * @param {Object.<string, string>} [args]
+   *   An object of replacements pairs to make after translation. Incidences
+   *   of any key in this array are replaced with the corresponding value.
+   *   See {@link Drupal.formatString}.
+   * @param {object} [options]
+   *   Additional options for translation.
+   * @param {string} [options.context='']
+   *   The context the source string belongs to.
+   *
+   * @return {string}
+   *   The formatted string.
+   *   The translated string.
+   */
   Drupal.t = function (str, args, options) {
     options = options || {};
     options.context = options.context || '';
 
-    if (typeof drupalTranslations !== 'undefined' && drupalTranslations.strings && drupalTranslations.strings[options.context] && drupalTranslations.strings[options.context][str]) {
+    // Fetch the localized version of the string.
+    if (
+      typeof drupalTranslations !== 'undefined' &&
+      drupalTranslations.strings &&
+      drupalTranslations.strings[options.context] &&
+      drupalTranslations.strings[options.context][str]
+    ) {
       str = drupalTranslations.strings[options.context][str];
     }
 
     if (args) {
       str = Drupal.formatString(str, args);
     }
-
     return str;
   };
 
+  /**
+   * Returns the URL to a Drupal page.
+   *
+   * @param {string} path
+   *   Drupal path to transform to URL.
+   *
+   * @return {string}
+   *   The full URL.
+   */
   Drupal.url = function (path) {
     return drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix + path;
   };
 
+  /**
+   * Returns the passed in URL as an absolute URL.
+   *
+   * @param {string} url
+   *   The URL string to be normalized to an absolute URL.
+   *
+   * @return {string}
+   *   The normalized, absolute URL.
+   *
+   * @see https://github.com/angular/angular.js/blob/v1.4.4/src/ng/urlUtils.js
+   * @see https://grack.com/blog/2009/11/17/absolutizing-url-in-javascript
+   * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L53
+   */
   Drupal.url.toAbsolute = function (url) {
     const urlParsingNode = document.createElement('a');
 
+    // Decode the URL first; this is required by IE <= 6. Decoding non-UTF-8
+    // strings may throw an exception.
     try {
       url = decodeURIComponent(url);
-    } catch (e) {}
+    } catch (e) {
+      // Empty.
+    }
 
     urlParsingNode.setAttribute('href', url);
+
+    // IE <= 7 normalizes the URL when assigned to the anchor node similar to
+    // the other browsers.
     return urlParsingNode.cloneNode(false).href;
   };
 
+  /**
+   * Returns true if the URL is within Drupal's base path.
+   *
+   * @param {string} url
+   *   The URL string to be tested.
+   *
+   * @return {bool}
+   *   `true` if local.
+   *
+   * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L58
+   */
   Drupal.url.isLocal = function (url) {
+    // Always use browser-derived absolute URLs in the comparison, to avoid
+    // attempts to break out of the base path using directory traversal.
     let absoluteUrl = Drupal.url.toAbsolute(url);
-    let {
-      protocol
-    } = window.location;
+    let { protocol } = window.location;
 
+    // Consider URLs that match this site's base URL but use HTTPS instead of HTTP
+    // as local as well.
     if (protocol === 'http:' && absoluteUrl.indexOf('https:') === 0) {
       protocol = 'https:';
     }
+    let baseUrl = `${protocol}//${
+      window.location.host
+    }${drupalSettings.path.baseUrl.slice(0, -1)}`;
 
-    let baseUrl = `${protocol}//${window.location.host}${drupalSettings.path.baseUrl.slice(0, -1)}`;
-
+    // Decoding non-UTF-8 strings may throw an exception.
     try {
       absoluteUrl = decodeURIComponent(absoluteUrl);
-    } catch (e) {}
-
+    } catch (e) {
+      // Empty.
+    }
     try {
       baseUrl = decodeURIComponent(baseUrl);
-    } catch (e) {}
+    } catch (e) {
+      // Empty.
+    }
 
+    // The given URL matches the site's base URL, or has a path under the site's
+    // base URL.
     return absoluteUrl === baseUrl || absoluteUrl.indexOf(`${baseUrl}/`) === 0;
   };
 
+  /**
+   * Formats a string containing a count of items.
+   *
+   * This function ensures that the string is pluralized correctly. Since
+   * {@link Drupal.t} is called by this function, make sure not to pass
+   * already-localized strings to it.
+   *
+   * See the documentation of the server-side
+   * \Drupal\Core\StringTranslation\TranslationInterface::formatPlural()
+   * function for more details.
+   *
+   * @param {number} count
+   *   The item count to display.
+   * @param {string} singular
+   *   The string for the singular case. Please make sure it is clear this is
+   *   singular, to ease translation (e.g. use "1 new comment" instead of "1
+   *   new"). Do not use @count in the singular string.
+   * @param {string} plural
+   *   The string for the plural case. Please make sure it is clear this is
+   *   plural, to ease translation. Use @count in place of the item count, as in
+   *   "@count new comments".
+   * @param {object} [args]
+   *   An object of replacements pairs to make after translation. Incidences
+   *   of any key in this array are replaced with the corresponding value.
+   *   See {@link Drupal.formatString}.
+   *   Note that you do not need to include @count in this array.
+   *   This replacement is done automatically for the plural case.
+   * @param {object} [options]
+   *   The options to pass to the {@link Drupal.t} function.
+   *
+   * @return {string}
+   *   A translated string.
+   */
   Drupal.formatPlural = function (count, singular, plural, args, options) {
     args = args || {};
     args['@count'] = count;
+
     const pluralDelimiter = drupalSettings.pluralDelimiter;
-    const translations = Drupal.t(singular + pluralDelimiter + plural, args, options).split(pluralDelimiter);
+    const translations = Drupal.t(
+      singular + pluralDelimiter + plural,
+      args,
+      options,
+    ).split(pluralDelimiter);
     let index = 0;
 
-    if (typeof drupalTranslations !== 'undefined' && drupalTranslations.pluralFormula) {
-      index = count in drupalTranslations.pluralFormula ? drupalTranslations.pluralFormula[count] : drupalTranslations.pluralFormula.default;
+    // Determine the index of the plural form.
+    if (
+      typeof drupalTranslations !== 'undefined' &&
+      drupalTranslations.pluralFormula
+    ) {
+      index =
+        count in drupalTranslations.pluralFormula
+          ? drupalTranslations.pluralFormula[count]
+          : drupalTranslations.pluralFormula.default;
     } else if (args['@count'] !== 1) {
       index = 1;
     }
@@ -168,59 +533,123 @@ window.Drupal = {
     return translations[index];
   };
 
+  /**
+   * Encodes a Drupal path for use in a URL.
+   *
+   * For aesthetic reasons slashes are not escaped.
+   *
+   * @param {string} item
+   *   Unencoded path.
+   *
+   * @return {string}
+   *   The encoded path.
+   */
   Drupal.encodePath = function (item) {
     return window.encodeURIComponent(item).replace(/%2F/g, '/');
   };
 
-  Drupal.deprecationError = _ref => {
-    let {
-      message
-    } = _ref;
-
-    if (drupalSettings.suppressDeprecationErrors === false && typeof console !== 'undefined' && console.warn) {
+  /**
+   * Triggers deprecation error.
+   *
+   * Deprecation errors are only triggered if deprecation errors haven't
+   * been suppressed.
+   *
+   * @param {Object} deprecation
+   *   The deprecation options.
+   * @param {string} deprecation.message
+   *   The deprecation message.
+   *
+   * @see https://www.drupal.org/core/deprecation#javascript
+   */
+  Drupal.deprecationError = ({ message }) => {
+    if (
+      drupalSettings.suppressDeprecationErrors === false &&
+      typeof console !== 'undefined' &&
+      console.warn
+    ) {
       console.warn(`[Deprecation] ${message}`);
     }
   };
 
-  Drupal.deprecatedProperty = _ref2 => {
-    let {
-      target,
-      deprecatedProperty,
-      message
-    } = _ref2;
-
+  /**
+   * Triggers deprecation error when object property is being used.
+   *
+   * @param {Object} deprecation
+   *   The deprecation options.
+   * @param {Object} deprecation.target
+   *   The targeted object.
+   * @param {string} deprecation.deprecatedProperty
+   *   A key of the deprecated property.
+   * @param {string} deprecation.message
+   *   The deprecation message.
+   * @returns {Object}
+   *
+   * @see https://www.drupal.org/core/deprecation#javascript
+   */
+  Drupal.deprecatedProperty = ({ target, deprecatedProperty, message }) => {
+    // Proxy and Reflect are not supported by all browsers. Unsupported browsers
+    // are ignored since this is a development feature.
     if (!Proxy || !Reflect) {
       return target;
     }
 
     return new Proxy(target, {
-      get: function (target, key) {
+      get: (target, key, ...rest) => {
         if (key === deprecatedProperty) {
-          Drupal.deprecationError({
-            message
-          });
+          Drupal.deprecationError({ message });
         }
-
-        for (var _len = arguments.length, rest = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
-          rest[_key - 2] = arguments[_key];
-        }
-
         return Reflect.get(target, key, ...rest);
-      }
+      },
     });
   };
 
-  Drupal.theme = function (func) {
+  /**
+   * Generates the themed representation of a Drupal object.
+   *
+   * All requests for themed output must go through this function. It examines
+   * the request and routes it to the appropriate theme function. If the current
+   * theme does not provide an override function, the generic theme function is
+   * called.
+   *
+   * @example
+   * <caption>To retrieve the HTML for text that should be emphasized and
+   * displayed as a placeholder inside a sentence.</caption>
+   * Drupal.theme('placeholder', text);
+   *
+   * @namespace
+   *
+   * @param {function} func
+   *   The name of the theme function to call.
+   * @param {...args}
+   *   Additional arguments to pass along to the theme function.
+   *
+   * @return {string|object|HTMLElement|jQuery}
+   *   Any data the theme function returns. This could be a plain HTML string,
+   *   but also a complex object.
+   */
+  Drupal.theme = function (func, ...args) {
     if (func in Drupal.theme) {
-      for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
-        args[_key2 - 1] = arguments[_key2];
-      }
-
       return Drupal.theme[func](...args);
     }
   };
 
+  /**
+   * Formats text for emphasized display in a placeholder inside a sentence.
+   *
+   * @param {string} str
+   *   The text to format (plain-text).
+   *
+   * @return {string}
+   *   The formatted text (html).
+   */
   Drupal.theme.placeholder = function (str) {
     return `<em class="placeholder">${Drupal.checkPlain(str)}</em>`;
   };
-})(Drupal, window.drupalSettings, window.drupalTranslations, window.console, window.Proxy, window.Reflect);
\ No newline at end of file
+})(
+  Drupal,
+  window.drupalSettings,
+  window.drupalTranslations,
+  window.console,
+  window.Proxy,
+  window.Reflect,
+);
diff --git a/core/misc/drupalSettingsLoader.es6.js b/core/misc/drupalSettingsLoader.es6.js
deleted file mode 100644
index 6cc4be9f41e0..000000000000
--- a/core/misc/drupalSettingsLoader.es6.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * @file
- * Parse inline JSON and initialize the drupalSettings global object.
- */
-
-(function () {
-  // Use direct child elements to harden against XSS exploits when CSP is on.
-  const settingsElement = document.querySelector(
-    'head > script[type="application/json"][data-drupal-selector="drupal-settings-json"], body > script[type="application/json"][data-drupal-selector="drupal-settings-json"]',
-  );
-
-  /**
-   * Variable generated by Drupal with all the configuration created from PHP.
-   *
-   * @global
-   *
-   * @type {object}
-   */
-  window.drupalSettings = {};
-
-  if (settingsElement !== null) {
-    window.drupalSettings = JSON.parse(settingsElement.textContent);
-  }
-})();
diff --git a/core/misc/drupalSettingsLoader.js b/core/misc/drupalSettingsLoader.js
index 73cf91dae1ea..6cc4be9f41e0 100644
--- a/core/misc/drupalSettingsLoader.js
+++ b/core/misc/drupalSettingsLoader.js
@@ -1,15 +1,24 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Parse inline JSON and initialize the drupalSettings global object.
+ */
 
 (function () {
-  const settingsElement = document.querySelector('head > script[type="application/json"][data-drupal-selector="drupal-settings-json"], body > script[type="application/json"][data-drupal-selector="drupal-settings-json"]');
+  // Use direct child elements to harden against XSS exploits when CSP is on.
+  const settingsElement = document.querySelector(
+    'head > script[type="application/json"][data-drupal-selector="drupal-settings-json"], body > script[type="application/json"][data-drupal-selector="drupal-settings-json"]',
+  );
+
+  /**
+   * Variable generated by Drupal with all the configuration created from PHP.
+   *
+   * @global
+   *
+   * @type {object}
+   */
   window.drupalSettings = {};
 
   if (settingsElement !== null) {
     window.drupalSettings = JSON.parse(settingsElement.textContent);
   }
-})();
\ No newline at end of file
+})();
diff --git a/core/misc/entity-form.es6.js b/core/misc/entity-form.es6.js
deleted file mode 100644
index 58a7c9ce1d18..000000000000
--- a/core/misc/entity-form.es6.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * @file
- * Defines JavaScript behaviors for the block_content module.
- */
-
-(function ($, Drupal) {
-  /**
-   * Sets summaries about revision and translation of entities.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches summary behavior entity form tabs.
-   *
-   *   Specifically, it updates summaries to the revision information and the
-   *   translation options.
-   */
-  Drupal.behaviors.entityContentDetailsSummaries = {
-    attach(context) {
-      const $context = $(context);
-      $context
-        .find('.entity-content-form-revision-information')
-        .drupalSetSummary((context) => {
-          const $revisionContext = $(context);
-          const revisionCheckbox = $revisionContext.find(
-            '.js-form-item-revision input',
-          );
-
-          // Return 'New revision' if the 'Create new revision' checkbox is checked,
-          // or if the checkbox doesn't exist, but the revision log does. For users
-          // without the "Administer content" permission the checkbox won't appear,
-          // but the revision log will if the content type is set to auto-revision.
-          if (
-            revisionCheckbox.is(':checked') ||
-            (!revisionCheckbox.length &&
-              $revisionContext.find('.js-form-item-revision-log textarea')
-                .length)
-          ) {
-            return Drupal.t('New revision');
-          }
-
-          return Drupal.t('No revision');
-        });
-
-      $context
-        .find('details.entity-translation-options')
-        .drupalSetSummary((context) => {
-          const $translationContext = $(context);
-          let translate;
-          let $checkbox = $translationContext.find(
-            '.js-form-item-translation-translate input',
-          );
-
-          if ($checkbox.length) {
-            translate = $checkbox.is(':checked')
-              ? Drupal.t('Needs to be updated')
-              : Drupal.t('Does not need to be updated');
-          } else {
-            $checkbox = $translationContext.find(
-              '.js-form-item-translation-retranslate input',
-            );
-            translate = $checkbox.is(':checked')
-              ? Drupal.t('Flag other translations as outdated')
-              : Drupal.t('Do not flag other translations as outdated');
-          }
-
-          return translate;
-        });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/misc/entity-form.js b/core/misc/entity-form.js
index 22c92201a0a1..58a7c9ce1d18 100644
--- a/core/misc/entity-form.js
+++ b/core/misc/entity-form.js
@@ -1,39 +1,71 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Defines JavaScript behaviors for the block_content module.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Sets summaries about revision and translation of entities.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches summary behavior entity form tabs.
+   *
+   *   Specifically, it updates summaries to the revision information and the
+   *   translation options.
+   */
   Drupal.behaviors.entityContentDetailsSummaries = {
     attach(context) {
       const $context = $(context);
-      $context.find('.entity-content-form-revision-information').drupalSetSummary(context => {
-        const $revisionContext = $(context);
-        const revisionCheckbox = $revisionContext.find('.js-form-item-revision input');
+      $context
+        .find('.entity-content-form-revision-information')
+        .drupalSetSummary((context) => {
+          const $revisionContext = $(context);
+          const revisionCheckbox = $revisionContext.find(
+            '.js-form-item-revision input',
+          );
 
-        if (revisionCheckbox.is(':checked') || !revisionCheckbox.length && $revisionContext.find('.js-form-item-revision-log textarea').length) {
-          return Drupal.t('New revision');
-        }
+          // Return 'New revision' if the 'Create new revision' checkbox is checked,
+          // or if the checkbox doesn't exist, but the revision log does. For users
+          // without the "Administer content" permission the checkbox won't appear,
+          // but the revision log will if the content type is set to auto-revision.
+          if (
+            revisionCheckbox.is(':checked') ||
+            (!revisionCheckbox.length &&
+              $revisionContext.find('.js-form-item-revision-log textarea')
+                .length)
+          ) {
+            return Drupal.t('New revision');
+          }
 
-        return Drupal.t('No revision');
-      });
-      $context.find('details.entity-translation-options').drupalSetSummary(context => {
-        const $translationContext = $(context);
-        let translate;
-        let $checkbox = $translationContext.find('.js-form-item-translation-translate input');
+          return Drupal.t('No revision');
+        });
 
-        if ($checkbox.length) {
-          translate = $checkbox.is(':checked') ? Drupal.t('Needs to be updated') : Drupal.t('Does not need to be updated');
-        } else {
-          $checkbox = $translationContext.find('.js-form-item-translation-retranslate input');
-          translate = $checkbox.is(':checked') ? Drupal.t('Flag other translations as outdated') : Drupal.t('Do not flag other translations as outdated');
-        }
+      $context
+        .find('details.entity-translation-options')
+        .drupalSetSummary((context) => {
+          const $translationContext = $(context);
+          let translate;
+          let $checkbox = $translationContext.find(
+            '.js-form-item-translation-translate input',
+          );
 
-        return translate;
-      });
-    }
+          if ($checkbox.length) {
+            translate = $checkbox.is(':checked')
+              ? Drupal.t('Needs to be updated')
+              : Drupal.t('Does not need to be updated');
+          } else {
+            $checkbox = $translationContext.find(
+              '.js-form-item-translation-retranslate input',
+            );
+            translate = $checkbox.is(':checked')
+              ? Drupal.t('Flag other translations as outdated')
+              : Drupal.t('Do not flag other translations as outdated');
+          }
 
+          return translate;
+        });
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/misc/form.es6.js b/core/misc/form.es6.js
deleted file mode 100644
index c02220c09973..000000000000
--- a/core/misc/form.es6.js
+++ /dev/null
@@ -1,325 +0,0 @@
-/**
- * @file
- * Form features.
- */
-
-/**
- * Triggers when a value in the form changed.
- *
- * The event triggers when content is typed or pasted in a text field, before
- * the change event triggers.
- *
- * @event formUpdated
- */
-
-/**
- * Triggers when a click on a page fragment link or hash change is detected.
- *
- * The event triggers when the fragment in the URL changes (a hash change) and
- * when a link containing a fragment identifier is clicked. In case the hash
- * changes due to a click this event will only be triggered once.
- *
- * @event formFragmentLinkClickOrHashChange
- */
-
-(function ($, Drupal, debounce) {
-  /**
-   * Retrieves the summary for the first element.
-   *
-   * @return {string}
-   *   The text of the summary.
-   */
-  $.fn.drupalGetSummary = function () {
-    const callback = this.data('summaryCallback');
-    return this[0] && callback ? callback(this[0]).trim() : '';
-  };
-
-  /**
-   * Sets the summary for all matched elements.
-   *
-   * @param {function} callback
-   *   Either a function that will be called each time the summary is
-   *   retrieved or a string (which is returned each time).
-   *
-   * @return {jQuery}
-   *   jQuery collection of the current element.
-   *
-   * @fires event:summaryUpdated
-   *
-   * @listens event:formUpdated
-   */
-  $.fn.drupalSetSummary = function (callback) {
-    const self = this;
-
-    // To facilitate things, the callback should always be a function. If it's
-    // not, we wrap it into an anonymous function which just returns the value.
-    if (typeof callback !== 'function') {
-      const val = callback;
-      callback = function () {
-        return val;
-      };
-    }
-
-    return (
-      this.data('summaryCallback', callback)
-        // To prevent duplicate events, the handlers are first removed and then
-        // (re-)added.
-        .off('formUpdated.summary')
-        .on('formUpdated.summary', () => {
-          self.trigger('summaryUpdated');
-        })
-        // The actual summaryUpdated handler doesn't fire when the callback is
-        // changed, so we have to do this manually.
-        .trigger('summaryUpdated')
-    );
-  };
-
-  /**
-   * Prevents consecutive form submissions of identical form values.
-   *
-   * Repetitive form submissions that would submit the identical form values
-   * are prevented, unless the form values are different to the previously
-   * submitted values.
-   *
-   * This is a simplified re-implementation of a user-agent behavior that
-   * should be natively supported by major web browsers, but at this time, only
-   * Firefox has a built-in protection.
-   *
-   * A form value-based approach ensures that the constraint is triggered for
-   * consecutive, identical form submissions only. Compared to that, a form
-   * button-based approach would (1) rely on [visible] buttons to exist where
-   * technically not required and (2) require more complex state management if
-   * there are multiple buttons in a form.
-   *
-   * This implementation is based on form-level submit events only and relies
-   * on jQuery's serialize() method to determine submitted form values. As such,
-   * the following limitations exist:
-   *
-   * - Event handlers on form buttons that preventDefault() do not receive a
-   *   double-submit protection. That is deemed to be fine, since such button
-   *   events typically trigger reversible client-side or server-side
-   *   operations that are local to the context of a form only.
-   * - Changed values in advanced form controls, such as file inputs, are not
-   *   part of the form values being compared between consecutive form submits
-   *   (due to limitations of jQuery.serialize()). That is deemed to be
-   *   acceptable, because if the user forgot to attach a file, then the size of
-   *   HTTP payload will most likely be small enough to be fully passed to the
-   *   server endpoint within (milli)seconds. If a user mistakenly attached a
-   *   wrong file and is technically versed enough to cancel the form submission
-   *   (and HTTP payload) in order to attach a different file, then that
-   *   edge-case is not supported here.
-   *
-   * Lastly, all forms submitted via HTTP GET are idempotent by definition of
-   * HTTP standards, so excluded in this implementation.
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.formSingleSubmit = {
-    attach() {
-      function onFormSubmit(e) {
-        const $form = $(e.currentTarget);
-        const formValues = $form.serialize();
-        const previousValues = $form.attr('data-drupal-form-submit-last');
-        if (previousValues === formValues) {
-          e.preventDefault();
-        } else {
-          $form.attr('data-drupal-form-submit-last', formValues);
-        }
-      }
-
-      $(once('form-single-submit', 'body')).on(
-        'submit.singleSubmit',
-        'form:not([method~="GET"])',
-        onFormSubmit,
-      );
-    },
-  };
-
-  /**
-   * Sends a 'formUpdated' event each time a form element is modified.
-   *
-   * @param {HTMLElement} element
-   *   The element to trigger a form updated event on.
-   *
-   * @fires event:formUpdated
-   */
-  function triggerFormUpdated(element) {
-    $(element).trigger('formUpdated');
-  }
-
-  /**
-   * Collects the IDs of all form fields in the given form.
-   *
-   * @param {HTMLFormElement} form
-   *   The form element to search.
-   *
-   * @return {Array}
-   *   Array of IDs for form fields.
-   */
-  function fieldsList(form) {
-    // We use id to avoid name duplicates on radio fields and filter out
-    // elements with a name but no id.
-    return [].map.call(form.querySelectorAll('[name][id]'), (el) => el.id);
-  }
-
-  /**
-   * Triggers the 'formUpdated' event on form elements when they are modified.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches formUpdated behaviors.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detaches formUpdated behaviors.
-   *
-   * @fires event:formUpdated
-   */
-  Drupal.behaviors.formUpdated = {
-    attach(context) {
-      const $context = $(context);
-      const contextIsForm = $context.is('form');
-      const $forms = $(
-        once('form-updated', contextIsForm ? $context : $context.find('form')),
-      );
-      let formFields;
-
-      if ($forms.length) {
-        // Initialize form behaviors, use $.makeArray to be able to use native
-        // forEach array method and have the callback parameters in the right
-        // order.
-        $.makeArray($forms).forEach((form) => {
-          const events = 'change.formUpdated input.formUpdated ';
-          const eventHandler = debounce((event) => {
-            triggerFormUpdated(event.target);
-          }, 300);
-          formFields = fieldsList(form).join(',');
-
-          form.setAttribute('data-drupal-form-fields', formFields);
-          $(form).on(events, eventHandler);
-        });
-      }
-      // On ajax requests context is the form element.
-      if (contextIsForm) {
-        formFields = fieldsList(context).join(',');
-        // @todo replace with form.getAttribute() when #1979468 is in.
-        const currentFields = $(context).attr('data-drupal-form-fields');
-        // If there has been a change in the fields or their order, trigger
-        // formUpdated.
-        if (formFields !== currentFields) {
-          triggerFormUpdated(context);
-        }
-      }
-    },
-    detach(context, settings, trigger) {
-      const $context = $(context);
-      const contextIsForm = $context.is('form');
-      if (trigger === 'unload') {
-        once
-          .remove(
-            'form-updated',
-            contextIsForm ? $context : $context.find('form'),
-          )
-          .forEach((form) => {
-            form.removeAttribute('data-drupal-form-fields');
-            $(form).off('.formUpdated');
-          });
-      }
-    },
-  };
-
-  /**
-   * Prepopulate form fields with information from the visitor browser.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the behavior for filling user info from browser.
-   */
-  Drupal.behaviors.fillUserInfoFromBrowser = {
-    attach(context, settings) {
-      const userInfo = ['name', 'mail', 'homepage'];
-      const $forms = $(
-        once('user-info-from-browser', '[data-user-info-from-browser]'),
-      );
-      if ($forms.length) {
-        userInfo.forEach((info) => {
-          const $element = $forms.find(`[name=${info}]`);
-          const browserData = localStorage.getItem(`Drupal.visitor.${info}`);
-          if (!$element.length) {
-            return;
-          }
-          const emptyValue = $element[0].value === '';
-          const defaultValue =
-            $element.attr('data-drupal-default-value') === $element[0].value;
-          if (browserData && (emptyValue || defaultValue)) {
-            $element.each(function (index, item) {
-              item.value = browserData;
-            });
-          }
-        });
-      }
-      $forms.on('submit', () => {
-        userInfo.forEach((info) => {
-          const $element = $forms.find(`[name=${info}]`);
-          if ($element.length) {
-            localStorage.setItem(`Drupal.visitor.${info}`, $element[0].value);
-          }
-        });
-      });
-    },
-  };
-
-  /**
-   * Sends a fragment interaction event on a hash change or fragment link click.
-   *
-   * @param {jQuery.Event} e
-   *   The event triggered.
-   *
-   * @fires event:formFragmentLinkClickOrHashChange
-   */
-  const handleFragmentLinkClickOrHashChange = (e) => {
-    let url;
-    if (e.type === 'click') {
-      url = e.currentTarget.location
-        ? e.currentTarget.location
-        : e.currentTarget;
-    } else {
-      url = window.location;
-    }
-    const hash = url.hash.substr(1);
-    if (hash) {
-      const $target = $(`#${hash}`);
-      $('body').trigger('formFragmentLinkClickOrHashChange', [$target]);
-
-      /**
-       * Clicking a fragment link or a hash change should focus the target
-       * element, but event timing issues in multiple browsers require a timeout.
-       */
-      setTimeout(() => $target.trigger('focus'), 300);
-    }
-  };
-
-  const debouncedHandleFragmentLinkClickOrHashChange = debounce(
-    handleFragmentLinkClickOrHashChange,
-    300,
-    true,
-  );
-
-  // Binds a listener to handle URL fragment changes.
-  $(window).on(
-    'hashchange.form-fragment',
-    debouncedHandleFragmentLinkClickOrHashChange,
-  );
-
-  /**
-   * Binds a listener to handle clicks on fragment links and absolute URL links
-   * containing a fragment, this is needed next to the hash change listener
-   * because clicking such links doesn't trigger a hash change when the fragment
-   * is already in the URL.
-   */
-  $(document).on(
-    'click.form-fragment',
-    'a[href*="#"]',
-    debouncedHandleFragmentLinkClickOrHashChange,
-  );
-})(jQuery, Drupal, Drupal.debounce);
diff --git a/core/misc/form.js b/core/misc/form.js
index ea5f8f50e600..c02220c09973 100644
--- a/core/misc/form.js
+++ b/core/misc/form.js
@@ -1,39 +1,125 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Form features.
+ */
+
+/**
+ * Triggers when a value in the form changed.
+ *
+ * The event triggers when content is typed or pasted in a text field, before
+ * the change event triggers.
+ *
+ * @event formUpdated
+ */
+
+/**
+ * Triggers when a click on a page fragment link or hash change is detected.
+ *
+ * The event triggers when the fragment in the URL changes (a hash change) and
+ * when a link containing a fragment identifier is clicked. In case the hash
+ * changes due to a click this event will only be triggered once.
+ *
+ * @event formFragmentLinkClickOrHashChange
+ */
 
 (function ($, Drupal, debounce) {
+  /**
+   * Retrieves the summary for the first element.
+   *
+   * @return {string}
+   *   The text of the summary.
+   */
   $.fn.drupalGetSummary = function () {
     const callback = this.data('summaryCallback');
     return this[0] && callback ? callback(this[0]).trim() : '';
   };
 
+  /**
+   * Sets the summary for all matched elements.
+   *
+   * @param {function} callback
+   *   Either a function that will be called each time the summary is
+   *   retrieved or a string (which is returned each time).
+   *
+   * @return {jQuery}
+   *   jQuery collection of the current element.
+   *
+   * @fires event:summaryUpdated
+   *
+   * @listens event:formUpdated
+   */
   $.fn.drupalSetSummary = function (callback) {
     const self = this;
 
+    // To facilitate things, the callback should always be a function. If it's
+    // not, we wrap it into an anonymous function which just returns the value.
     if (typeof callback !== 'function') {
       const val = callback;
-
       callback = function () {
         return val;
       };
     }
 
-    return this.data('summaryCallback', callback).off('formUpdated.summary').on('formUpdated.summary', () => {
-      self.trigger('summaryUpdated');
-    }).trigger('summaryUpdated');
+    return (
+      this.data('summaryCallback', callback)
+        // To prevent duplicate events, the handlers are first removed and then
+        // (re-)added.
+        .off('formUpdated.summary')
+        .on('formUpdated.summary', () => {
+          self.trigger('summaryUpdated');
+        })
+        // The actual summaryUpdated handler doesn't fire when the callback is
+        // changed, so we have to do this manually.
+        .trigger('summaryUpdated')
+    );
   };
 
+  /**
+   * Prevents consecutive form submissions of identical form values.
+   *
+   * Repetitive form submissions that would submit the identical form values
+   * are prevented, unless the form values are different to the previously
+   * submitted values.
+   *
+   * This is a simplified re-implementation of a user-agent behavior that
+   * should be natively supported by major web browsers, but at this time, only
+   * Firefox has a built-in protection.
+   *
+   * A form value-based approach ensures that the constraint is triggered for
+   * consecutive, identical form submissions only. Compared to that, a form
+   * button-based approach would (1) rely on [visible] buttons to exist where
+   * technically not required and (2) require more complex state management if
+   * there are multiple buttons in a form.
+   *
+   * This implementation is based on form-level submit events only and relies
+   * on jQuery's serialize() method to determine submitted form values. As such,
+   * the following limitations exist:
+   *
+   * - Event handlers on form buttons that preventDefault() do not receive a
+   *   double-submit protection. That is deemed to be fine, since such button
+   *   events typically trigger reversible client-side or server-side
+   *   operations that are local to the context of a form only.
+   * - Changed values in advanced form controls, such as file inputs, are not
+   *   part of the form values being compared between consecutive form submits
+   *   (due to limitations of jQuery.serialize()). That is deemed to be
+   *   acceptable, because if the user forgot to attach a file, then the size of
+   *   HTTP payload will most likely be small enough to be fully passed to the
+   *   server endpoint within (milli)seconds. If a user mistakenly attached a
+   *   wrong file and is technically versed enough to cancel the form submission
+   *   (and HTTP payload) in order to attach a different file, then that
+   *   edge-case is not supported here.
+   *
+   * Lastly, all forms submitted via HTTP GET are idempotent by definition of
+   * HTTP standards, so excluded in this implementation.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.formSingleSubmit = {
     attach() {
       function onFormSubmit(e) {
         const $form = $(e.currentTarget);
         const formValues = $form.serialize();
         const previousValues = $form.attr('data-drupal-form-submit-last');
-
         if (previousValues === formValues) {
           e.preventDefault();
         } else {
@@ -41,78 +127,130 @@
         }
       }
 
-      $(once('form-single-submit', 'body')).on('submit.singleSubmit', 'form:not([method~="GET"])', onFormSubmit);
-    }
-
+      $(once('form-single-submit', 'body')).on(
+        'submit.singleSubmit',
+        'form:not([method~="GET"])',
+        onFormSubmit,
+      );
+    },
   };
 
+  /**
+   * Sends a 'formUpdated' event each time a form element is modified.
+   *
+   * @param {HTMLElement} element
+   *   The element to trigger a form updated event on.
+   *
+   * @fires event:formUpdated
+   */
   function triggerFormUpdated(element) {
     $(element).trigger('formUpdated');
   }
 
+  /**
+   * Collects the IDs of all form fields in the given form.
+   *
+   * @param {HTMLFormElement} form
+   *   The form element to search.
+   *
+   * @return {Array}
+   *   Array of IDs for form fields.
+   */
   function fieldsList(form) {
-    return [].map.call(form.querySelectorAll('[name][id]'), el => el.id);
+    // We use id to avoid name duplicates on radio fields and filter out
+    // elements with a name but no id.
+    return [].map.call(form.querySelectorAll('[name][id]'), (el) => el.id);
   }
 
+  /**
+   * Triggers the 'formUpdated' event on form elements when they are modified.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches formUpdated behaviors.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches formUpdated behaviors.
+   *
+   * @fires event:formUpdated
+   */
   Drupal.behaviors.formUpdated = {
     attach(context) {
       const $context = $(context);
       const contextIsForm = $context.is('form');
-      const $forms = $(once('form-updated', contextIsForm ? $context : $context.find('form')));
+      const $forms = $(
+        once('form-updated', contextIsForm ? $context : $context.find('form')),
+      );
       let formFields;
 
       if ($forms.length) {
-        $.makeArray($forms).forEach(form => {
+        // Initialize form behaviors, use $.makeArray to be able to use native
+        // forEach array method and have the callback parameters in the right
+        // order.
+        $.makeArray($forms).forEach((form) => {
           const events = 'change.formUpdated input.formUpdated ';
-          const eventHandler = debounce(event => {
+          const eventHandler = debounce((event) => {
             triggerFormUpdated(event.target);
           }, 300);
           formFields = fieldsList(form).join(',');
+
           form.setAttribute('data-drupal-form-fields', formFields);
           $(form).on(events, eventHandler);
         });
       }
-
+      // On ajax requests context is the form element.
       if (contextIsForm) {
         formFields = fieldsList(context).join(',');
+        // @todo replace with form.getAttribute() when #1979468 is in.
         const currentFields = $(context).attr('data-drupal-form-fields');
-
+        // If there has been a change in the fields or their order, trigger
+        // formUpdated.
         if (formFields !== currentFields) {
           triggerFormUpdated(context);
         }
       }
     },
-
     detach(context, settings, trigger) {
       const $context = $(context);
       const contextIsForm = $context.is('form');
-
       if (trigger === 'unload') {
-        once.remove('form-updated', contextIsForm ? $context : $context.find('form')).forEach(form => {
-          form.removeAttribute('data-drupal-form-fields');
-          $(form).off('.formUpdated');
-        });
+        once
+          .remove(
+            'form-updated',
+            contextIsForm ? $context : $context.find('form'),
+          )
+          .forEach((form) => {
+            form.removeAttribute('data-drupal-form-fields');
+            $(form).off('.formUpdated');
+          });
       }
-    }
-
+    },
   };
+
+  /**
+   * Prepopulate form fields with information from the visitor browser.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the behavior for filling user info from browser.
+   */
   Drupal.behaviors.fillUserInfoFromBrowser = {
     attach(context, settings) {
       const userInfo = ['name', 'mail', 'homepage'];
-      const $forms = $(once('user-info-from-browser', '[data-user-info-from-browser]'));
-
+      const $forms = $(
+        once('user-info-from-browser', '[data-user-info-from-browser]'),
+      );
       if ($forms.length) {
-        userInfo.forEach(info => {
+        userInfo.forEach((info) => {
           const $element = $forms.find(`[name=${info}]`);
           const browserData = localStorage.getItem(`Drupal.visitor.${info}`);
-
           if (!$element.length) {
             return;
           }
-
           const emptyValue = $element[0].value === '';
-          const defaultValue = $element.attr('data-drupal-default-value') === $element[0].value;
-
+          const defaultValue =
+            $element.attr('data-drupal-default-value') === $element[0].value;
           if (browserData && (emptyValue || defaultValue)) {
             $element.each(function (index, item) {
               item.value = browserData;
@@ -120,39 +258,68 @@
           }
         });
       }
-
       $forms.on('submit', () => {
-        userInfo.forEach(info => {
+        userInfo.forEach((info) => {
           const $element = $forms.find(`[name=${info}]`);
-
           if ($element.length) {
             localStorage.setItem(`Drupal.visitor.${info}`, $element[0].value);
           }
         });
       });
-    }
-
+    },
   };
 
-  const handleFragmentLinkClickOrHashChange = e => {
+  /**
+   * Sends a fragment interaction event on a hash change or fragment link click.
+   *
+   * @param {jQuery.Event} e
+   *   The event triggered.
+   *
+   * @fires event:formFragmentLinkClickOrHashChange
+   */
+  const handleFragmentLinkClickOrHashChange = (e) => {
     let url;
-
     if (e.type === 'click') {
-      url = e.currentTarget.location ? e.currentTarget.location : e.currentTarget;
+      url = e.currentTarget.location
+        ? e.currentTarget.location
+        : e.currentTarget;
     } else {
       url = window.location;
     }
-
     const hash = url.hash.substr(1);
-
     if (hash) {
       const $target = $(`#${hash}`);
       $('body').trigger('formFragmentLinkClickOrHashChange', [$target]);
+
+      /**
+       * Clicking a fragment link or a hash change should focus the target
+       * element, but event timing issues in multiple browsers require a timeout.
+       */
       setTimeout(() => $target.trigger('focus'), 300);
     }
   };
 
-  const debouncedHandleFragmentLinkClickOrHashChange = debounce(handleFragmentLinkClickOrHashChange, 300, true);
-  $(window).on('hashchange.form-fragment', debouncedHandleFragmentLinkClickOrHashChange);
-  $(document).on('click.form-fragment', 'a[href*="#"]', debouncedHandleFragmentLinkClickOrHashChange);
-})(jQuery, Drupal, Drupal.debounce);
\ No newline at end of file
+  const debouncedHandleFragmentLinkClickOrHashChange = debounce(
+    handleFragmentLinkClickOrHashChange,
+    300,
+    true,
+  );
+
+  // Binds a listener to handle URL fragment changes.
+  $(window).on(
+    'hashchange.form-fragment',
+    debouncedHandleFragmentLinkClickOrHashChange,
+  );
+
+  /**
+   * Binds a listener to handle clicks on fragment links and absolute URL links
+   * containing a fragment, this is needed next to the hash change listener
+   * because clicking such links doesn't trigger a hash change when the fragment
+   * is already in the URL.
+   */
+  $(document).on(
+    'click.form-fragment',
+    'a[href*="#"]',
+    debouncedHandleFragmentLinkClickOrHashChange,
+  );
+})(jQuery, Drupal, Drupal.debounce);
diff --git a/core/misc/jquery.tabbable.shim.es6.js b/core/misc/jquery.tabbable.shim.es6.js
deleted file mode 100644
index 6820cd1b1ff7..000000000000
--- a/core/misc/jquery.tabbable.shim.es6.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * @file
- * Defines a backwards-compatible shim for the jQuery UI :tabbable selector.
- */
-
-(($, Drupal, { isTabbable }) => {
-  $.extend($.expr[':'], {
-    tabbable(element) {
-      Drupal.deprecationError({
-        message:
-          'The :tabbable selector is deprecated in Drupal 9.2.0 and will be removed in Drupal 11.0.0. Use the core/tabbable library instead. See https://www.drupal.org/node/3183730',
-      });
-
-      // The tabbable library considers the summary element tabbable, and also
-      // considers a details element without a summary tabbable. The jQuery UI
-      // :tabbable selector does not. This is due to those element types being
-      // inert in IE/Edge.
-      // @see https://allyjs.io/data-tables/focusable.html
-      if (element.tagName === 'SUMMARY' || element.tagName === 'DETAILS') {
-        const tabIndex = element.getAttribute('tabIndex');
-        if (tabIndex === null || tabIndex < 0) {
-          return false;
-        }
-      }
-      return isTabbable(element);
-    },
-  });
-})(jQuery, Drupal, window.tabbable);
diff --git a/core/misc/jquery.tabbable.shim.js b/core/misc/jquery.tabbable.shim.js
index bd4174214c2e..6820cd1b1ff7 100644
--- a/core/misc/jquery.tabbable.shim.js
+++ b/core/misc/jquery.tabbable.shim.js
@@ -1,30 +1,28 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Defines a backwards-compatible shim for the jQuery UI :tabbable selector.
+ */
 
-(($, Drupal, _ref) => {
-  let {
-    isTabbable
-  } = _ref;
+(($, Drupal, { isTabbable }) => {
   $.extend($.expr[':'], {
     tabbable(element) {
       Drupal.deprecationError({
-        message: 'The :tabbable selector is deprecated in Drupal 9.2.0 and will be removed in Drupal 11.0.0. Use the core/tabbable library instead. See https://www.drupal.org/node/3183730'
+        message:
+          'The :tabbable selector is deprecated in Drupal 9.2.0 and will be removed in Drupal 11.0.0. Use the core/tabbable library instead. See https://www.drupal.org/node/3183730',
       });
 
+      // The tabbable library considers the summary element tabbable, and also
+      // considers a details element without a summary tabbable. The jQuery UI
+      // :tabbable selector does not. This is due to those element types being
+      // inert in IE/Edge.
+      // @see https://allyjs.io/data-tables/focusable.html
       if (element.tagName === 'SUMMARY' || element.tagName === 'DETAILS') {
         const tabIndex = element.getAttribute('tabIndex');
-
         if (tabIndex === null || tabIndex < 0) {
           return false;
         }
       }
-
       return isTabbable(element);
-    }
-
+    },
   });
-})(jQuery, Drupal, window.tabbable);
\ No newline at end of file
+})(jQuery, Drupal, window.tabbable);
diff --git a/core/misc/machine-name.es6.js b/core/misc/machine-name.es6.js
deleted file mode 100644
index e890685ec515..000000000000
--- a/core/misc/machine-name.es6.js
+++ /dev/null
@@ -1,237 +0,0 @@
-/**
- * @file
- * Machine name functionality.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Attach the machine-readable name form element behavior.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches machine-name behaviors.
-   */
-  Drupal.behaviors.machineName = {
-    /**
-     * Attaches the behavior.
-     *
-     * @param {Element} context
-     *   The context for attaching the behavior.
-     * @param {object} settings
-     *   Settings object.
-     * @param {object} settings.machineName
-     *   A list of elements to process, keyed by the HTML ID of the form
-     *   element containing the human-readable value. Each element is an object
-     *   defining the following properties:
-     *   - target: The HTML ID of the machine name form element.
-     *   - suffix: The HTML ID of a container to show the machine name preview
-     *     in (usually a field suffix after the human-readable name
-     *     form element).
-     *   - label: The label to show for the machine name preview.
-     *   - replace_pattern: A regular expression (without modifiers) matching
-     *     disallowed characters in the machine name; e.g., '[^a-z0-9]+'.
-     *   - replace: A character to replace disallowed characters with; e.g.,
-     *     '_' or '-'.
-     *   - standalone: Whether the preview should stay in its own element
-     *     rather than the suffix of the source element.
-     *   - field_prefix: The #field_prefix of the form element.
-     *   - field_suffix: The #field_suffix of the form element.
-     */
-    attach(context, settings) {
-      const self = this;
-      const $context = $(context);
-      let timeout = null;
-      let xhr = null;
-
-      function clickEditHandler(e) {
-        const data = e.data;
-        data.$wrapper.removeClass('visually-hidden');
-        data.$target.trigger('focus');
-        data.$suffix.hide();
-        data.$source.off('.machineName');
-      }
-
-      function machineNameHandler(e) {
-        const data = e.data;
-        const options = data.options;
-        const baseValue = e.target.value;
-
-        const rx = new RegExp(options.replace_pattern, 'g');
-        const expected = baseValue
-          .toLowerCase()
-          .replace(rx, options.replace)
-          .substr(0, options.maxlength);
-
-        // Abort the last pending request because the label has changed and it
-        // is no longer valid.
-        if (xhr && xhr.readystate !== 4) {
-          xhr.abort();
-          xhr = null;
-        }
-
-        // Wait 300 milliseconds for Ajax request since the last event to update
-        // the machine name i.e., after the user has stopped typing.
-        if (timeout) {
-          clearTimeout(timeout);
-          timeout = null;
-        }
-        if (baseValue.toLowerCase() !== expected) {
-          timeout = setTimeout(() => {
-            xhr = self.transliterate(baseValue, options).done((machine) => {
-              self.showMachineName(machine.substr(0, options.maxlength), data);
-            });
-          }, 300);
-        } else {
-          self.showMachineName(expected, data);
-        }
-      }
-
-      Object.keys(settings.machineName).forEach((sourceId) => {
-        const options = settings.machineName[sourceId];
-
-        const $source = $(
-          once(
-            'machine-name',
-            $context.find(sourceId).addClass('machine-name-source'),
-          ),
-        );
-        const $target = $context
-          .find(options.target)
-          .addClass('machine-name-target');
-        const $suffix = $context.find(options.suffix);
-        const $wrapper = $target.closest('.js-form-item');
-        // All elements have to exist.
-        if (
-          !$source.length ||
-          !$target.length ||
-          !$suffix.length ||
-          !$wrapper.length
-        ) {
-          return;
-        }
-        // Skip processing upon a form validation error on the machine name.
-        if ($target.hasClass('error')) {
-          return;
-        }
-        // Figure out the maximum length for the machine name.
-        options.maxlength = $target.attr('maxlength');
-        // Hide the form item container of the machine name form element.
-        $wrapper.addClass('visually-hidden');
-        // Initial machine name from the target field default value.
-        const machine = $target[0].value;
-        // Append the machine name preview to the source field.
-        const $preview = $(
-          `<span class="machine-name-value">${
-            options.field_prefix
-          }${Drupal.checkPlain(machine)}${options.field_suffix}</span>`,
-        );
-        $suffix.empty();
-        if (options.label) {
-          $suffix.append(
-            `<span class="machine-name-label">${options.label}: </span>`,
-          );
-        }
-        $suffix.append($preview);
-
-        // If the machine name cannot be edited, stop further processing.
-        if ($target.is(':disabled')) {
-          return;
-        }
-
-        const eventData = {
-          $source,
-          $target,
-          $suffix,
-          $wrapper,
-          $preview,
-          options,
-        };
-
-        // If no initial value, determine machine name based on the
-        // human-readable form element value.
-        if (machine === '' && $source[0].value !== '') {
-          self.transliterate($source[0].value, options).done((machineName) => {
-            self.showMachineName(
-              machineName.substr(0, options.maxlength),
-              eventData,
-            );
-          });
-        }
-
-        // If it is editable, append an edit link.
-        const $link = $(
-          `<span class="admin-link"><button type="button" class="link">${Drupal.t(
-            'Edit',
-          )}</button></span>`,
-        ).on('click', eventData, clickEditHandler);
-        $suffix.append($link);
-
-        // Preview the machine name in realtime when the human-readable name
-        // changes, but only if there is no machine name yet; i.e., only upon
-        // initial creation, not when editing.
-        if ($target[0].value === '') {
-          $source
-            .on('formUpdated.machineName', eventData, machineNameHandler)
-            // Initialize machine name preview.
-            .trigger('formUpdated.machineName');
-        }
-
-        // Add a listener for an invalid event on the machine name input
-        // to show its container and focus it.
-        $target.on('invalid', eventData, clickEditHandler);
-      });
-    },
-
-    showMachineName(machine, data) {
-      const settings = data.options;
-      // Set the machine name to the transliterated value.
-      if (machine !== '') {
-        if (machine !== settings.replace) {
-          data.$target[0].value = machine;
-          data.$preview.html(
-            settings.field_prefix +
-              Drupal.checkPlain(machine) +
-              settings.field_suffix,
-          );
-        }
-        data.$suffix.show();
-      } else {
-        data.$suffix.hide();
-        data.$target[0].value = machine;
-        data.$preview.empty();
-      }
-    },
-
-    /**
-     * Transliterate a human-readable name to a machine name.
-     *
-     * @param {string} source
-     *   A string to transliterate.
-     * @param {object} settings
-     *   The machine name settings for the corresponding field.
-     * @param {string} settings.replace_pattern
-     *   A regular expression (without modifiers) matching disallowed characters
-     *   in the machine name; e.g., '[^a-z0-9]+'.
-     * @param {string} settings.replace_token
-     *   A token to validate the regular expression.
-     * @param {string} settings.replace
-     *   A character to replace disallowed characters with; e.g., '_' or '-'.
-     * @param {number} settings.maxlength
-     *   The maximum length of the machine name.
-     *
-     * @return {jQuery}
-     *   The transliterated source string.
-     */
-    transliterate(source, settings) {
-      return $.get(Drupal.url('machine_name/transliterate'), {
-        text: source,
-        langcode: drupalSettings.langcode,
-        replace_pattern: settings.replace_pattern,
-        replace_token: settings.replace_token,
-        replace: settings.replace,
-        lowercase: true,
-      });
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/misc/machine-name.js b/core/misc/machine-name.js
index 7281c4a3eda2..e890685ec515 100644
--- a/core/misc/machine-name.js
+++ b/core/misc/machine-name.js
@@ -1,12 +1,43 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Machine name functionality.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * Attach the machine-readable name form element behavior.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches machine-name behaviors.
+   */
   Drupal.behaviors.machineName = {
+    /**
+     * Attaches the behavior.
+     *
+     * @param {Element} context
+     *   The context for attaching the behavior.
+     * @param {object} settings
+     *   Settings object.
+     * @param {object} settings.machineName
+     *   A list of elements to process, keyed by the HTML ID of the form
+     *   element containing the human-readable value. Each element is an object
+     *   defining the following properties:
+     *   - target: The HTML ID of the machine name form element.
+     *   - suffix: The HTML ID of a container to show the machine name preview
+     *     in (usually a field suffix after the human-readable name
+     *     form element).
+     *   - label: The label to show for the machine name preview.
+     *   - replace_pattern: A regular expression (without modifiers) matching
+     *     disallowed characters in the machine name; e.g., '[^a-z0-9]+'.
+     *   - replace: A character to replace disallowed characters with; e.g.,
+     *     '_' or '-'.
+     *   - standalone: Whether the preview should stay in its own element
+     *     rather than the suffix of the source element.
+     *   - field_prefix: The #field_prefix of the form element.
+     *   - field_suffix: The #field_suffix of the form element.
+     */
     attach(context, settings) {
       const self = this;
       const $context = $(context);
@@ -25,22 +56,29 @@
         const data = e.data;
         const options = data.options;
         const baseValue = e.target.value;
+
         const rx = new RegExp(options.replace_pattern, 'g');
-        const expected = baseValue.toLowerCase().replace(rx, options.replace).substr(0, options.maxlength);
+        const expected = baseValue
+          .toLowerCase()
+          .replace(rx, options.replace)
+          .substr(0, options.maxlength);
 
+        // Abort the last pending request because the label has changed and it
+        // is no longer valid.
         if (xhr && xhr.readystate !== 4) {
           xhr.abort();
           xhr = null;
         }
 
+        // Wait 300 milliseconds for Ajax request since the last event to update
+        // the machine name i.e., after the user has stopped typing.
         if (timeout) {
           clearTimeout(timeout);
           timeout = null;
         }
-
         if (baseValue.toLowerCase() !== expected) {
           timeout = setTimeout(() => {
-            xhr = self.transliterate(baseValue, options).done(machine => {
+            xhr = self.transliterate(baseValue, options).done((machine) => {
               self.showMachineName(machine.substr(0, options.maxlength), data);
             });
           }, 300);
@@ -49,33 +87,54 @@
         }
       }
 
-      Object.keys(settings.machineName).forEach(sourceId => {
+      Object.keys(settings.machineName).forEach((sourceId) => {
         const options = settings.machineName[sourceId];
-        const $source = $(once('machine-name', $context.find(sourceId).addClass('machine-name-source')));
-        const $target = $context.find(options.target).addClass('machine-name-target');
+
+        const $source = $(
+          once(
+            'machine-name',
+            $context.find(sourceId).addClass('machine-name-source'),
+          ),
+        );
+        const $target = $context
+          .find(options.target)
+          .addClass('machine-name-target');
         const $suffix = $context.find(options.suffix);
         const $wrapper = $target.closest('.js-form-item');
-
-        if (!$source.length || !$target.length || !$suffix.length || !$wrapper.length) {
+        // All elements have to exist.
+        if (
+          !$source.length ||
+          !$target.length ||
+          !$suffix.length ||
+          !$wrapper.length
+        ) {
           return;
         }
-
+        // Skip processing upon a form validation error on the machine name.
         if ($target.hasClass('error')) {
           return;
         }
-
+        // Figure out the maximum length for the machine name.
         options.maxlength = $target.attr('maxlength');
+        // Hide the form item container of the machine name form element.
         $wrapper.addClass('visually-hidden');
+        // Initial machine name from the target field default value.
         const machine = $target[0].value;
-        const $preview = $(`<span class="machine-name-value">${options.field_prefix}${Drupal.checkPlain(machine)}${options.field_suffix}</span>`);
+        // Append the machine name preview to the source field.
+        const $preview = $(
+          `<span class="machine-name-value">${
+            options.field_prefix
+          }${Drupal.checkPlain(machine)}${options.field_suffix}</span>`,
+        );
         $suffix.empty();
-
         if (options.label) {
-          $suffix.append(`<span class="machine-name-label">${options.label}: </span>`);
+          $suffix.append(
+            `<span class="machine-name-label">${options.label}: </span>`,
+          );
         }
-
         $suffix.append($preview);
 
+        // If the machine name cannot be edited, stop further processing.
         if ($target.is(':disabled')) {
           return;
         }
@@ -86,35 +145,56 @@
           $suffix,
           $wrapper,
           $preview,
-          options
+          options,
         };
 
+        // If no initial value, determine machine name based on the
+        // human-readable form element value.
         if (machine === '' && $source[0].value !== '') {
-          self.transliterate($source[0].value, options).done(machineName => {
-            self.showMachineName(machineName.substr(0, options.maxlength), eventData);
+          self.transliterate($source[0].value, options).done((machineName) => {
+            self.showMachineName(
+              machineName.substr(0, options.maxlength),
+              eventData,
+            );
           });
         }
 
-        const $link = $(`<span class="admin-link"><button type="button" class="link">${Drupal.t('Edit')}</button></span>`).on('click', eventData, clickEditHandler);
+        // If it is editable, append an edit link.
+        const $link = $(
+          `<span class="admin-link"><button type="button" class="link">${Drupal.t(
+            'Edit',
+          )}</button></span>`,
+        ).on('click', eventData, clickEditHandler);
         $suffix.append($link);
 
+        // Preview the machine name in realtime when the human-readable name
+        // changes, but only if there is no machine name yet; i.e., only upon
+        // initial creation, not when editing.
         if ($target[0].value === '') {
-          $source.on('formUpdated.machineName', eventData, machineNameHandler).trigger('formUpdated.machineName');
+          $source
+            .on('formUpdated.machineName', eventData, machineNameHandler)
+            // Initialize machine name preview.
+            .trigger('formUpdated.machineName');
         }
 
+        // Add a listener for an invalid event on the machine name input
+        // to show its container and focus it.
         $target.on('invalid', eventData, clickEditHandler);
       });
     },
 
     showMachineName(machine, data) {
       const settings = data.options;
-
+      // Set the machine name to the transliterated value.
       if (machine !== '') {
         if (machine !== settings.replace) {
           data.$target[0].value = machine;
-          data.$preview.html(settings.field_prefix + Drupal.checkPlain(machine) + settings.field_suffix);
+          data.$preview.html(
+            settings.field_prefix +
+              Drupal.checkPlain(machine) +
+              settings.field_suffix,
+          );
         }
-
         data.$suffix.show();
       } else {
         data.$suffix.hide();
@@ -123,6 +203,26 @@
       }
     },
 
+    /**
+     * Transliterate a human-readable name to a machine name.
+     *
+     * @param {string} source
+     *   A string to transliterate.
+     * @param {object} settings
+     *   The machine name settings for the corresponding field.
+     * @param {string} settings.replace_pattern
+     *   A regular expression (without modifiers) matching disallowed characters
+     *   in the machine name; e.g., '[^a-z0-9]+'.
+     * @param {string} settings.replace_token
+     *   A token to validate the regular expression.
+     * @param {string} settings.replace
+     *   A character to replace disallowed characters with; e.g., '_' or '-'.
+     * @param {number} settings.maxlength
+     *   The maximum length of the machine name.
+     *
+     * @return {jQuery}
+     *   The transliterated source string.
+     */
     transliterate(source, settings) {
       return $.get(Drupal.url('machine_name/transliterate'), {
         text: source,
@@ -130,9 +230,8 @@
         replace_pattern: settings.replace_pattern,
         replace_token: settings.replace_token,
         replace: settings.replace,
-        lowercase: true
+        lowercase: true,
       });
-    }
-
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/misc/message.es6.js b/core/misc/message.es6.js
deleted file mode 100644
index 9db487cd9085..000000000000
--- a/core/misc/message.es6.js
+++ /dev/null
@@ -1,254 +0,0 @@
-/**
- * @file
- * Message API.
- */
-((Drupal) => {
-  /**
-   * @typedef {class} Drupal.Message~messageDefinition
-   */
-
-  /**
-   * Constructs a new instance of the Drupal.Message class.
-   *
-   * This provides a uniform interface for adding and removing messages to a
-   * specific location on the page.
-   *
-   * @param {HTMLElement} messageWrapper
-   *   The zone where to add messages. If no element is provided an attempt is
-   *   made to determine a default location.
-   *
-   * @return {Drupal.Message~messageDefinition}
-   *   Class to add and remove messages.
-   */
-  Drupal.Message = class {
-    constructor(messageWrapper = null) {
-      if (!messageWrapper) {
-        this.messageWrapper = Drupal.Message.defaultWrapper();
-      } else {
-        this.messageWrapper = messageWrapper;
-      }
-    }
-
-    /**
-     * Attempt to determine the default location for
-     * inserting JavaScript messages or create one if needed.
-     *
-     * @return {HTMLElement}
-     *   The default destination for JavaScript messages.
-     */
-    static defaultWrapper() {
-      let wrapper = document.querySelector('[data-drupal-messages]');
-      if (!wrapper) {
-        wrapper = document.querySelector('[data-drupal-messages-fallback]');
-        wrapper.removeAttribute('data-drupal-messages-fallback');
-        wrapper.setAttribute('data-drupal-messages', '');
-        wrapper.classList.remove('hidden');
-      }
-      return wrapper.innerHTML === ''
-        ? Drupal.Message.messageInternalWrapper(wrapper)
-        : wrapper.firstElementChild;
-    }
-
-    /**
-     * Provide an object containing the available message types.
-     *
-     * @return {Object}
-     *   An object containing message type strings.
-     */
-    static getMessageTypeLabels() {
-      return {
-        status: Drupal.t('Status message'),
-        error: Drupal.t('Error message'),
-        warning: Drupal.t('Warning message'),
-      };
-    }
-
-    /**
-     * Sequentially adds a message to the message area.
-     *
-     * @name Drupal.Message~messageDefinition.add
-     *
-     * @param {string} message
-     *   The message to display
-     * @param {object} [options]
-     *   The context of the message.
-     * @param {string} [options.id]
-     *   The message ID, it can be a simple value: `'filevalidationerror'`
-     *   or several values separated by a space: `'mymodule formvalidation'`
-     *   which can be used as an explicit selector for a message.
-     * @param {string} [options.type=status]
-     *   Message type, can be either 'status', 'error' or 'warning'.
-     * @param {string} [options.announce]
-     *   Screen-reader version of the message if necessary. To prevent a message
-     *   being sent to Drupal.announce() this should be an empty string.
-     * @param {string} [options.priority]
-     *   Priority of the message for Drupal.announce().
-     *
-     * @return {string}
-     *   ID of message.
-     */
-    add(message, options = {}) {
-      if (!options.hasOwnProperty('type')) {
-        options.type = 'status';
-      }
-
-      if (typeof message !== 'string') {
-        throw new Error('Message must be a string.');
-      }
-
-      // Send message to screen reader.
-      Drupal.Message.announce(message, options);
-      /**
-       * Use the provided index for the message or generate a pseudo-random key
-       * to allow message deletion.
-       */
-      options.id = options.id
-        ? String(options.id)
-        : `${options.type}-${Math.random().toFixed(15).replace('0.', '')}`;
-
-      // Throw an error if an unexpected message type is used.
-      if (!Drupal.Message.getMessageTypeLabels().hasOwnProperty(options.type)) {
-        const { type } = options;
-        throw new Error(
-          `The message type, ${type}, is not present in Drupal.Message.getMessageTypeLabels().`,
-        );
-      }
-
-      this.messageWrapper.appendChild(
-        Drupal.theme('message', { text: message }, options),
-      );
-
-      return options.id;
-    }
-
-    /**
-     * Select a message based on id.
-     *
-     * @name Drupal.Message~messageDefinition.select
-     *
-     * @param {string} id
-     *   The message id to delete from the area.
-     *
-     * @return {Element}
-     *   Element found.
-     */
-    select(id) {
-      return this.messageWrapper.querySelector(
-        `[data-drupal-message-id^="${id}"]`,
-      );
-    }
-
-    /**
-     * Removes messages from the message area.
-     *
-     * @name Drupal.Message~messageDefinition.remove
-     *
-     * @param {string} id
-     *   Index of the message to remove, as returned by
-     *   {@link Drupal.Message~messageDefinition.add}.
-     *
-     * @return {number}
-     *   Number of removed messages.
-     */
-    remove(id) {
-      return this.messageWrapper.removeChild(this.select(id));
-    }
-
-    /**
-     * Removes all messages from the message area.
-     *
-     * @name Drupal.Message~messageDefinition.clear
-     */
-    clear() {
-      Array.prototype.forEach.call(
-        this.messageWrapper.querySelectorAll('[data-drupal-message-id]'),
-        (message) => {
-          this.messageWrapper.removeChild(message);
-        },
-      );
-    }
-
-    /**
-     * Helper to call Drupal.announce() with the right parameters.
-     *
-     * @param {string} message
-     *   Displayed message.
-     * @param {object} options
-     *   Additional data.
-     * @param {string} [options.announce]
-     *   Screen-reader version of the message if necessary. To prevent a message
-     *   being sent to Drupal.announce() this should be `''`.
-     * @param {string} [options.priority]
-     *   Priority of the message for Drupal.announce().
-     * @param {string} [options.type]
-     *   Message type, can be either 'status', 'error' or 'warning'.
-     */
-    static announce(message, options) {
-      if (
-        !options.priority &&
-        (options.type === 'warning' || options.type === 'error')
-      ) {
-        options.priority = 'assertive';
-      }
-      /**
-       * If screen reader message is not disabled announce screen reader
-       * specific text or fallback to the displayed message.
-       */
-      if (options.announce !== '') {
-        Drupal.announce(options.announce || message, options.priority);
-      }
-    }
-
-    /**
-     * Function for creating the internal message wrapper element.
-     *
-     * @param {HTMLElement} messageWrapper
-     *   The message wrapper.
-     *
-     * @return {HTMLElement}
-     *   The internal wrapper DOM element.
-     */
-    static messageInternalWrapper(messageWrapper) {
-      const innerWrapper = document.createElement('div');
-      innerWrapper.setAttribute('class', 'messages__wrapper');
-      messageWrapper.insertAdjacentElement('afterbegin', innerWrapper);
-      return innerWrapper;
-    }
-  };
-
-  /**
-   * Theme function for a message.
-   *
-   * @param {object} message
-   *   The message object.
-   * @param {string} message.text
-   *   The message text.
-   * @param {object} options
-   *   The message context.
-   * @param {string} options.type
-   *   The message type.
-   * @param {string} options.id
-   *   ID of the message, for reference.
-   *
-   * @return {HTMLElement}
-   *   A DOM Node.
-   */
-  Drupal.theme.message = ({ text }, { type, id }) => {
-    const messagesTypes = Drupal.Message.getMessageTypeLabels();
-    const messageWrapper = document.createElement('div');
-
-    messageWrapper.setAttribute('class', `messages messages--${type}`);
-    messageWrapper.setAttribute(
-      'role',
-      type === 'error' || type === 'warning' ? 'alert' : 'status',
-    );
-    messageWrapper.setAttribute('data-drupal-message-id', id);
-    messageWrapper.setAttribute('data-drupal-message-type', type);
-
-    messageWrapper.setAttribute('aria-label', messagesTypes[type]);
-
-    messageWrapper.innerHTML = `${text}`;
-
-    return messageWrapper;
-  };
-})(Drupal);
diff --git a/core/misc/message.js b/core/misc/message.js
index fd899e0ceba2..9db487cd9085 100644
--- a/core/misc/message.js
+++ b/core/misc/message.js
@@ -1,15 +1,27 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(Drupal => {
+ * @file
+ * Message API.
+ */
+((Drupal) => {
+  /**
+   * @typedef {class} Drupal.Message~messageDefinition
+   */
+
+  /**
+   * Constructs a new instance of the Drupal.Message class.
+   *
+   * This provides a uniform interface for adding and removing messages to a
+   * specific location on the page.
+   *
+   * @param {HTMLElement} messageWrapper
+   *   The zone where to add messages. If no element is provided an attempt is
+   *   made to determine a default location.
+   *
+   * @return {Drupal.Message~messageDefinition}
+   *   Class to add and remove messages.
+   */
   Drupal.Message = class {
-    constructor() {
-      let messageWrapper = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
-
+    constructor(messageWrapper = null) {
       if (!messageWrapper) {
         this.messageWrapper = Drupal.Message.defaultWrapper();
       } else {
@@ -17,30 +29,65 @@
       }
     }
 
+    /**
+     * Attempt to determine the default location for
+     * inserting JavaScript messages or create one if needed.
+     *
+     * @return {HTMLElement}
+     *   The default destination for JavaScript messages.
+     */
     static defaultWrapper() {
       let wrapper = document.querySelector('[data-drupal-messages]');
-
       if (!wrapper) {
         wrapper = document.querySelector('[data-drupal-messages-fallback]');
         wrapper.removeAttribute('data-drupal-messages-fallback');
         wrapper.setAttribute('data-drupal-messages', '');
         wrapper.classList.remove('hidden');
       }
-
-      return wrapper.innerHTML === '' ? Drupal.Message.messageInternalWrapper(wrapper) : wrapper.firstElementChild;
+      return wrapper.innerHTML === ''
+        ? Drupal.Message.messageInternalWrapper(wrapper)
+        : wrapper.firstElementChild;
     }
 
+    /**
+     * Provide an object containing the available message types.
+     *
+     * @return {Object}
+     *   An object containing message type strings.
+     */
     static getMessageTypeLabels() {
       return {
         status: Drupal.t('Status message'),
         error: Drupal.t('Error message'),
-        warning: Drupal.t('Warning message')
+        warning: Drupal.t('Warning message'),
       };
     }
 
-    add(message) {
-      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
-
+    /**
+     * Sequentially adds a message to the message area.
+     *
+     * @name Drupal.Message~messageDefinition.add
+     *
+     * @param {string} message
+     *   The message to display
+     * @param {object} [options]
+     *   The context of the message.
+     * @param {string} [options.id]
+     *   The message ID, it can be a simple value: `'filevalidationerror'`
+     *   or several values separated by a space: `'mymodule formvalidation'`
+     *   which can be used as an explicit selector for a message.
+     * @param {string} [options.type=status]
+     *   Message type, can be either 'status', 'error' or 'warning'.
+     * @param {string} [options.announce]
+     *   Screen-reader version of the message if necessary. To prevent a message
+     *   being sent to Drupal.announce() this should be an empty string.
+     * @param {string} [options.priority]
+     *   Priority of the message for Drupal.announce().
+     *
+     * @return {string}
+     *   ID of message.
+     */
+    add(message, options = {}) {
       if (!options.hasOwnProperty('type')) {
         options.type = 'status';
       }
@@ -49,71 +96,159 @@
         throw new Error('Message must be a string.');
       }
 
+      // Send message to screen reader.
       Drupal.Message.announce(message, options);
-      options.id = options.id ? String(options.id) : `${options.type}-${Math.random().toFixed(15).replace('0.', '')}`;
-
+      /**
+       * Use the provided index for the message or generate a pseudo-random key
+       * to allow message deletion.
+       */
+      options.id = options.id
+        ? String(options.id)
+        : `${options.type}-${Math.random().toFixed(15).replace('0.', '')}`;
+
+      // Throw an error if an unexpected message type is used.
       if (!Drupal.Message.getMessageTypeLabels().hasOwnProperty(options.type)) {
-        const {
-          type
-        } = options;
-        throw new Error(`The message type, ${type}, is not present in Drupal.Message.getMessageTypeLabels().`);
+        const { type } = options;
+        throw new Error(
+          `The message type, ${type}, is not present in Drupal.Message.getMessageTypeLabels().`,
+        );
       }
 
-      this.messageWrapper.appendChild(Drupal.theme('message', {
-        text: message
-      }, options));
+      this.messageWrapper.appendChild(
+        Drupal.theme('message', { text: message }, options),
+      );
+
       return options.id;
     }
 
+    /**
+     * Select a message based on id.
+     *
+     * @name Drupal.Message~messageDefinition.select
+     *
+     * @param {string} id
+     *   The message id to delete from the area.
+     *
+     * @return {Element}
+     *   Element found.
+     */
     select(id) {
-      return this.messageWrapper.querySelector(`[data-drupal-message-id^="${id}"]`);
+      return this.messageWrapper.querySelector(
+        `[data-drupal-message-id^="${id}"]`,
+      );
     }
 
+    /**
+     * Removes messages from the message area.
+     *
+     * @name Drupal.Message~messageDefinition.remove
+     *
+     * @param {string} id
+     *   Index of the message to remove, as returned by
+     *   {@link Drupal.Message~messageDefinition.add}.
+     *
+     * @return {number}
+     *   Number of removed messages.
+     */
     remove(id) {
       return this.messageWrapper.removeChild(this.select(id));
     }
 
+    /**
+     * Removes all messages from the message area.
+     *
+     * @name Drupal.Message~messageDefinition.clear
+     */
     clear() {
-      Array.prototype.forEach.call(this.messageWrapper.querySelectorAll('[data-drupal-message-id]'), message => {
-        this.messageWrapper.removeChild(message);
-      });
+      Array.prototype.forEach.call(
+        this.messageWrapper.querySelectorAll('[data-drupal-message-id]'),
+        (message) => {
+          this.messageWrapper.removeChild(message);
+        },
+      );
     }
 
+    /**
+     * Helper to call Drupal.announce() with the right parameters.
+     *
+     * @param {string} message
+     *   Displayed message.
+     * @param {object} options
+     *   Additional data.
+     * @param {string} [options.announce]
+     *   Screen-reader version of the message if necessary. To prevent a message
+     *   being sent to Drupal.announce() this should be `''`.
+     * @param {string} [options.priority]
+     *   Priority of the message for Drupal.announce().
+     * @param {string} [options.type]
+     *   Message type, can be either 'status', 'error' or 'warning'.
+     */
     static announce(message, options) {
-      if (!options.priority && (options.type === 'warning' || options.type === 'error')) {
+      if (
+        !options.priority &&
+        (options.type === 'warning' || options.type === 'error')
+      ) {
         options.priority = 'assertive';
       }
-
+      /**
+       * If screen reader message is not disabled announce screen reader
+       * specific text or fallback to the displayed message.
+       */
       if (options.announce !== '') {
         Drupal.announce(options.announce || message, options.priority);
       }
     }
 
+    /**
+     * Function for creating the internal message wrapper element.
+     *
+     * @param {HTMLElement} messageWrapper
+     *   The message wrapper.
+     *
+     * @return {HTMLElement}
+     *   The internal wrapper DOM element.
+     */
     static messageInternalWrapper(messageWrapper) {
       const innerWrapper = document.createElement('div');
       innerWrapper.setAttribute('class', 'messages__wrapper');
       messageWrapper.insertAdjacentElement('afterbegin', innerWrapper);
       return innerWrapper;
     }
-
   };
 
-  Drupal.theme.message = (_ref, _ref2) => {
-    let {
-      text
-    } = _ref;
-    let {
-      type,
-      id
-    } = _ref2;
+  /**
+   * Theme function for a message.
+   *
+   * @param {object} message
+   *   The message object.
+   * @param {string} message.text
+   *   The message text.
+   * @param {object} options
+   *   The message context.
+   * @param {string} options.type
+   *   The message type.
+   * @param {string} options.id
+   *   ID of the message, for reference.
+   *
+   * @return {HTMLElement}
+   *   A DOM Node.
+   */
+  Drupal.theme.message = ({ text }, { type, id }) => {
     const messagesTypes = Drupal.Message.getMessageTypeLabels();
     const messageWrapper = document.createElement('div');
+
     messageWrapper.setAttribute('class', `messages messages--${type}`);
-    messageWrapper.setAttribute('role', type === 'error' || type === 'warning' ? 'alert' : 'status');
+    messageWrapper.setAttribute(
+      'role',
+      type === 'error' || type === 'warning' ? 'alert' : 'status',
+    );
     messageWrapper.setAttribute('data-drupal-message-id', id);
     messageWrapper.setAttribute('data-drupal-message-type', type);
+
     messageWrapper.setAttribute('aria-label', messagesTypes[type]);
+
     messageWrapper.innerHTML = `${text}`;
+
     return messageWrapper;
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/misc/position.es6.js b/core/misc/position.es6.js
deleted file mode 100644
index a42f2331f249..000000000000
--- a/core/misc/position.es6.js
+++ /dev/null
@@ -1,628 +0,0 @@
-/**
- * @file
- * A modified version of jQuery UI position.
- *
- * Per jQuery UI's public domain license, it is permissible to run modified
- * versions of their code. This file offers the same functionality as what is
- * provided by jQuery UI position, but refactored to meet Drupal coding
- * standards, and restructured so it extends jQuery core instead of jQuery UI.
- *
- * This is provided to support pre-existing code that expects the jQuery
- * position API.
- *
- * @see https://github.com/jquery/jquery-ui/blob/1.12.1/LICENSE.txt
- * @see https://raw.githubusercontent.com/jquery/jquery-ui/1.12.1/ui/position.js
- */
-
-/**
- * This provides ported version of jQuery UI position, refactored to not depend
- * on jQuery UI and to meet Drupal JavaScript coding standards. Functionality
- * and usage is identical. It positions an element relative to another. The
- * `position()` function can be called by any jQuery object. Additional details
- * on using `position()` are provided in this file in the docblock for
- * $.fn.position.
- */
-(($) => {
-  let cachedScrollbarWidth = null;
-  const { max, abs } = Math;
-  const regexHorizontal = /left|center|right/;
-  const regexVertical = /top|center|bottom/;
-  const regexOffset = /[+-]\d+(\.[\d]+)?%?/;
-  const regexPosition = /^\w+/;
-  const regexPercent = /%$/;
-  const _position = $.fn.position;
-
-  function getOffsets(offsets, width, height) {
-    return [
-      parseFloat(offsets[0]) *
-        (regexPercent.test(offsets[0]) ? width / 100 : 1),
-      parseFloat(offsets[1]) *
-        (regexPercent.test(offsets[1]) ? height / 100 : 1),
-    ];
-  }
-
-  function parseCss(element, property) {
-    return parseInt($.css(element, property), 10) || 0;
-  }
-
-  function getDimensions(elem) {
-    const raw = elem[0];
-    if (raw.nodeType === 9) {
-      return {
-        width: elem.width(),
-        height: elem.height(),
-        offset: { top: 0, left: 0 },
-      };
-    }
-    if ($.isWindow(raw)) {
-      return {
-        width: elem.width(),
-        height: elem.height(),
-        offset: { top: elem.scrollTop(), left: elem.scrollLeft() },
-      };
-    }
-    if (raw.preventDefault) {
-      return {
-        width: 0,
-        height: 0,
-        offset: { top: raw.pageY, left: raw.pageX },
-      };
-    }
-    return {
-      width: elem.outerWidth(),
-      height: elem.outerHeight(),
-      offset: elem.offset(),
-    };
-  }
-
-  const collisions = {
-    fit: {
-      left(position, data) {
-        const { within } = data;
-        const withinOffset = within.isWindow
-          ? within.scrollLeft
-          : within.offset.left;
-        const outerWidth = within.width;
-        const collisionPosLeft =
-          position.left - data.collisionPosition.marginLeft;
-        const overLeft = withinOffset - collisionPosLeft;
-        const overRight =
-          collisionPosLeft + data.collisionWidth - outerWidth - withinOffset;
-        let newOverRight;
-
-        // Element is wider than within
-        if (data.collisionWidth > outerWidth) {
-          // Element is initially over the left side of within
-          if (overLeft > 0 && overRight <= 0) {
-            newOverRight =
-              position.left +
-              overLeft +
-              data.collisionWidth -
-              outerWidth -
-              withinOffset;
-            position.left += overLeft - newOverRight;
-
-            // Element is initially over right side of within
-          } else if (overRight > 0 && overLeft <= 0) {
-            position.left = withinOffset;
-
-            // Element is initially over both left and right sides of within
-          } else if (overLeft > overRight) {
-            position.left = withinOffset + outerWidth - data.collisionWidth;
-          } else {
-            position.left = withinOffset;
-          }
-
-          // Too far left -> align with left edge
-        } else if (overLeft > 0) {
-          position.left += overLeft;
-
-          // Too far right -> align with right edge
-        } else if (overRight > 0) {
-          position.left -= overRight;
-
-          // Adjust based on position and margin
-        } else {
-          position.left = max(position.left - collisionPosLeft, position.left);
-        }
-      },
-      top(position, data) {
-        const { within } = data;
-        const withinOffset = within.isWindow
-          ? within.scrollTop
-          : within.offset.top;
-        const outerHeight = data.within.height;
-        const collisionPosTop = position.top - data.collisionPosition.marginTop;
-        const overTop = withinOffset - collisionPosTop;
-        const overBottom =
-          collisionPosTop + data.collisionHeight - outerHeight - withinOffset;
-        let newOverBottom;
-
-        // Element is taller than within
-        if (data.collisionHeight > outerHeight) {
-          // Element is initially over the top of within
-          if (overTop > 0 && overBottom <= 0) {
-            newOverBottom =
-              position.top +
-              overTop +
-              data.collisionHeight -
-              outerHeight -
-              withinOffset;
-            position.top += overTop - newOverBottom;
-
-            // Element is initially over bottom of within
-          } else if (overBottom > 0 && overTop <= 0) {
-            position.top = withinOffset;
-
-            // Element is initially over both top and bottom of within
-          } else if (overTop > overBottom) {
-            position.top = withinOffset + outerHeight - data.collisionHeight;
-          } else {
-            position.top = withinOffset;
-          }
-
-          // Too far up -> align with top
-        } else if (overTop > 0) {
-          position.top += overTop;
-
-          // Too far down -> align with bottom edge
-        } else if (overBottom > 0) {
-          position.top -= overBottom;
-
-          // Adjust based on position and margin
-        } else {
-          position.top = max(position.top - collisionPosTop, position.top);
-        }
-      },
-    },
-    flip: {
-      left(position, data) {
-        const { within } = data;
-        const withinOffset = within.offset.left + within.scrollLeft;
-        const outerWidth = within.width;
-        const offsetLeft = within.isWindow
-          ? within.scrollLeft
-          : within.offset.left;
-        const collisionPosLeft =
-          position.left - data.collisionPosition.marginLeft;
-        const overLeft = collisionPosLeft - offsetLeft;
-        const overRight =
-          collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft;
-        const myOffset =
-          // eslint-disable-next-line no-nested-ternary
-          data.my[0] === 'left'
-            ? -data.elemWidth
-            : data.my[0] === 'right'
-            ? data.elemWidth
-            : 0;
-        const atOffset =
-          // eslint-disable-next-line no-nested-ternary
-          data.at[0] === 'left'
-            ? data.targetWidth
-            : data.at[0] === 'right'
-            ? -data.targetWidth
-            : 0;
-        const offset = -2 * data.offset[0];
-        let newOverRight;
-        let newOverLeft;
-
-        if (overLeft < 0) {
-          newOverRight =
-            position.left +
-            myOffset +
-            atOffset +
-            offset +
-            data.collisionWidth -
-            outerWidth -
-            withinOffset;
-          if (newOverRight < 0 || newOverRight < abs(overLeft)) {
-            position.left += myOffset + atOffset + offset;
-          }
-        } else if (overRight > 0) {
-          newOverLeft =
-            position.left -
-            data.collisionPosition.marginLeft +
-            myOffset +
-            atOffset +
-            offset -
-            offsetLeft;
-          if (newOverLeft > 0 || abs(newOverLeft) < overRight) {
-            position.left += myOffset + atOffset + offset;
-          }
-        }
-      },
-      top(position, data) {
-        const { within } = data;
-        const withinOffset = within.offset.top + within.scrollTop;
-        const outerHeight = within.height;
-        const offsetTop = within.isWindow
-          ? within.scrollTop
-          : within.offset.top;
-        const collisionPosTop = position.top - data.collisionPosition.marginTop;
-        const overTop = collisionPosTop - offsetTop;
-        const overBottom =
-          collisionPosTop + data.collisionHeight - outerHeight - offsetTop;
-        const top = data.my[1] === 'top';
-        // eslint-disable-next-line no-nested-ternary
-        const myOffset = top
-          ? -data.elemHeight
-          : data.my[1] === 'bottom'
-          ? data.elemHeight
-          : 0;
-        const atOffset =
-          // eslint-disable-next-line no-nested-ternary
-          data.at[1] === 'top'
-            ? data.targetHeight
-            : data.at[1] === 'bottom'
-            ? -data.targetHeight
-            : 0;
-        const offset = -2 * data.offset[1];
-        let newOverTop;
-        let newOverBottom;
-        if (overTop < 0) {
-          newOverBottom =
-            position.top +
-            myOffset +
-            atOffset +
-            offset +
-            data.collisionHeight -
-            outerHeight -
-            withinOffset;
-          if (newOverBottom < 0 || newOverBottom < abs(overTop)) {
-            position.top += myOffset + atOffset + offset;
-          }
-        } else if (overBottom > 0) {
-          newOverTop =
-            position.top -
-            data.collisionPosition.marginTop +
-            myOffset +
-            atOffset +
-            offset -
-            offsetTop;
-          if (newOverTop > 0 || abs(newOverTop) < overBottom) {
-            position.top += myOffset + atOffset + offset;
-          }
-        }
-      },
-    },
-    flipfit: {
-      left(...args) {
-        collisions.flip.left.apply(this, args);
-        collisions.fit.left.apply(this, args);
-      },
-      top(...args) {
-        collisions.flip.top.apply(this, args);
-        collisions.fit.top.apply(this, args);
-      },
-    },
-  };
-
-  $.position = {
-    scrollbarWidth() {
-      if (cachedScrollbarWidth !== undefined) {
-        return cachedScrollbarWidth;
-      }
-      const div = $(
-        '<div ' +
-          "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
-          "<div style='height:100px;width:auto;'></div></div>",
-      );
-      const innerDiv = div.children()[0];
-
-      $('body').append(div);
-      const w1 = innerDiv.offsetWidth;
-      div.css('overflow', 'scroll');
-
-      let w2 = innerDiv.offsetWidth;
-
-      if (w1 === w2) {
-        w2 = div[0].clientWidth;
-      }
-
-      div.remove();
-      cachedScrollbarWidth = w1 - w2;
-      return cachedScrollbarWidth;
-    },
-    getScrollInfo(within) {
-      const overflowX =
-        within.isWindow || within.isDocument
-          ? ''
-          : within.element.css('overflow-x');
-      const overflowY =
-        within.isWindow || within.isDocument
-          ? ''
-          : within.element.css('overflow-y');
-      const hasOverflowX =
-        overflowX === 'scroll' ||
-        (overflowX === 'auto' && within.width < within.element[0].scrollWidth);
-      const hasOverflowY =
-        overflowY === 'scroll' ||
-        (overflowY === 'auto' &&
-          within.height < within.element[0].scrollHeight);
-      return {
-        width: hasOverflowY ? $.position.scrollbarWidth() : 0,
-        height: hasOverflowX ? $.position.scrollbarWidth() : 0,
-      };
-    },
-    getWithinInfo(element) {
-      const withinElement = $(element || window);
-      const isWindow = $.isWindow(withinElement[0]);
-      const isDocument = !!withinElement[0] && withinElement[0].nodeType === 9;
-      const hasOffset = !isWindow && !isDocument;
-      return {
-        element: withinElement,
-        isWindow,
-        isDocument,
-        offset: hasOffset ? $(element).offset() : { left: 0, top: 0 },
-        scrollLeft: withinElement.scrollLeft(),
-        scrollTop: withinElement.scrollTop(),
-        width: withinElement.outerWidth(),
-        height: withinElement.outerHeight(),
-      };
-    },
-  };
-
-  // eslint-disable-next-line func-names
-  /**
-   * Positions an element relative to another.
-   *
-   * The following documentation is originally from
-   * {@link https://api.jqueryui.com/position/}.
-   *
-   * @param {Object} options - the options object.
-   * @param {string} options.my - Defines which position on the element being
-   *   positioned to align with the target element: "horizontal vertical"
-   *   alignment. A single value such as "right" will be normalized to "right
-   *   center", "top" will be normalized to "center top" (following CSS
-   *   convention). Acceptable horizontal values: "left", "center", "right".
-   *   Acceptable vertical values: "top", "center", "bottom". Example: "left
-   *   top" or "center center". Each dimension can also contain offsets, in
-   *   pixels or percent, e.g., "right+10 top-25%". Percentage offsets are
-   *   relative to the element being positioned. Default value is "center".
-   * @param {string} options.at - Defines which position on the target element
-   *   to align the positioned element against: "horizontal vertical" alignment.
-   *   See the `my` option for full details on possible values. Percentage
-   *   offsets are relative to the target element. Default value is "center".
-   * @param {string|Element|jQuery|Event|null} options.of - Which element to
-   *   position against. If you provide a selector or jQuery object, the first
-   *   matching element will be used. If you provide an event object, the pageX
-   *   and pageY properties will be used. Example: "#top-menu". Default value is
-   *   null.
-   * @param {string} options.collision - When the positioned element overflows
-   *   the window in some direction, move it to an alternative position. Similar
-   *   to `my` and `at`, this accepts a single value or a pair for
-   *   horizontal/vertical, e.g., "flip", "fit", "fit flip", "fit none". Default
-   *   value is "flip". The options work as follows:
-   *   - "flip": Flips the element to the opposite side of the target and the
-   *     collision detection is run again to see if it will fit. Whichever side
-   *     allows more of the element to be visible will be used.
-   *   - "fit": Shift the element away from the edge of the window.
-   *   - "flipfit": First applies the flip logic, placing the element on
-   *     whichever side allows more of the element to be visible. Then the fit
-   *     logic is applied to ensure as much of the element is visible as
-   *     possible.
-   *     "none": Does not apply any collision detection.
-   * @param {function|null} options.using - When specified, the actual property
-   *   setting is delegated to this callback. Receives two parameters: The first
-   *   is a hash of top and left values for the position that should be set and
-   *   can be forwarded to .css() or .animate().The second provides feedback
-   *   about the position and dimensions of both elements, as well as
-   *   calculations to their relative position. Both target and element have
-   *   these properties: element, left, top, width, height. In addition, there's
-   *   horizontal, vertical and important, providing twelve potential directions
-   *   like { horizontal: "center", vertical: "left", important: "horizontal" }.
-   *   Default value is null.
-   * @param {string|Element|jQuery} options.within - Element to position within,
-   *   affecting collision detection. If you provide a selector or jQuery
-   *   object, the first matching element will be used. Default value is window.
-   *
-   * @return {jQuery}
-   *  The jQuery object that called called this function.
-   */
-  $.fn.position = function (options) {
-    if (!options || !options.of) {
-      // eslint-disable-next-line prefer-rest-params
-      return _position.apply(this, arguments);
-    }
-
-    // Make a copy, we don't want to modify arguments
-    options = $.extend({}, options);
-
-    const within = $.position.getWithinInfo(options.within);
-    const scrollInfo = $.position.getScrollInfo(within);
-    const collision = (options.collision || 'flip').split(' ');
-    const offsets = {};
-
-    // Make sure string options are treated as CSS selectors
-    const target =
-      typeof options.of === 'string'
-        ? $(document).find(options.of)
-        : $(options.of);
-    const dimensions = getDimensions(target);
-    const targetWidth = dimensions.width;
-    const targetHeight = dimensions.height;
-    const targetOffset = dimensions.offset;
-
-    if (target[0].preventDefault) {
-      // Force left top to allow flipping
-      options.at = 'left top';
-    }
-
-    // Clone to reuse original targetOffset later
-    const basePosition = $.extend({}, targetOffset);
-
-    // Force my and at to have valid horizontal and vertical positions
-    // if a value is missing or invalid, it will be converted to center
-    // eslint-disable-next-line func-names
-    $.each(['my', 'at'], function () {
-      let pos = (options[this] || '').split(' ');
-
-      if (pos.length === 1) {
-        // eslint-disable-next-line no-nested-ternary
-        pos = regexHorizontal.test(pos[0])
-          ? pos.concat(['center'])
-          : regexVertical.test(pos[0])
-          ? ['center'].concat(pos)
-          : ['center', 'center'];
-      }
-      pos[0] = regexHorizontal.test(pos[0]) ? pos[0] : 'center';
-      pos[1] = regexVertical.test(pos[1]) ? pos[1] : 'center';
-
-      // Calculate offsets
-      const horizontalOffset = regexOffset.exec(pos[0]);
-      const verticalOffset = regexOffset.exec(pos[1]);
-      offsets[this] = [
-        horizontalOffset ? horizontalOffset[0] : 0,
-        verticalOffset ? verticalOffset[0] : 0,
-      ];
-
-      // Reduce to just the positions without the offsets
-      options[this] = [
-        regexPosition.exec(pos[0])[0],
-        regexPosition.exec(pos[1])[0],
-      ];
-    });
-
-    // Normalize collision option
-    if (collision.length === 1) {
-      // eslint-disable-next-line prefer-destructuring
-      collision[1] = collision[0];
-    }
-
-    if (options.at[0] === 'right') {
-      basePosition.left += targetWidth;
-    } else if (options.at[0] === 'center') {
-      basePosition.left += targetWidth / 2;
-    }
-
-    if (options.at[1] === 'bottom') {
-      basePosition.top += targetHeight;
-    } else if (options.at[1] === 'center') {
-      basePosition.top += targetHeight / 2;
-    }
-
-    const atOffset = getOffsets(offsets.at, targetWidth, targetHeight);
-    basePosition.left += atOffset[0];
-    basePosition.top += atOffset[1];
-
-    // eslint-disable-next-line func-names
-    return this.each(function () {
-      let using;
-      const elem = $(this);
-      const elemWidth = elem.outerWidth();
-      const elemHeight = elem.outerHeight();
-      const marginLeft = parseCss(this, 'marginLeft');
-      const marginTop = parseCss(this, 'marginTop');
-      const collisionWidth =
-        elemWidth +
-        marginLeft +
-        parseCss(this, 'marginRight') +
-        scrollInfo.width;
-      const collisionHeight =
-        elemHeight +
-        marginTop +
-        parseCss(this, 'marginBottom') +
-        scrollInfo.height;
-      const position = $.extend({}, basePosition);
-      const myOffset = getOffsets(
-        offsets.my,
-        elem.outerWidth(),
-        elem.outerHeight(),
-      );
-
-      if (options.my[0] === 'right') {
-        position.left -= elemWidth;
-      } else if (options.my[0] === 'center') {
-        position.left -= elemWidth / 2;
-      }
-
-      if (options.my[1] === 'bottom') {
-        position.top -= elemHeight;
-      } else if (options.my[1] === 'center') {
-        position.top -= elemHeight / 2;
-      }
-
-      position.left += myOffset[0];
-      position.top += myOffset[1];
-
-      const collisionPosition = {
-        marginLeft,
-        marginTop,
-      };
-
-      // eslint-disable-next-line func-names
-      $.each(['left', 'top'], function (i, dir) {
-        if (collisions[collision[i]]) {
-          collisions[collision[i]][dir](position, {
-            targetWidth,
-            targetHeight,
-            elemWidth,
-            elemHeight,
-            collisionPosition,
-            collisionWidth,
-            collisionHeight,
-            offset: [atOffset[0] + myOffset[0], atOffset[1] + myOffset[1]],
-            my: options.my,
-            at: options.at,
-            within,
-            elem,
-          });
-        }
-      });
-
-      if (options.using) {
-        // Adds feedback as second argument to using callback, if present
-        // eslint-disable-next-line func-names
-        using = function (props) {
-          const left = targetOffset.left - position.left;
-          const right = left + targetWidth - elemWidth;
-          const top = targetOffset.top - position.top;
-          const bottom = top + targetHeight - elemHeight;
-          const feedback = {
-            target: {
-              element: target,
-              left: targetOffset.left,
-              top: targetOffset.top,
-              width: targetWidth,
-              height: targetHeight,
-            },
-            element: {
-              element: elem,
-              left: position.left,
-              top: position.top,
-              width: elemWidth,
-              height: elemHeight,
-            },
-            // eslint-disable-next-line no-nested-ternary
-            horizontal: right < 0 ? 'left' : left > 0 ? 'right' : 'center',
-            // eslint-disable-next-line no-nested-ternary
-            vertical: bottom < 0 ? 'top' : top > 0 ? 'bottom' : 'middle',
-          };
-          if (targetWidth < elemWidth && abs(left + right) < targetWidth) {
-            feedback.horizontal = 'center';
-          }
-          if (targetHeight < elemHeight && abs(top + bottom) < targetHeight) {
-            feedback.vertical = 'middle';
-          }
-          if (max(abs(left), abs(right)) > max(abs(top), abs(bottom))) {
-            feedback.important = 'horizontal';
-          } else {
-            feedback.important = 'vertical';
-          }
-          options.using.call(this, props, feedback);
-        };
-      }
-
-      elem.offset($.extend(position, { using }));
-    });
-  };
-
-  // Although $.ui.position is not built to be called directly, some legacy code
-  // may have checks for the presence of $.ui.position, which can be used to
-  // confirm the presence of jQuery UI position's API, as opposed to the more
-  // limited version provided by jQuery.
-  if (!$.hasOwnProperty('ui')) {
-    $.ui = {};
-  }
-  $.ui.position = collisions;
-})(jQuery);
diff --git a/core/misc/position.js b/core/misc/position.js
index 6faf9c122fee..a42f2331f249 100644
--- a/core/misc/position.js
+++ b/core/misc/position.js
@@ -1,16 +1,30 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A modified version of jQuery UI position.
+ *
+ * Per jQuery UI's public domain license, it is permissible to run modified
+ * versions of their code. This file offers the same functionality as what is
+ * provided by jQuery UI position, but refactored to meet Drupal coding
+ * standards, and restructured so it extends jQuery core instead of jQuery UI.
+ *
+ * This is provided to support pre-existing code that expects the jQuery
+ * position API.
+ *
+ * @see https://github.com/jquery/jquery-ui/blob/1.12.1/LICENSE.txt
+ * @see https://raw.githubusercontent.com/jquery/jquery-ui/1.12.1/ui/position.js
+ */
 
-($ => {
+/**
+ * This provides ported version of jQuery UI position, refactored to not depend
+ * on jQuery UI and to meet Drupal JavaScript coding standards. Functionality
+ * and usage is identical. It positions an element relative to another. The
+ * `position()` function can be called by any jQuery object. Additional details
+ * on using `position()` are provided in this file in the docblock for
+ * $.fn.position.
+ */
+(($) => {
   let cachedScrollbarWidth = null;
-  const {
-    max,
-    abs
-  } = Math;
+  const { max, abs } = Math;
   const regexHorizontal = /left|center|right/;
   const regexVertical = /top|center|bottom/;
   const regexOffset = /[+-]\d+(\.[\d]+)?%?/;
@@ -19,7 +33,12 @@
   const _position = $.fn.position;
 
   function getOffsets(offsets, width, height) {
-    return [parseFloat(offsets[0]) * (regexPercent.test(offsets[0]) ? width / 100 : 1), parseFloat(offsets[1]) * (regexPercent.test(offsets[1]) ? height / 100 : 1)];
+    return [
+      parseFloat(offsets[0]) *
+        (regexPercent.test(offsets[0]) ? width / 100 : 1),
+      parseFloat(offsets[1]) *
+        (regexPercent.test(offsets[1]) ? height / 100 : 1),
+    ];
   }
 
   function parseCss(element, property) {
@@ -28,209 +47,272 @@
 
   function getDimensions(elem) {
     const raw = elem[0];
-
     if (raw.nodeType === 9) {
       return {
         width: elem.width(),
         height: elem.height(),
-        offset: {
-          top: 0,
-          left: 0
-        }
+        offset: { top: 0, left: 0 },
       };
     }
-
     if ($.isWindow(raw)) {
       return {
         width: elem.width(),
         height: elem.height(),
-        offset: {
-          top: elem.scrollTop(),
-          left: elem.scrollLeft()
-        }
+        offset: { top: elem.scrollTop(), left: elem.scrollLeft() },
       };
     }
-
     if (raw.preventDefault) {
       return {
         width: 0,
         height: 0,
-        offset: {
-          top: raw.pageY,
-          left: raw.pageX
-        }
+        offset: { top: raw.pageY, left: raw.pageX },
       };
     }
-
     return {
       width: elem.outerWidth(),
       height: elem.outerHeight(),
-      offset: elem.offset()
+      offset: elem.offset(),
     };
   }
 
   const collisions = {
     fit: {
       left(position, data) {
-        const {
-          within
-        } = data;
-        const withinOffset = within.isWindow ? within.scrollLeft : within.offset.left;
+        const { within } = data;
+        const withinOffset = within.isWindow
+          ? within.scrollLeft
+          : within.offset.left;
         const outerWidth = within.width;
-        const collisionPosLeft = position.left - data.collisionPosition.marginLeft;
+        const collisionPosLeft =
+          position.left - data.collisionPosition.marginLeft;
         const overLeft = withinOffset - collisionPosLeft;
-        const overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset;
+        const overRight =
+          collisionPosLeft + data.collisionWidth - outerWidth - withinOffset;
         let newOverRight;
 
+        // Element is wider than within
         if (data.collisionWidth > outerWidth) {
+          // Element is initially over the left side of within
           if (overLeft > 0 && overRight <= 0) {
-            newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
+            newOverRight =
+              position.left +
+              overLeft +
+              data.collisionWidth -
+              outerWidth -
+              withinOffset;
             position.left += overLeft - newOverRight;
+
+            // Element is initially over right side of within
           } else if (overRight > 0 && overLeft <= 0) {
             position.left = withinOffset;
+
+            // Element is initially over both left and right sides of within
           } else if (overLeft > overRight) {
             position.left = withinOffset + outerWidth - data.collisionWidth;
           } else {
             position.left = withinOffset;
           }
+
+          // Too far left -> align with left edge
         } else if (overLeft > 0) {
           position.left += overLeft;
+
+          // Too far right -> align with right edge
         } else if (overRight > 0) {
           position.left -= overRight;
+
+          // Adjust based on position and margin
         } else {
           position.left = max(position.left - collisionPosLeft, position.left);
         }
       },
-
       top(position, data) {
-        const {
-          within
-        } = data;
-        const withinOffset = within.isWindow ? within.scrollTop : within.offset.top;
+        const { within } = data;
+        const withinOffset = within.isWindow
+          ? within.scrollTop
+          : within.offset.top;
         const outerHeight = data.within.height;
         const collisionPosTop = position.top - data.collisionPosition.marginTop;
         const overTop = withinOffset - collisionPosTop;
-        const overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset;
+        const overBottom =
+          collisionPosTop + data.collisionHeight - outerHeight - withinOffset;
         let newOverBottom;
 
+        // Element is taller than within
         if (data.collisionHeight > outerHeight) {
+          // Element is initially over the top of within
           if (overTop > 0 && overBottom <= 0) {
-            newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
+            newOverBottom =
+              position.top +
+              overTop +
+              data.collisionHeight -
+              outerHeight -
+              withinOffset;
             position.top += overTop - newOverBottom;
+
+            // Element is initially over bottom of within
           } else if (overBottom > 0 && overTop <= 0) {
             position.top = withinOffset;
+
+            // Element is initially over both top and bottom of within
           } else if (overTop > overBottom) {
             position.top = withinOffset + outerHeight - data.collisionHeight;
           } else {
             position.top = withinOffset;
           }
+
+          // Too far up -> align with top
         } else if (overTop > 0) {
           position.top += overTop;
+
+          // Too far down -> align with bottom edge
         } else if (overBottom > 0) {
           position.top -= overBottom;
+
+          // Adjust based on position and margin
         } else {
           position.top = max(position.top - collisionPosTop, position.top);
         }
-      }
-
+      },
     },
     flip: {
       left(position, data) {
-        const {
-          within
-        } = data;
+        const { within } = data;
         const withinOffset = within.offset.left + within.scrollLeft;
         const outerWidth = within.width;
-        const offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left;
-        const collisionPosLeft = position.left - data.collisionPosition.marginLeft;
+        const offsetLeft = within.isWindow
+          ? within.scrollLeft
+          : within.offset.left;
+        const collisionPosLeft =
+          position.left - data.collisionPosition.marginLeft;
         const overLeft = collisionPosLeft - offsetLeft;
-        const overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft;
-        const myOffset = data.my[0] === 'left' ? -data.elemWidth : data.my[0] === 'right' ? data.elemWidth : 0;
-        const atOffset = data.at[0] === 'left' ? data.targetWidth : data.at[0] === 'right' ? -data.targetWidth : 0;
+        const overRight =
+          collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft;
+        const myOffset =
+          // eslint-disable-next-line no-nested-ternary
+          data.my[0] === 'left'
+            ? -data.elemWidth
+            : data.my[0] === 'right'
+            ? data.elemWidth
+            : 0;
+        const atOffset =
+          // eslint-disable-next-line no-nested-ternary
+          data.at[0] === 'left'
+            ? data.targetWidth
+            : data.at[0] === 'right'
+            ? -data.targetWidth
+            : 0;
         const offset = -2 * data.offset[0];
         let newOverRight;
         let newOverLeft;
 
         if (overLeft < 0) {
-          newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
-
+          newOverRight =
+            position.left +
+            myOffset +
+            atOffset +
+            offset +
+            data.collisionWidth -
+            outerWidth -
+            withinOffset;
           if (newOverRight < 0 || newOverRight < abs(overLeft)) {
             position.left += myOffset + atOffset + offset;
           }
         } else if (overRight > 0) {
-          newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
-
+          newOverLeft =
+            position.left -
+            data.collisionPosition.marginLeft +
+            myOffset +
+            atOffset +
+            offset -
+            offsetLeft;
           if (newOverLeft > 0 || abs(newOverLeft) < overRight) {
             position.left += myOffset + atOffset + offset;
           }
         }
       },
-
       top(position, data) {
-        const {
-          within
-        } = data;
+        const { within } = data;
         const withinOffset = within.offset.top + within.scrollTop;
         const outerHeight = within.height;
-        const offsetTop = within.isWindow ? within.scrollTop : within.offset.top;
+        const offsetTop = within.isWindow
+          ? within.scrollTop
+          : within.offset.top;
         const collisionPosTop = position.top - data.collisionPosition.marginTop;
         const overTop = collisionPosTop - offsetTop;
-        const overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop;
+        const overBottom =
+          collisionPosTop + data.collisionHeight - outerHeight - offsetTop;
         const top = data.my[1] === 'top';
-        const myOffset = top ? -data.elemHeight : data.my[1] === 'bottom' ? data.elemHeight : 0;
-        const atOffset = data.at[1] === 'top' ? data.targetHeight : data.at[1] === 'bottom' ? -data.targetHeight : 0;
+        // eslint-disable-next-line no-nested-ternary
+        const myOffset = top
+          ? -data.elemHeight
+          : data.my[1] === 'bottom'
+          ? data.elemHeight
+          : 0;
+        const atOffset =
+          // eslint-disable-next-line no-nested-ternary
+          data.at[1] === 'top'
+            ? data.targetHeight
+            : data.at[1] === 'bottom'
+            ? -data.targetHeight
+            : 0;
         const offset = -2 * data.offset[1];
         let newOverTop;
         let newOverBottom;
-
         if (overTop < 0) {
-          newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
-
+          newOverBottom =
+            position.top +
+            myOffset +
+            atOffset +
+            offset +
+            data.collisionHeight -
+            outerHeight -
+            withinOffset;
           if (newOverBottom < 0 || newOverBottom < abs(overTop)) {
             position.top += myOffset + atOffset + offset;
           }
         } else if (overBottom > 0) {
-          newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
-
+          newOverTop =
+            position.top -
+            data.collisionPosition.marginTop +
+            myOffset +
+            atOffset +
+            offset -
+            offsetTop;
           if (newOverTop > 0 || abs(newOverTop) < overBottom) {
             position.top += myOffset + atOffset + offset;
           }
         }
-      }
-
+      },
     },
     flipfit: {
-      left() {
-        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
-          args[_key] = arguments[_key];
-        }
-
+      left(...args) {
         collisions.flip.left.apply(this, args);
         collisions.fit.left.apply(this, args);
       },
-
-      top() {
-        for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
-          args[_key2] = arguments[_key2];
-        }
-
+      top(...args) {
         collisions.flip.top.apply(this, args);
         collisions.fit.top.apply(this, args);
-      }
-
-    }
+      },
+    },
   };
+
   $.position = {
     scrollbarWidth() {
       if (cachedScrollbarWidth !== undefined) {
         return cachedScrollbarWidth;
       }
-
-      const div = $('<div ' + "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" + "<div style='height:100px;width:auto;'></div></div>");
+      const div = $(
+        '<div ' +
+          "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
+          "<div style='height:100px;width:auto;'></div></div>",
+      );
       const innerDiv = div.children()[0];
+
       $('body').append(div);
       const w1 = innerDiv.offsetWidth;
       div.css('overflow', 'scroll');
+
       let w2 = innerDiv.offsetWidth;
 
       if (w1 === w2) {
@@ -241,18 +323,27 @@
       cachedScrollbarWidth = w1 - w2;
       return cachedScrollbarWidth;
     },
-
     getScrollInfo(within) {
-      const overflowX = within.isWindow || within.isDocument ? '' : within.element.css('overflow-x');
-      const overflowY = within.isWindow || within.isDocument ? '' : within.element.css('overflow-y');
-      const hasOverflowX = overflowX === 'scroll' || overflowX === 'auto' && within.width < within.element[0].scrollWidth;
-      const hasOverflowY = overflowY === 'scroll' || overflowY === 'auto' && within.height < within.element[0].scrollHeight;
+      const overflowX =
+        within.isWindow || within.isDocument
+          ? ''
+          : within.element.css('overflow-x');
+      const overflowY =
+        within.isWindow || within.isDocument
+          ? ''
+          : within.element.css('overflow-y');
+      const hasOverflowX =
+        overflowX === 'scroll' ||
+        (overflowX === 'auto' && within.width < within.element[0].scrollWidth);
+      const hasOverflowY =
+        overflowY === 'scroll' ||
+        (overflowY === 'auto' &&
+          within.height < within.element[0].scrollHeight);
       return {
         width: hasOverflowY ? $.position.scrollbarWidth() : 0,
-        height: hasOverflowX ? $.position.scrollbarWidth() : 0
+        height: hasOverflowX ? $.position.scrollbarWidth() : 0,
       };
     },
-
     getWithinInfo(element) {
       const withinElement = $(element || window);
       const isWindow = $.isWindow(withinElement[0]);
@@ -262,56 +353,139 @@
         element: withinElement,
         isWindow,
         isDocument,
-        offset: hasOffset ? $(element).offset() : {
-          left: 0,
-          top: 0
-        },
+        offset: hasOffset ? $(element).offset() : { left: 0, top: 0 },
         scrollLeft: withinElement.scrollLeft(),
         scrollTop: withinElement.scrollTop(),
         width: withinElement.outerWidth(),
-        height: withinElement.outerHeight()
+        height: withinElement.outerHeight(),
       };
-    }
-
+    },
   };
 
+  // eslint-disable-next-line func-names
+  /**
+   * Positions an element relative to another.
+   *
+   * The following documentation is originally from
+   * {@link https://api.jqueryui.com/position/}.
+   *
+   * @param {Object} options - the options object.
+   * @param {string} options.my - Defines which position on the element being
+   *   positioned to align with the target element: "horizontal vertical"
+   *   alignment. A single value such as "right" will be normalized to "right
+   *   center", "top" will be normalized to "center top" (following CSS
+   *   convention). Acceptable horizontal values: "left", "center", "right".
+   *   Acceptable vertical values: "top", "center", "bottom". Example: "left
+   *   top" or "center center". Each dimension can also contain offsets, in
+   *   pixels or percent, e.g., "right+10 top-25%". Percentage offsets are
+   *   relative to the element being positioned. Default value is "center".
+   * @param {string} options.at - Defines which position on the target element
+   *   to align the positioned element against: "horizontal vertical" alignment.
+   *   See the `my` option for full details on possible values. Percentage
+   *   offsets are relative to the target element. Default value is "center".
+   * @param {string|Element|jQuery|Event|null} options.of - Which element to
+   *   position against. If you provide a selector or jQuery object, the first
+   *   matching element will be used. If you provide an event object, the pageX
+   *   and pageY properties will be used. Example: "#top-menu". Default value is
+   *   null.
+   * @param {string} options.collision - When the positioned element overflows
+   *   the window in some direction, move it to an alternative position. Similar
+   *   to `my` and `at`, this accepts a single value or a pair for
+   *   horizontal/vertical, e.g., "flip", "fit", "fit flip", "fit none". Default
+   *   value is "flip". The options work as follows:
+   *   - "flip": Flips the element to the opposite side of the target and the
+   *     collision detection is run again to see if it will fit. Whichever side
+   *     allows more of the element to be visible will be used.
+   *   - "fit": Shift the element away from the edge of the window.
+   *   - "flipfit": First applies the flip logic, placing the element on
+   *     whichever side allows more of the element to be visible. Then the fit
+   *     logic is applied to ensure as much of the element is visible as
+   *     possible.
+   *     "none": Does not apply any collision detection.
+   * @param {function|null} options.using - When specified, the actual property
+   *   setting is delegated to this callback. Receives two parameters: The first
+   *   is a hash of top and left values for the position that should be set and
+   *   can be forwarded to .css() or .animate().The second provides feedback
+   *   about the position and dimensions of both elements, as well as
+   *   calculations to their relative position. Both target and element have
+   *   these properties: element, left, top, width, height. In addition, there's
+   *   horizontal, vertical and important, providing twelve potential directions
+   *   like { horizontal: "center", vertical: "left", important: "horizontal" }.
+   *   Default value is null.
+   * @param {string|Element|jQuery} options.within - Element to position within,
+   *   affecting collision detection. If you provide a selector or jQuery
+   *   object, the first matching element will be used. Default value is window.
+   *
+   * @return {jQuery}
+   *  The jQuery object that called called this function.
+   */
   $.fn.position = function (options) {
     if (!options || !options.of) {
+      // eslint-disable-next-line prefer-rest-params
       return _position.apply(this, arguments);
     }
 
+    // Make a copy, we don't want to modify arguments
     options = $.extend({}, options);
+
     const within = $.position.getWithinInfo(options.within);
     const scrollInfo = $.position.getScrollInfo(within);
     const collision = (options.collision || 'flip').split(' ');
     const offsets = {};
-    const target = typeof options.of === 'string' ? $(document).find(options.of) : $(options.of);
+
+    // Make sure string options are treated as CSS selectors
+    const target =
+      typeof options.of === 'string'
+        ? $(document).find(options.of)
+        : $(options.of);
     const dimensions = getDimensions(target);
     const targetWidth = dimensions.width;
     const targetHeight = dimensions.height;
     const targetOffset = dimensions.offset;
 
     if (target[0].preventDefault) {
+      // Force left top to allow flipping
       options.at = 'left top';
     }
 
+    // Clone to reuse original targetOffset later
     const basePosition = $.extend({}, targetOffset);
+
+    // Force my and at to have valid horizontal and vertical positions
+    // if a value is missing or invalid, it will be converted to center
+    // eslint-disable-next-line func-names
     $.each(['my', 'at'], function () {
       let pos = (options[this] || '').split(' ');
 
       if (pos.length === 1) {
-        pos = regexHorizontal.test(pos[0]) ? pos.concat(['center']) : regexVertical.test(pos[0]) ? ['center'].concat(pos) : ['center', 'center'];
+        // eslint-disable-next-line no-nested-ternary
+        pos = regexHorizontal.test(pos[0])
+          ? pos.concat(['center'])
+          : regexVertical.test(pos[0])
+          ? ['center'].concat(pos)
+          : ['center', 'center'];
       }
-
       pos[0] = regexHorizontal.test(pos[0]) ? pos[0] : 'center';
       pos[1] = regexVertical.test(pos[1]) ? pos[1] : 'center';
+
+      // Calculate offsets
       const horizontalOffset = regexOffset.exec(pos[0]);
       const verticalOffset = regexOffset.exec(pos[1]);
-      offsets[this] = [horizontalOffset ? horizontalOffset[0] : 0, verticalOffset ? verticalOffset[0] : 0];
-      options[this] = [regexPosition.exec(pos[0])[0], regexPosition.exec(pos[1])[0]];
+      offsets[this] = [
+        horizontalOffset ? horizontalOffset[0] : 0,
+        verticalOffset ? verticalOffset[0] : 0,
+      ];
+
+      // Reduce to just the positions without the offsets
+      options[this] = [
+        regexPosition.exec(pos[0])[0],
+        regexPosition.exec(pos[1])[0],
+      ];
     });
 
+    // Normalize collision option
     if (collision.length === 1) {
+      // eslint-disable-next-line prefer-destructuring
       collision[1] = collision[0];
     }
 
@@ -330,6 +504,8 @@
     const atOffset = getOffsets(offsets.at, targetWidth, targetHeight);
     basePosition.left += atOffset[0];
     basePosition.top += atOffset[1];
+
+    // eslint-disable-next-line func-names
     return this.each(function () {
       let using;
       const elem = $(this);
@@ -337,10 +513,22 @@
       const elemHeight = elem.outerHeight();
       const marginLeft = parseCss(this, 'marginLeft');
       const marginTop = parseCss(this, 'marginTop');
-      const collisionWidth = elemWidth + marginLeft + parseCss(this, 'marginRight') + scrollInfo.width;
-      const collisionHeight = elemHeight + marginTop + parseCss(this, 'marginBottom') + scrollInfo.height;
+      const collisionWidth =
+        elemWidth +
+        marginLeft +
+        parseCss(this, 'marginRight') +
+        scrollInfo.width;
+      const collisionHeight =
+        elemHeight +
+        marginTop +
+        parseCss(this, 'marginBottom') +
+        scrollInfo.height;
       const position = $.extend({}, basePosition);
-      const myOffset = getOffsets(offsets.my, elem.outerWidth(), elem.outerHeight());
+      const myOffset = getOffsets(
+        offsets.my,
+        elem.outerWidth(),
+        elem.outerHeight(),
+      );
 
       if (options.my[0] === 'right') {
         position.left -= elemWidth;
@@ -356,10 +544,13 @@
 
       position.left += myOffset[0];
       position.top += myOffset[1];
+
       const collisionPosition = {
         marginLeft,
-        marginTop
+        marginTop,
       };
+
+      // eslint-disable-next-line func-names
       $.each(['left', 'top'], function (i, dir) {
         if (collisions[collision[i]]) {
           collisions[collision[i]][dir](position, {
@@ -374,12 +565,14 @@
             my: options.my,
             at: options.at,
             within,
-            elem
+            elem,
           });
         }
       });
 
       if (options.using) {
+        // Adds feedback as second argument to using callback, if present
+        // eslint-disable-next-line func-names
         using = function (props) {
           const left = targetOffset.left - position.left;
           const right = left + targetWidth - elemWidth;
@@ -391,46 +584,45 @@
               left: targetOffset.left,
               top: targetOffset.top,
               width: targetWidth,
-              height: targetHeight
+              height: targetHeight,
             },
             element: {
               element: elem,
               left: position.left,
               top: position.top,
               width: elemWidth,
-              height: elemHeight
+              height: elemHeight,
             },
+            // eslint-disable-next-line no-nested-ternary
             horizontal: right < 0 ? 'left' : left > 0 ? 'right' : 'center',
-            vertical: bottom < 0 ? 'top' : top > 0 ? 'bottom' : 'middle'
+            // eslint-disable-next-line no-nested-ternary
+            vertical: bottom < 0 ? 'top' : top > 0 ? 'bottom' : 'middle',
           };
-
           if (targetWidth < elemWidth && abs(left + right) < targetWidth) {
             feedback.horizontal = 'center';
           }
-
           if (targetHeight < elemHeight && abs(top + bottom) < targetHeight) {
             feedback.vertical = 'middle';
           }
-
           if (max(abs(left), abs(right)) > max(abs(top), abs(bottom))) {
             feedback.important = 'horizontal';
           } else {
             feedback.important = 'vertical';
           }
-
           options.using.call(this, props, feedback);
         };
       }
 
-      elem.offset($.extend(position, {
-        using
-      }));
+      elem.offset($.extend(position, { using }));
     });
   };
 
+  // Although $.ui.position is not built to be called directly, some legacy code
+  // may have checks for the presence of $.ui.position, which can be used to
+  // confirm the presence of jQuery UI position's API, as opposed to the more
+  // limited version provided by jQuery.
   if (!$.hasOwnProperty('ui')) {
     $.ui = {};
   }
-
   $.ui.position = collisions;
-})(jQuery);
\ No newline at end of file
+})(jQuery);
diff --git a/core/misc/progress.es6.js b/core/misc/progress.es6.js
deleted file mode 100644
index 24c13af0cc34..000000000000
--- a/core/misc/progress.es6.js
+++ /dev/null
@@ -1,180 +0,0 @@
-/**
- * @file
- * Progress bar.
- */
-
-(function ($, Drupal) {
-  /**
-   * Theme function for the progress bar.
-   *
-   * @param {string} id
-   *   The id for the progress bar.
-   *
-   * @return {string}
-   *   The HTML for the progress bar.
-   */
-  Drupal.theme.progressBar = function (id) {
-    return (
-      `<div id="${id}" class="progress" aria-live="polite">` +
-      '<div class="progress__label">&nbsp;</div>' +
-      '<div class="progress__track"><div class="progress__bar"></div></div>' +
-      '<div class="progress__percentage"></div>' +
-      '<div class="progress__description">&nbsp;</div>' +
-      '</div>'
-    );
-  };
-
-  /**
-   * A progressbar object. Initialized with the given id. Must be inserted into
-   * the DOM afterwards through progressBar.element.
-   *
-   * Method is the function which will perform the HTTP request to get the
-   * progress bar state. Either "GET" or "POST".
-   *
-   * @example
-   * pb = new Drupal.ProgressBar('myProgressBar');
-   * some_element.appendChild(pb.element);
-   *
-   * @constructor
-   *
-   * @param {string} id
-   *   The id for the progressbar.
-   * @param {function} updateCallback
-   *   Callback to run on update.
-   * @param {string} method
-   *   HTTP method to use.
-   * @param {function} errorCallback
-   *   Callback to call on error.
-   */
-  Drupal.ProgressBar = function (id, updateCallback, method, errorCallback) {
-    this.id = id;
-    this.method = method || 'GET';
-    this.updateCallback = updateCallback;
-    this.errorCallback = errorCallback;
-
-    // The WAI-ARIA setting aria-live="polite" will announce changes after
-    // users
-    // have completed their current activity and not interrupt the screen
-    // reader.
-    this.element = $(Drupal.theme('progressBar', id));
-  };
-
-  $.extend(
-    Drupal.ProgressBar.prototype,
-    /** @lends Drupal.ProgressBar# */ {
-      /**
-       * Set the percentage and status message for the progressbar.
-       *
-       * @param {number} percentage
-       *   The progress percentage.
-       * @param {string} message
-       *   The message to show the user.
-       * @param {string} label
-       *   The text for the progressbar label.
-       */
-      setProgress(percentage, message, label) {
-        if (percentage >= 0 && percentage <= 100) {
-          $(this.element)
-            .find('div.progress__bar')
-            .css('width', `${percentage}%`);
-          $(this.element)
-            .find('div.progress__percentage')
-            .html(`${percentage}%`);
-        }
-        $('div.progress__description', this.element).html(message);
-        $('div.progress__label', this.element).html(label);
-        if (this.updateCallback) {
-          this.updateCallback(percentage, message, this);
-        }
-      },
-
-      /**
-       * Start monitoring progress via Ajax.
-       *
-       * @param {string} uri
-       *   The URI to use for monitoring.
-       * @param {number} delay
-       *   The delay for calling the monitoring URI.
-       */
-      startMonitoring(uri, delay) {
-        this.delay = delay;
-        this.uri = uri;
-        this.sendPing();
-      },
-
-      /**
-       * Stop monitoring progress via Ajax.
-       */
-      stopMonitoring() {
-        clearTimeout(this.timer);
-        // This allows monitoring to be stopped from within the callback.
-        this.uri = null;
-      },
-
-      /**
-       * Request progress data from server.
-       */
-      sendPing() {
-        if (this.timer) {
-          clearTimeout(this.timer);
-        }
-        if (this.uri) {
-          const pb = this;
-          // When doing a post request, you need non-null data. Otherwise a
-          // HTTP 411 or HTTP 406 (with Apache mod_security) error may result.
-          let uri = this.uri;
-          if (uri.indexOf('?') === -1) {
-            uri += '?';
-          } else {
-            uri += '&';
-          }
-          uri += '_format=json';
-          $.ajax({
-            type: this.method,
-            url: uri,
-            data: '',
-            dataType: 'json',
-            success(progress) {
-              // Display errors.
-              if (progress.status === 0) {
-                pb.displayError(progress.data);
-                return;
-              }
-              // Update display.
-              pb.setProgress(
-                progress.percentage,
-                progress.message,
-                progress.label,
-              );
-              // Schedule next timer.
-              pb.timer = setTimeout(() => {
-                pb.sendPing();
-              }, pb.delay);
-            },
-            error(xmlhttp) {
-              const e = new Drupal.AjaxError(xmlhttp, pb.uri);
-              pb.displayError(`<pre>${e.message}</pre>`);
-            },
-          });
-        }
-      },
-
-      /**
-       * Display errors on the page.
-       *
-       * @param {string} string
-       *   The error message to show the user.
-       */
-      displayError(string) {
-        const error = $('<div class="messages messages--error"></div>').html(
-          string,
-        );
-        $(this.element).before(error).hide();
-
-        if (this.errorCallback) {
-          this.errorCallback(this);
-        }
-      },
-    },
-  );
-})(jQuery, Drupal);
diff --git a/core/misc/progress.js b/core/misc/progress.js
index 8c1a6ff3fb83..24c13af0cc34 100644
--- a/core/misc/progress.js
+++ b/core/misc/progress.js
@@ -1,100 +1,180 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Progress bar.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Theme function for the progress bar.
+   *
+   * @param {string} id
+   *   The id for the progress bar.
+   *
+   * @return {string}
+   *   The HTML for the progress bar.
+   */
   Drupal.theme.progressBar = function (id) {
-    return `<div id="${id}" class="progress" aria-live="polite">` + '<div class="progress__label">&nbsp;</div>' + '<div class="progress__track"><div class="progress__bar"></div></div>' + '<div class="progress__percentage"></div>' + '<div class="progress__description">&nbsp;</div>' + '</div>';
+    return (
+      `<div id="${id}" class="progress" aria-live="polite">` +
+      '<div class="progress__label">&nbsp;</div>' +
+      '<div class="progress__track"><div class="progress__bar"></div></div>' +
+      '<div class="progress__percentage"></div>' +
+      '<div class="progress__description">&nbsp;</div>' +
+      '</div>'
+    );
   };
 
+  /**
+   * A progressbar object. Initialized with the given id. Must be inserted into
+   * the DOM afterwards through progressBar.element.
+   *
+   * Method is the function which will perform the HTTP request to get the
+   * progress bar state. Either "GET" or "POST".
+   *
+   * @example
+   * pb = new Drupal.ProgressBar('myProgressBar');
+   * some_element.appendChild(pb.element);
+   *
+   * @constructor
+   *
+   * @param {string} id
+   *   The id for the progressbar.
+   * @param {function} updateCallback
+   *   Callback to run on update.
+   * @param {string} method
+   *   HTTP method to use.
+   * @param {function} errorCallback
+   *   Callback to call on error.
+   */
   Drupal.ProgressBar = function (id, updateCallback, method, errorCallback) {
     this.id = id;
     this.method = method || 'GET';
     this.updateCallback = updateCallback;
     this.errorCallback = errorCallback;
+
+    // The WAI-ARIA setting aria-live="polite" will announce changes after
+    // users
+    // have completed their current activity and not interrupt the screen
+    // reader.
     this.element = $(Drupal.theme('progressBar', id));
   };
 
-  $.extend(Drupal.ProgressBar.prototype, {
-    setProgress(percentage, message, label) {
-      if (percentage >= 0 && percentage <= 100) {
-        $(this.element).find('div.progress__bar').css('width', `${percentage}%`);
-        $(this.element).find('div.progress__percentage').html(`${percentage}%`);
-      }
-
-      $('div.progress__description', this.element).html(message);
-      $('div.progress__label', this.element).html(label);
-
-      if (this.updateCallback) {
-        this.updateCallback(percentage, message, this);
-      }
-    },
-
-    startMonitoring(uri, delay) {
-      this.delay = delay;
-      this.uri = uri;
-      this.sendPing();
-    },
-
-    stopMonitoring() {
-      clearTimeout(this.timer);
-      this.uri = null;
-    },
-
-    sendPing() {
-      if (this.timer) {
+  $.extend(
+    Drupal.ProgressBar.prototype,
+    /** @lends Drupal.ProgressBar# */ {
+      /**
+       * Set the percentage and status message for the progressbar.
+       *
+       * @param {number} percentage
+       *   The progress percentage.
+       * @param {string} message
+       *   The message to show the user.
+       * @param {string} label
+       *   The text for the progressbar label.
+       */
+      setProgress(percentage, message, label) {
+        if (percentage >= 0 && percentage <= 100) {
+          $(this.element)
+            .find('div.progress__bar')
+            .css('width', `${percentage}%`);
+          $(this.element)
+            .find('div.progress__percentage')
+            .html(`${percentage}%`);
+        }
+        $('div.progress__description', this.element).html(message);
+        $('div.progress__label', this.element).html(label);
+        if (this.updateCallback) {
+          this.updateCallback(percentage, message, this);
+        }
+      },
+
+      /**
+       * Start monitoring progress via Ajax.
+       *
+       * @param {string} uri
+       *   The URI to use for monitoring.
+       * @param {number} delay
+       *   The delay for calling the monitoring URI.
+       */
+      startMonitoring(uri, delay) {
+        this.delay = delay;
+        this.uri = uri;
+        this.sendPing();
+      },
+
+      /**
+       * Stop monitoring progress via Ajax.
+       */
+      stopMonitoring() {
         clearTimeout(this.timer);
-      }
-
-      if (this.uri) {
-        const pb = this;
-        let uri = this.uri;
-
-        if (uri.indexOf('?') === -1) {
-          uri += '?';
-        } else {
-          uri += '&';
+        // This allows monitoring to be stopped from within the callback.
+        this.uri = null;
+      },
+
+      /**
+       * Request progress data from server.
+       */
+      sendPing() {
+        if (this.timer) {
+          clearTimeout(this.timer);
         }
-
-        uri += '_format=json';
-        $.ajax({
-          type: this.method,
-          url: uri,
-          data: '',
-          dataType: 'json',
-
-          success(progress) {
-            if (progress.status === 0) {
-              pb.displayError(progress.data);
-              return;
-            }
-
-            pb.setProgress(progress.percentage, progress.message, progress.label);
-            pb.timer = setTimeout(() => {
-              pb.sendPing();
-            }, pb.delay);
-          },
-
-          error(xmlhttp) {
-            const e = new Drupal.AjaxError(xmlhttp, pb.uri);
-            pb.displayError(`<pre>${e.message}</pre>`);
+        if (this.uri) {
+          const pb = this;
+          // When doing a post request, you need non-null data. Otherwise a
+          // HTTP 411 or HTTP 406 (with Apache mod_security) error may result.
+          let uri = this.uri;
+          if (uri.indexOf('?') === -1) {
+            uri += '?';
+          } else {
+            uri += '&';
           }
-
-        });
-      }
+          uri += '_format=json';
+          $.ajax({
+            type: this.method,
+            url: uri,
+            data: '',
+            dataType: 'json',
+            success(progress) {
+              // Display errors.
+              if (progress.status === 0) {
+                pb.displayError(progress.data);
+                return;
+              }
+              // Update display.
+              pb.setProgress(
+                progress.percentage,
+                progress.message,
+                progress.label,
+              );
+              // Schedule next timer.
+              pb.timer = setTimeout(() => {
+                pb.sendPing();
+              }, pb.delay);
+            },
+            error(xmlhttp) {
+              const e = new Drupal.AjaxError(xmlhttp, pb.uri);
+              pb.displayError(`<pre>${e.message}</pre>`);
+            },
+          });
+        }
+      },
+
+      /**
+       * Display errors on the page.
+       *
+       * @param {string} string
+       *   The error message to show the user.
+       */
+      displayError(string) {
+        const error = $('<div class="messages messages--error"></div>').html(
+          string,
+        );
+        $(this.element).before(error).hide();
+
+        if (this.errorCallback) {
+          this.errorCallback(this);
+        }
+      },
     },
-
-    displayError(string) {
-      const error = $('<div class="messages messages--error"></div>').html(string);
-      $(this.element).before(error).hide();
-
-      if (this.errorCallback) {
-        this.errorCallback(this);
-      }
-    }
-
-  });
-})(jQuery, Drupal);
\ No newline at end of file
+  );
+})(jQuery, Drupal);
diff --git a/core/misc/states.es6.js b/core/misc/states.es6.js
deleted file mode 100644
index b45e1e0504cd..000000000000
--- a/core/misc/states.es6.js
+++ /dev/null
@@ -1,736 +0,0 @@
-/**
- * @file
- * Drupal's states library.
- */
-
-(function ($, Drupal) {
-  /**
-   * The base States namespace.
-   *
-   * Having the local states variable allows us to use the States namespace
-   * without having to always declare "Drupal.states".
-   *
-   * @namespace Drupal.states
-   */
-  const states = {
-    /**
-     * An array of functions that should be postponed.
-     */
-    postponed: [],
-  };
-
-  Drupal.states = states;
-
-  /**
-   * Inverts a (if it's not undefined) when invertState is true.
-   *
-   * @function Drupal.states~invert
-   *
-   * @param {*} a
-   *   The value to maybe invert.
-   * @param {bool} invertState
-   *   Whether to invert state or not.
-   *
-   * @return {bool}
-   *   The result.
-   */
-  function invert(a, invertState) {
-    return invertState && typeof a !== 'undefined' ? !a : a;
-  }
-
-  /**
-   * Compares two values while ignoring undefined values.
-   *
-   * @function Drupal.states~compare
-   *
-   * @param {*} a
-   *   Value a.
-   * @param {*} b
-   *   Value b.
-   *
-   * @return {bool}
-   *   The comparison result.
-   */
-  function compare(a, b) {
-    if (a === b) {
-      return typeof a === 'undefined' ? a : true;
-    }
-
-    return typeof a === 'undefined' || typeof b === 'undefined';
-  }
-
-  /**
-   * Bitwise AND with a third undefined state.
-   *
-   * @function Drupal.states~ternary
-   *
-   * @param {*} a
-   *   Value a.
-   * @param {*} b
-   *   Value b
-   *
-   * @return {bool}
-   *   The result.
-   */
-  function ternary(a, b) {
-    if (typeof a === 'undefined') {
-      return b;
-    }
-    if (typeof b === 'undefined') {
-      return a;
-    }
-
-    return a && b;
-  }
-
-  /**
-   * Attaches the states.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches states behaviors.
-   */
-  Drupal.behaviors.states = {
-    attach(context, settings) {
-      const $states = $(context).find('[data-drupal-states]');
-      const il = $states.length;
-      for (let i = 0; i < il; i++) {
-        const config = JSON.parse(
-          $states[i].getAttribute('data-drupal-states'),
-        );
-        Object.keys(config || {}).forEach((state) => {
-          new states.Dependent({
-            element: $($states[i]),
-            state: states.State.sanitize(state),
-            constraints: config[state],
-          });
-        });
-      }
-
-      // Execute all postponed functions now.
-      while (states.postponed.length) {
-        states.postponed.shift()();
-      }
-    },
-  };
-
-  /**
-   * Object representing an element that depends on other elements.
-   *
-   * @constructor Drupal.states.Dependent
-   *
-   * @param {object} args
-   *   Object with the following keys (all of which are required)
-   * @param {jQuery} args.element
-   *   A jQuery object of the dependent element
-   * @param {Drupal.states.State} args.state
-   *   A State object describing the state that is dependent
-   * @param {object} args.constraints
-   *   An object with dependency specifications. Lists all elements that this
-   *   element depends on. It can be nested and can contain
-   *   arbitrary AND and OR clauses.
-   */
-  states.Dependent = function (args) {
-    $.extend(this, { values: {}, oldValue: null }, args);
-
-    this.dependees = this.getDependees();
-    Object.keys(this.dependees || {}).forEach((selector) => {
-      this.initializeDependee(selector, this.dependees[selector]);
-    });
-  };
-
-  /**
-   * Comparison functions for comparing the value of an element with the
-   * specification from the dependency settings. If the object type can't be
-   * found in this list, the === operator is used by default.
-   *
-   * @name Drupal.states.Dependent.comparisons
-   *
-   * @prop {function} RegExp
-   * @prop {function} Function
-   * @prop {function} Number
-   */
-  states.Dependent.comparisons = {
-    RegExp(reference, value) {
-      return reference.test(value);
-    },
-    Function(reference, value) {
-      // The "reference" variable is a comparison function.
-      return reference(value);
-    },
-    Number(reference, value) {
-      // If "reference" is a number and "value" is a string, then cast
-      // reference as a string before applying the strict comparison in
-      // compare().
-      // Otherwise numeric keys in the form's #states array fail to match
-      // string values returned from jQuery's val().
-      return typeof value === 'string'
-        ? compare(reference.toString(), value)
-        : compare(reference, value);
-    },
-  };
-
-  states.Dependent.prototype = {
-    /**
-     * Initializes one of the elements this dependent depends on.
-     *
-     * @memberof Drupal.states.Dependent#
-     *
-     * @param {string} selector
-     *   The CSS selector describing the dependee.
-     * @param {object} dependeeStates
-     *   The list of states that have to be monitored for tracking the
-     *   dependee's compliance status.
-     */
-    initializeDependee(selector, dependeeStates) {
-      // Cache for the states of this dependee.
-      this.values[selector] = {};
-
-      Object.keys(dependeeStates).forEach((i) => {
-        let state = dependeeStates[i];
-        // Make sure we're not initializing this selector/state combination
-        // twice.
-        if ($.inArray(state, dependeeStates) === -1) {
-          return;
-        }
-
-        state = states.State.sanitize(state);
-
-        // Initialize the value of this state.
-        this.values[selector][state.name] = null;
-
-        // Monitor state changes of the specified state for this dependee.
-        $(selector).on(`state:${state}`, { selector, state }, (e) => {
-          this.update(e.data.selector, e.data.state, e.value);
-        });
-
-        // Make sure the event we just bound ourselves to is actually fired.
-        new states.Trigger({ selector, state });
-      });
-    },
-
-    /**
-     * Compares a value with a reference value.
-     *
-     * @memberof Drupal.states.Dependent#
-     *
-     * @param {object} reference
-     *   The value used for reference.
-     * @param {string} selector
-     *   CSS selector describing the dependee.
-     * @param {Drupal.states.State} state
-     *   A State object describing the dependee's updated state.
-     *
-     * @return {bool}
-     *   true or false.
-     */
-    compare(reference, selector, state) {
-      const value = this.values[selector][state.name];
-      if (reference.constructor.name in states.Dependent.comparisons) {
-        // Use a custom compare function for certain reference value types.
-        return states.Dependent.comparisons[reference.constructor.name](
-          reference,
-          value,
-        );
-      }
-
-      // Do a plain comparison otherwise.
-      return compare(reference, value);
-    },
-
-    /**
-     * Update the value of a dependee's state.
-     *
-     * @memberof Drupal.states.Dependent#
-     *
-     * @param {string} selector
-     *   CSS selector describing the dependee.
-     * @param {Drupal.states.state} state
-     *   A State object describing the dependee's updated state.
-     * @param {string} value
-     *   The new value for the dependee's updated state.
-     */
-    update(selector, state, value) {
-      // Only act when the 'new' value is actually new.
-      if (value !== this.values[selector][state.name]) {
-        this.values[selector][state.name] = value;
-        this.reevaluate();
-      }
-    },
-
-    /**
-     * Triggers change events in case a state changed.
-     *
-     * @memberof Drupal.states.Dependent#
-     */
-    reevaluate() {
-      // Check whether any constraint for this dependent state is satisfied.
-      let value = this.verifyConstraints(this.constraints);
-
-      // Only invoke a state change event when the value actually changed.
-      if (value !== this.oldValue) {
-        // Store the new value so that we can compare later whether the value
-        // actually changed.
-        this.oldValue = value;
-
-        // Normalize the value to match the normalized state name.
-        value = invert(value, this.state.invert);
-
-        // By adding "trigger: true", we ensure that state changes don't go into
-        // infinite loops.
-        this.element.trigger({
-          type: `state:${this.state}`,
-          value,
-          trigger: true,
-        });
-      }
-    },
-
-    /**
-     * Evaluates child constraints to determine if a constraint is satisfied.
-     *
-     * @memberof Drupal.states.Dependent#
-     *
-     * @param {object|Array} constraints
-     *   A constraint object or an array of constraints.
-     * @param {string} selector
-     *   The selector for these constraints. If undefined, there isn't yet a
-     *   selector that these constraints apply to. In that case, the keys of the
-     *   object are interpreted as the selector if encountered.
-     *
-     * @return {bool}
-     *   true or false, depending on whether these constraints are satisfied.
-     */
-    verifyConstraints(constraints, selector) {
-      let result;
-      if ($.isArray(constraints)) {
-        // This constraint is an array (OR or XOR).
-        const hasXor = $.inArray('xor', constraints) === -1;
-        const len = constraints.length;
-        for (let i = 0; i < len; i++) {
-          if (constraints[i] !== 'xor') {
-            const constraint = this.checkConstraints(
-              constraints[i],
-              selector,
-              i,
-            );
-            // Return if this is OR and we have a satisfied constraint or if
-            // this is XOR and we have a second satisfied constraint.
-            if (constraint && (hasXor || result)) {
-              return hasXor;
-            }
-            result = result || constraint;
-          }
-        }
-      }
-      // Make sure we don't try to iterate over things other than objects. This
-      // shouldn't normally occur, but in case the condition definition is
-      // bogus, we don't want to end up with an infinite loop.
-      else if ($.isPlainObject(constraints)) {
-        // This constraint is an object (AND).
-        // eslint-disable-next-line no-restricted-syntax
-        for (const n in constraints) {
-          if (constraints.hasOwnProperty(n)) {
-            result = ternary(
-              result,
-              this.checkConstraints(constraints[n], selector, n),
-            );
-            // False and anything else will evaluate to false, so return when
-            // any false condition is found.
-            if (result === false) {
-              return false;
-            }
-          }
-        }
-      }
-      return result;
-    },
-
-    /**
-     * Checks whether the value matches the requirements for this constraint.
-     *
-     * @memberof Drupal.states.Dependent#
-     *
-     * @param {string|Array|object} value
-     *   Either the value of a state or an array/object of constraints. In the
-     *   latter case, resolving the constraint continues.
-     * @param {string} [selector]
-     *   The selector for this constraint. If undefined, there isn't yet a
-     *   selector that this constraint applies to. In that case, the state key
-     *   is propagates to a selector and resolving continues.
-     * @param {Drupal.states.State} [state]
-     *   The state to check for this constraint. If undefined, resolving
-     *   continues. If both selector and state aren't undefined and valid
-     *   non-numeric strings, a lookup for the actual value of that selector's
-     *   state is performed. This parameter is not a State object but a pristine
-     *   state string.
-     *
-     * @return {bool}
-     *   true or false, depending on whether this constraint is satisfied.
-     */
-    checkConstraints(value, selector, state) {
-      // Normalize the last parameter. If it's non-numeric, we treat it either
-      // as a selector (in case there isn't one yet) or as a trigger/state.
-      if (typeof state !== 'string' || /[0-9]/.test(state[0])) {
-        state = null;
-      } else if (typeof selector === 'undefined') {
-        // Propagate the state to the selector when there isn't one yet.
-        selector = state;
-        state = null;
-      }
-
-      if (state !== null) {
-        // Constraints is the actual constraints of an element to check for.
-        state = states.State.sanitize(state);
-        return invert(this.compare(value, selector, state), state.invert);
-      }
-
-      // Resolve this constraint as an AND/OR operator.
-      return this.verifyConstraints(value, selector);
-    },
-
-    /**
-     * Gathers information about all required triggers.
-     *
-     * @memberof Drupal.states.Dependent#
-     *
-     * @return {object}
-     *   An object describing the required triggers.
-     */
-    getDependees() {
-      const cache = {};
-      // Swivel the lookup function so that we can record all available
-      // selector- state combinations for initialization.
-      const _compare = this.compare;
-      this.compare = function (reference, selector, state) {
-        (cache[selector] || (cache[selector] = [])).push(state.name);
-        // Return nothing (=== undefined) so that the constraint loops are not
-        // broken.
-      };
-
-      // This call doesn't actually verify anything but uses the resolving
-      // mechanism to go through the constraints array, trying to look up each
-      // value. Since we swivelled the compare function, this comparison returns
-      // undefined and lookup continues until the very end. Instead of lookup up
-      // the value, we record that combination of selector and state so that we
-      // can initialize all triggers.
-      this.verifyConstraints(this.constraints);
-      // Restore the original function.
-      this.compare = _compare;
-
-      return cache;
-    },
-  };
-
-  /**
-   * @constructor Drupal.states.Trigger
-   *
-   * @param {object} args
-   *   Trigger arguments.
-   */
-  states.Trigger = function (args) {
-    $.extend(this, args);
-
-    if (this.state in states.Trigger.states) {
-      this.element = $(this.selector);
-
-      // Only call the trigger initializer when it wasn't yet attached to this
-      // element. Otherwise we'd end up with duplicate events.
-      if (!this.element.data(`trigger:${this.state}`)) {
-        this.initialize();
-      }
-    }
-  };
-
-  states.Trigger.prototype = {
-    /**
-     * @memberof Drupal.states.Trigger#
-     */
-    initialize() {
-      const trigger = states.Trigger.states[this.state];
-
-      if (typeof trigger === 'function') {
-        // We have a custom trigger initialization function.
-        trigger.call(window, this.element);
-      } else {
-        Object.keys(trigger || {}).forEach((event) => {
-          this.defaultTrigger(event, trigger[event]);
-        });
-      }
-
-      // Mark this trigger as initialized for this element.
-      this.element.data(`trigger:${this.state}`, true);
-    },
-
-    /**
-     * @memberof Drupal.states.Trigger#
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered.
-     * @param {function} valueFn
-     *   The function to call.
-     */
-    defaultTrigger(event, valueFn) {
-      let oldValue = valueFn.call(this.element);
-
-      // Attach the event callback.
-      this.element.on(
-        event,
-        $.proxy(function (e) {
-          const value = valueFn.call(this.element, e);
-          // Only trigger the event if the value has actually changed.
-          if (oldValue !== value) {
-            this.element.trigger({
-              type: `state:${this.state}`,
-              value,
-              oldValue,
-            });
-            oldValue = value;
-          }
-        }, this),
-      );
-
-      states.postponed.push(
-        $.proxy(function () {
-          // Trigger the event once for initialization purposes.
-          this.element.trigger({
-            type: `state:${this.state}`,
-            value: oldValue,
-            oldValue: null,
-          });
-        }, this),
-      );
-    },
-  };
-
-  /**
-   * This list of states contains functions that are used to monitor the state
-   * of an element. Whenever an element depends on the state of another element,
-   * one of these trigger functions is added to the dependee so that the
-   * dependent element can be updated.
-   *
-   * @name Drupal.states.Trigger.states
-   *
-   * @prop empty
-   * @prop checked
-   * @prop value
-   * @prop collapsed
-   */
-  states.Trigger.states = {
-    // 'empty' describes the state to be monitored.
-    empty: {
-      // 'keyup' is the (native DOM) event that we watch for.
-      keyup() {
-        // The function associated with that trigger returns the new value for
-        // the state.
-        return this.val() === '';
-      },
-    },
-
-    checked: {
-      change() {
-        // prop() and attr() only takes the first element into account. To
-        // support selectors matching multiple checkboxes, iterate over all and
-        // return whether any is checked.
-        let checked = false;
-        this.each(function () {
-          // Use prop() here as we want a boolean of the checkbox state.
-          // @see http://api.jquery.com/prop/
-          checked = $(this).prop('checked');
-          // Break the each() loop if this is checked.
-          return !checked;
-        });
-        return checked;
-      },
-    },
-
-    // For radio buttons, only return the value if the radio button is selected.
-    value: {
-      keyup() {
-        // Radio buttons share the same :input[name="key"] selector.
-        if (this.length > 1) {
-          // Initial checked value of radios is undefined, so we return false.
-          return this.filter(':checked').val() || false;
-        }
-        return this.val();
-      },
-      change() {
-        // Radio buttons share the same :input[name="key"] selector.
-        if (this.length > 1) {
-          // Initial checked value of radios is undefined, so we return false.
-          return this.filter(':checked').val() || false;
-        }
-        return this.val();
-      },
-    },
-
-    collapsed: {
-      collapsed(e) {
-        return typeof e !== 'undefined' && 'value' in e
-          ? e.value
-          : !this.is('[open]');
-      },
-    },
-  };
-
-  /**
-   * A state object is used for describing the state and performing aliasing.
-   *
-   * @constructor Drupal.states.State
-   *
-   * @param {string} state
-   *   The name of the state.
-   */
-  states.State = function (state) {
-    /**
-     * Original unresolved name.
-     */
-    this.pristine = state;
-    this.name = state;
-
-    // Normalize the state name.
-    let process = true;
-    do {
-      // Iteratively remove exclamation marks and invert the value.
-      while (this.name.charAt(0) === '!') {
-        this.name = this.name.substring(1);
-        this.invert = !this.invert;
-      }
-
-      // Replace the state with its normalized name.
-      if (this.name in states.State.aliases) {
-        this.name = states.State.aliases[this.name];
-      } else {
-        process = false;
-      }
-    } while (process);
-  };
-
-  /**
-   * Creates a new State object by sanitizing the passed value.
-   *
-   * @name Drupal.states.State.sanitize
-   *
-   * @param {string|Drupal.states.State} state
-   *   A state object or the name of a state.
-   *
-   * @return {Drupal.states.state}
-   *   A state object.
-   */
-  states.State.sanitize = function (state) {
-    if (state instanceof states.State) {
-      return state;
-    }
-
-    return new states.State(state);
-  };
-
-  /**
-   * This list of aliases is used to normalize states and associates negated
-   * names with their respective inverse state.
-   *
-   * @name Drupal.states.State.aliases
-   */
-  states.State.aliases = {
-    enabled: '!disabled',
-    invisible: '!visible',
-    invalid: '!valid',
-    untouched: '!touched',
-    optional: '!required',
-    filled: '!empty',
-    unchecked: '!checked',
-    irrelevant: '!relevant',
-    expanded: '!collapsed',
-    open: '!collapsed',
-    closed: 'collapsed',
-    readwrite: '!readonly',
-  };
-
-  states.State.prototype = {
-    /**
-     * @memberof Drupal.states.State#
-     */
-    invert: false,
-
-    /**
-     * Ensures that just using the state object returns the name.
-     *
-     * @memberof Drupal.states.State#
-     *
-     * @return {string}
-     *   The name of the state.
-     */
-    toString() {
-      return this.name;
-    },
-  };
-
-  /**
-   * Global state change handlers. These are bound to "document" to cover all
-   * elements whose state changes. Events sent to elements within the page
-   * bubble up to these handlers. We use this system so that themes and modules
-   * can override these state change handlers for particular parts of a page.
-   */
-
-  const $document = $(document);
-  $document.on('state:disabled', (e) => {
-    // Only act when this change was triggered by a dependency and not by the
-    // element monitoring itself.
-    if (e.trigger) {
-      $(e.target)
-        .prop('disabled', e.value)
-        .closest('.js-form-item, .js-form-submit, .js-form-wrapper')
-        .toggleClass('form-disabled', e.value)
-        .find('select, input, textarea')
-        .prop('disabled', e.value);
-
-      // Note: WebKit nightlies don't reflect that change correctly.
-      // See https://bugs.webkit.org/show_bug.cgi?id=23789
-    }
-  });
-
-  $document.on('state:required', (e) => {
-    if (e.trigger) {
-      if (e.value) {
-        const label = `label${e.target.id ? `[for=${e.target.id}]` : ''}`;
-        const $label = $(e.target)
-          .attr({ required: 'required', 'aria-required': 'true' })
-          .closest('.js-form-item, .js-form-wrapper')
-          .find(label);
-        // Avoids duplicate required markers on initialization.
-        if (!$label.hasClass('js-form-required').length) {
-          $label.addClass('js-form-required form-required');
-        }
-      } else {
-        $(e.target)
-          .removeAttr('required aria-required')
-          .closest('.js-form-item, .js-form-wrapper')
-          .find('label.js-form-required')
-          .removeClass('js-form-required form-required');
-      }
-    }
-  });
-
-  $document.on('state:visible', (e) => {
-    if (e.trigger) {
-      $(e.target)
-        .closest('.js-form-item, .js-form-submit, .js-form-wrapper')
-        .toggle(e.value);
-    }
-  });
-
-  $document.on('state:checked', (e) => {
-    if (e.trigger) {
-      $(e.target).prop('checked', e.value);
-    }
-  });
-
-  $document.on('state:collapsed', (e) => {
-    if (e.trigger) {
-      if ($(e.target).is('[open]') === e.value) {
-        $(e.target).find('> summary').trigger('click');
-      }
-    }
-  });
-})(jQuery, Drupal);
diff --git a/core/misc/states.js b/core/misc/states.js
index 766e2e9dff5e..b45e1e0504cd 100644
--- a/core/misc/states.js
+++ b/core/misc/states.js
@@ -1,20 +1,56 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Drupal's states library.
+ */
 
 (function ($, Drupal) {
+  /**
+   * The base States namespace.
+   *
+   * Having the local states variable allows us to use the States namespace
+   * without having to always declare "Drupal.states".
+   *
+   * @namespace Drupal.states
+   */
   const states = {
-    postponed: []
+    /**
+     * An array of functions that should be postponed.
+     */
+    postponed: [],
   };
+
   Drupal.states = states;
 
+  /**
+   * Inverts a (if it's not undefined) when invertState is true.
+   *
+   * @function Drupal.states~invert
+   *
+   * @param {*} a
+   *   The value to maybe invert.
+   * @param {bool} invertState
+   *   Whether to invert state or not.
+   *
+   * @return {bool}
+   *   The result.
+   */
   function invert(a, invertState) {
     return invertState && typeof a !== 'undefined' ? !a : a;
   }
 
+  /**
+   * Compares two values while ignoring undefined values.
+   *
+   * @function Drupal.states~compare
+   *
+   * @param {*} a
+   *   Value a.
+   * @param {*} b
+   *   Value b.
+   *
+   * @return {bool}
+   *   The comparison result.
+   */
   function compare(a, b) {
     if (a === b) {
       return typeof a === 'undefined' ? a : true;
@@ -23,11 +59,23 @@
     return typeof a === 'undefined' || typeof b === 'undefined';
   }
 
+  /**
+   * Bitwise AND with a third undefined state.
+   *
+   * @function Drupal.states~ternary
+   *
+   * @param {*} a
+   *   Value a.
+   * @param {*} b
+   *   Value b
+   *
+   * @return {bool}
+   *   The result.
+   */
   function ternary(a, b) {
     if (typeof a === 'undefined') {
       return b;
     }
-
     if (typeof b === 'undefined') {
       return a;
     }
@@ -35,180 +83,360 @@
     return a && b;
   }
 
+  /**
+   * Attaches the states.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches states behaviors.
+   */
   Drupal.behaviors.states = {
     attach(context, settings) {
       const $states = $(context).find('[data-drupal-states]');
       const il = $states.length;
-
       for (let i = 0; i < il; i++) {
-        const config = JSON.parse($states[i].getAttribute('data-drupal-states'));
-        Object.keys(config || {}).forEach(state => {
+        const config = JSON.parse(
+          $states[i].getAttribute('data-drupal-states'),
+        );
+        Object.keys(config || {}).forEach((state) => {
           new states.Dependent({
             element: $($states[i]),
             state: states.State.sanitize(state),
-            constraints: config[state]
+            constraints: config[state],
           });
         });
       }
 
+      // Execute all postponed functions now.
       while (states.postponed.length) {
         states.postponed.shift()();
       }
-    }
-
+    },
   };
 
+  /**
+   * Object representing an element that depends on other elements.
+   *
+   * @constructor Drupal.states.Dependent
+   *
+   * @param {object} args
+   *   Object with the following keys (all of which are required)
+   * @param {jQuery} args.element
+   *   A jQuery object of the dependent element
+   * @param {Drupal.states.State} args.state
+   *   A State object describing the state that is dependent
+   * @param {object} args.constraints
+   *   An object with dependency specifications. Lists all elements that this
+   *   element depends on. It can be nested and can contain
+   *   arbitrary AND and OR clauses.
+   */
   states.Dependent = function (args) {
-    $.extend(this, {
-      values: {},
-      oldValue: null
-    }, args);
+    $.extend(this, { values: {}, oldValue: null }, args);
+
     this.dependees = this.getDependees();
-    Object.keys(this.dependees || {}).forEach(selector => {
+    Object.keys(this.dependees || {}).forEach((selector) => {
       this.initializeDependee(selector, this.dependees[selector]);
     });
   };
 
+  /**
+   * Comparison functions for comparing the value of an element with the
+   * specification from the dependency settings. If the object type can't be
+   * found in this list, the === operator is used by default.
+   *
+   * @name Drupal.states.Dependent.comparisons
+   *
+   * @prop {function} RegExp
+   * @prop {function} Function
+   * @prop {function} Number
+   */
   states.Dependent.comparisons = {
     RegExp(reference, value) {
       return reference.test(value);
     },
-
     Function(reference, value) {
+      // The "reference" variable is a comparison function.
       return reference(value);
     },
-
     Number(reference, value) {
-      return typeof value === 'string' ? compare(reference.toString(), value) : compare(reference, value);
-    }
-
+      // If "reference" is a number and "value" is a string, then cast
+      // reference as a string before applying the strict comparison in
+      // compare().
+      // Otherwise numeric keys in the form's #states array fail to match
+      // string values returned from jQuery's val().
+      return typeof value === 'string'
+        ? compare(reference.toString(), value)
+        : compare(reference, value);
+    },
   };
+
   states.Dependent.prototype = {
+    /**
+     * Initializes one of the elements this dependent depends on.
+     *
+     * @memberof Drupal.states.Dependent#
+     *
+     * @param {string} selector
+     *   The CSS selector describing the dependee.
+     * @param {object} dependeeStates
+     *   The list of states that have to be monitored for tracking the
+     *   dependee's compliance status.
+     */
     initializeDependee(selector, dependeeStates) {
+      // Cache for the states of this dependee.
       this.values[selector] = {};
-      Object.keys(dependeeStates).forEach(i => {
-        let state = dependeeStates[i];
 
+      Object.keys(dependeeStates).forEach((i) => {
+        let state = dependeeStates[i];
+        // Make sure we're not initializing this selector/state combination
+        // twice.
         if ($.inArray(state, dependeeStates) === -1) {
           return;
         }
 
         state = states.State.sanitize(state);
+
+        // Initialize the value of this state.
         this.values[selector][state.name] = null;
-        $(selector).on(`state:${state}`, {
-          selector,
-          state
-        }, e => {
+
+        // Monitor state changes of the specified state for this dependee.
+        $(selector).on(`state:${state}`, { selector, state }, (e) => {
           this.update(e.data.selector, e.data.state, e.value);
         });
-        new states.Trigger({
-          selector,
-          state
-        });
+
+        // Make sure the event we just bound ourselves to is actually fired.
+        new states.Trigger({ selector, state });
       });
     },
 
+    /**
+     * Compares a value with a reference value.
+     *
+     * @memberof Drupal.states.Dependent#
+     *
+     * @param {object} reference
+     *   The value used for reference.
+     * @param {string} selector
+     *   CSS selector describing the dependee.
+     * @param {Drupal.states.State} state
+     *   A State object describing the dependee's updated state.
+     *
+     * @return {bool}
+     *   true or false.
+     */
     compare(reference, selector, state) {
       const value = this.values[selector][state.name];
-
       if (reference.constructor.name in states.Dependent.comparisons) {
-        return states.Dependent.comparisons[reference.constructor.name](reference, value);
+        // Use a custom compare function for certain reference value types.
+        return states.Dependent.comparisons[reference.constructor.name](
+          reference,
+          value,
+        );
       }
 
+      // Do a plain comparison otherwise.
       return compare(reference, value);
     },
 
+    /**
+     * Update the value of a dependee's state.
+     *
+     * @memberof Drupal.states.Dependent#
+     *
+     * @param {string} selector
+     *   CSS selector describing the dependee.
+     * @param {Drupal.states.state} state
+     *   A State object describing the dependee's updated state.
+     * @param {string} value
+     *   The new value for the dependee's updated state.
+     */
     update(selector, state, value) {
+      // Only act when the 'new' value is actually new.
       if (value !== this.values[selector][state.name]) {
         this.values[selector][state.name] = value;
         this.reevaluate();
       }
     },
 
+    /**
+     * Triggers change events in case a state changed.
+     *
+     * @memberof Drupal.states.Dependent#
+     */
     reevaluate() {
+      // Check whether any constraint for this dependent state is satisfied.
       let value = this.verifyConstraints(this.constraints);
 
+      // Only invoke a state change event when the value actually changed.
       if (value !== this.oldValue) {
+        // Store the new value so that we can compare later whether the value
+        // actually changed.
         this.oldValue = value;
+
+        // Normalize the value to match the normalized state name.
         value = invert(value, this.state.invert);
+
+        // By adding "trigger: true", we ensure that state changes don't go into
+        // infinite loops.
         this.element.trigger({
           type: `state:${this.state}`,
           value,
-          trigger: true
+          trigger: true,
         });
       }
     },
 
+    /**
+     * Evaluates child constraints to determine if a constraint is satisfied.
+     *
+     * @memberof Drupal.states.Dependent#
+     *
+     * @param {object|Array} constraints
+     *   A constraint object or an array of constraints.
+     * @param {string} selector
+     *   The selector for these constraints. If undefined, there isn't yet a
+     *   selector that these constraints apply to. In that case, the keys of the
+     *   object are interpreted as the selector if encountered.
+     *
+     * @return {bool}
+     *   true or false, depending on whether these constraints are satisfied.
+     */
     verifyConstraints(constraints, selector) {
       let result;
-
       if ($.isArray(constraints)) {
+        // This constraint is an array (OR or XOR).
         const hasXor = $.inArray('xor', constraints) === -1;
         const len = constraints.length;
-
         for (let i = 0; i < len; i++) {
           if (constraints[i] !== 'xor') {
-            const constraint = this.checkConstraints(constraints[i], selector, i);
-
+            const constraint = this.checkConstraints(
+              constraints[i],
+              selector,
+              i,
+            );
+            // Return if this is OR and we have a satisfied constraint or if
+            // this is XOR and we have a second satisfied constraint.
             if (constraint && (hasXor || result)) {
               return hasXor;
             }
-
             result = result || constraint;
           }
         }
-      } else if ($.isPlainObject(constraints)) {
+      }
+      // Make sure we don't try to iterate over things other than objects. This
+      // shouldn't normally occur, but in case the condition definition is
+      // bogus, we don't want to end up with an infinite loop.
+      else if ($.isPlainObject(constraints)) {
+        // This constraint is an object (AND).
+        // eslint-disable-next-line no-restricted-syntax
         for (const n in constraints) {
           if (constraints.hasOwnProperty(n)) {
-            result = ternary(result, this.checkConstraints(constraints[n], selector, n));
-
+            result = ternary(
+              result,
+              this.checkConstraints(constraints[n], selector, n),
+            );
+            // False and anything else will evaluate to false, so return when
+            // any false condition is found.
             if (result === false) {
               return false;
             }
           }
         }
       }
-
       return result;
     },
 
+    /**
+     * Checks whether the value matches the requirements for this constraint.
+     *
+     * @memberof Drupal.states.Dependent#
+     *
+     * @param {string|Array|object} value
+     *   Either the value of a state or an array/object of constraints. In the
+     *   latter case, resolving the constraint continues.
+     * @param {string} [selector]
+     *   The selector for this constraint. If undefined, there isn't yet a
+     *   selector that this constraint applies to. In that case, the state key
+     *   is propagates to a selector and resolving continues.
+     * @param {Drupal.states.State} [state]
+     *   The state to check for this constraint. If undefined, resolving
+     *   continues. If both selector and state aren't undefined and valid
+     *   non-numeric strings, a lookup for the actual value of that selector's
+     *   state is performed. This parameter is not a State object but a pristine
+     *   state string.
+     *
+     * @return {bool}
+     *   true or false, depending on whether this constraint is satisfied.
+     */
     checkConstraints(value, selector, state) {
+      // Normalize the last parameter. If it's non-numeric, we treat it either
+      // as a selector (in case there isn't one yet) or as a trigger/state.
       if (typeof state !== 'string' || /[0-9]/.test(state[0])) {
         state = null;
       } else if (typeof selector === 'undefined') {
+        // Propagate the state to the selector when there isn't one yet.
         selector = state;
         state = null;
       }
 
       if (state !== null) {
+        // Constraints is the actual constraints of an element to check for.
         state = states.State.sanitize(state);
         return invert(this.compare(value, selector, state), state.invert);
       }
 
+      // Resolve this constraint as an AND/OR operator.
       return this.verifyConstraints(value, selector);
     },
 
+    /**
+     * Gathers information about all required triggers.
+     *
+     * @memberof Drupal.states.Dependent#
+     *
+     * @return {object}
+     *   An object describing the required triggers.
+     */
     getDependees() {
       const cache = {};
+      // Swivel the lookup function so that we can record all available
+      // selector- state combinations for initialization.
       const _compare = this.compare;
-
       this.compare = function (reference, selector, state) {
         (cache[selector] || (cache[selector] = [])).push(state.name);
+        // Return nothing (=== undefined) so that the constraint loops are not
+        // broken.
       };
 
+      // This call doesn't actually verify anything but uses the resolving
+      // mechanism to go through the constraints array, trying to look up each
+      // value. Since we swivelled the compare function, this comparison returns
+      // undefined and lookup continues until the very end. Instead of lookup up
+      // the value, we record that combination of selector and state so that we
+      // can initialize all triggers.
       this.verifyConstraints(this.constraints);
+      // Restore the original function.
       this.compare = _compare;
-      return cache;
-    }
 
+      return cache;
+    },
   };
 
+  /**
+   * @constructor Drupal.states.Trigger
+   *
+   * @param {object} args
+   *   Trigger arguments.
+   */
   states.Trigger = function (args) {
     $.extend(this, args);
 
     if (this.state in states.Trigger.states) {
       this.element = $(this.selector);
 
+      // Only call the trigger initializer when it wasn't yet attached to this
+      // element. Otherwise we'd end up with duplicate events.
       if (!this.element.data(`trigger:${this.state}`)) {
         this.initialize();
       }
@@ -216,99 +444,161 @@
   };
 
   states.Trigger.prototype = {
+    /**
+     * @memberof Drupal.states.Trigger#
+     */
     initialize() {
       const trigger = states.Trigger.states[this.state];
 
       if (typeof trigger === 'function') {
+        // We have a custom trigger initialization function.
         trigger.call(window, this.element);
       } else {
-        Object.keys(trigger || {}).forEach(event => {
+        Object.keys(trigger || {}).forEach((event) => {
           this.defaultTrigger(event, trigger[event]);
         });
       }
 
+      // Mark this trigger as initialized for this element.
       this.element.data(`trigger:${this.state}`, true);
     },
 
+    /**
+     * @memberof Drupal.states.Trigger#
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered.
+     * @param {function} valueFn
+     *   The function to call.
+     */
     defaultTrigger(event, valueFn) {
       let oldValue = valueFn.call(this.element);
-      this.element.on(event, $.proxy(function (e) {
-        const value = valueFn.call(this.element, e);
 
-        if (oldValue !== value) {
+      // Attach the event callback.
+      this.element.on(
+        event,
+        $.proxy(function (e) {
+          const value = valueFn.call(this.element, e);
+          // Only trigger the event if the value has actually changed.
+          if (oldValue !== value) {
+            this.element.trigger({
+              type: `state:${this.state}`,
+              value,
+              oldValue,
+            });
+            oldValue = value;
+          }
+        }, this),
+      );
+
+      states.postponed.push(
+        $.proxy(function () {
+          // Trigger the event once for initialization purposes.
           this.element.trigger({
             type: `state:${this.state}`,
-            value,
-            oldValue
+            value: oldValue,
+            oldValue: null,
           });
-          oldValue = value;
-        }
-      }, this));
-      states.postponed.push($.proxy(function () {
-        this.element.trigger({
-          type: `state:${this.state}`,
-          value: oldValue,
-          oldValue: null
-        });
-      }, this));
-    }
-
+        }, this),
+      );
+    },
   };
+
+  /**
+   * This list of states contains functions that are used to monitor the state
+   * of an element. Whenever an element depends on the state of another element,
+   * one of these trigger functions is added to the dependee so that the
+   * dependent element can be updated.
+   *
+   * @name Drupal.states.Trigger.states
+   *
+   * @prop empty
+   * @prop checked
+   * @prop value
+   * @prop collapsed
+   */
   states.Trigger.states = {
+    // 'empty' describes the state to be monitored.
     empty: {
+      // 'keyup' is the (native DOM) event that we watch for.
       keyup() {
+        // The function associated with that trigger returns the new value for
+        // the state.
         return this.val() === '';
-      }
-
+      },
     },
+
     checked: {
       change() {
+        // prop() and attr() only takes the first element into account. To
+        // support selectors matching multiple checkboxes, iterate over all and
+        // return whether any is checked.
         let checked = false;
         this.each(function () {
+          // Use prop() here as we want a boolean of the checkbox state.
+          // @see http://api.jquery.com/prop/
           checked = $(this).prop('checked');
+          // Break the each() loop if this is checked.
           return !checked;
         });
         return checked;
-      }
-
+      },
     },
+
+    // For radio buttons, only return the value if the radio button is selected.
     value: {
       keyup() {
+        // Radio buttons share the same :input[name="key"] selector.
         if (this.length > 1) {
+          // Initial checked value of radios is undefined, so we return false.
           return this.filter(':checked').val() || false;
         }
-
         return this.val();
       },
-
       change() {
+        // Radio buttons share the same :input[name="key"] selector.
         if (this.length > 1) {
+          // Initial checked value of radios is undefined, so we return false.
           return this.filter(':checked').val() || false;
         }
-
         return this.val();
-      }
-
+      },
     },
+
     collapsed: {
       collapsed(e) {
-        return typeof e !== 'undefined' && 'value' in e ? e.value : !this.is('[open]');
-      }
-
-    }
+        return typeof e !== 'undefined' && 'value' in e
+          ? e.value
+          : !this.is('[open]');
+      },
+    },
   };
 
+  /**
+   * A state object is used for describing the state and performing aliasing.
+   *
+   * @constructor Drupal.states.State
+   *
+   * @param {string} state
+   *   The name of the state.
+   */
   states.State = function (state) {
+    /**
+     * Original unresolved name.
+     */
     this.pristine = state;
     this.name = state;
-    let process = true;
 
+    // Normalize the state name.
+    let process = true;
     do {
+      // Iteratively remove exclamation marks and invert the value.
       while (this.name.charAt(0) === '!') {
         this.name = this.name.substring(1);
         this.invert = !this.invert;
       }
 
+      // Replace the state with its normalized name.
       if (this.name in states.State.aliases) {
         this.name = states.State.aliases[this.name];
       } else {
@@ -317,6 +607,17 @@
     } while (process);
   };
 
+  /**
+   * Creates a new State object by sanitizing the passed value.
+   *
+   * @name Drupal.states.State.sanitize
+   *
+   * @param {string|Drupal.states.State} state
+   *   A state object or the name of a state.
+   *
+   * @return {Drupal.states.state}
+   *   A state object.
+   */
   states.State.sanitize = function (state) {
     if (state instanceof states.State) {
       return state;
@@ -325,6 +626,12 @@
     return new states.State(state);
   };
 
+  /**
+   * This list of aliases is used to normalize states and associates negated
+   * names with their respective inverse state.
+   *
+   * @name Drupal.states.State.aliases
+   */
   states.State.aliases = {
     enabled: '!disabled',
     invisible: '!visible',
@@ -337,54 +644,93 @@
     expanded: '!collapsed',
     open: '!collapsed',
     closed: 'collapsed',
-    readwrite: '!readonly'
+    readwrite: '!readonly',
   };
+
   states.State.prototype = {
+    /**
+     * @memberof Drupal.states.State#
+     */
     invert: false,
 
+    /**
+     * Ensures that just using the state object returns the name.
+     *
+     * @memberof Drupal.states.State#
+     *
+     * @return {string}
+     *   The name of the state.
+     */
     toString() {
       return this.name;
-    }
-
+    },
   };
+
+  /**
+   * Global state change handlers. These are bound to "document" to cover all
+   * elements whose state changes. Events sent to elements within the page
+   * bubble up to these handlers. We use this system so that themes and modules
+   * can override these state change handlers for particular parts of a page.
+   */
+
   const $document = $(document);
-  $document.on('state:disabled', e => {
+  $document.on('state:disabled', (e) => {
+    // Only act when this change was triggered by a dependency and not by the
+    // element monitoring itself.
     if (e.trigger) {
-      $(e.target).prop('disabled', e.value).closest('.js-form-item, .js-form-submit, .js-form-wrapper').toggleClass('form-disabled', e.value).find('select, input, textarea').prop('disabled', e.value);
+      $(e.target)
+        .prop('disabled', e.value)
+        .closest('.js-form-item, .js-form-submit, .js-form-wrapper')
+        .toggleClass('form-disabled', e.value)
+        .find('select, input, textarea')
+        .prop('disabled', e.value);
+
+      // Note: WebKit nightlies don't reflect that change correctly.
+      // See https://bugs.webkit.org/show_bug.cgi?id=23789
     }
   });
-  $document.on('state:required', e => {
+
+  $document.on('state:required', (e) => {
     if (e.trigger) {
       if (e.value) {
         const label = `label${e.target.id ? `[for=${e.target.id}]` : ''}`;
-        const $label = $(e.target).attr({
-          required: 'required',
-          'aria-required': 'true'
-        }).closest('.js-form-item, .js-form-wrapper').find(label);
-
+        const $label = $(e.target)
+          .attr({ required: 'required', 'aria-required': 'true' })
+          .closest('.js-form-item, .js-form-wrapper')
+          .find(label);
+        // Avoids duplicate required markers on initialization.
         if (!$label.hasClass('js-form-required').length) {
           $label.addClass('js-form-required form-required');
         }
       } else {
-        $(e.target).removeAttr('required aria-required').closest('.js-form-item, .js-form-wrapper').find('label.js-form-required').removeClass('js-form-required form-required');
+        $(e.target)
+          .removeAttr('required aria-required')
+          .closest('.js-form-item, .js-form-wrapper')
+          .find('label.js-form-required')
+          .removeClass('js-form-required form-required');
       }
     }
   });
-  $document.on('state:visible', e => {
+
+  $document.on('state:visible', (e) => {
     if (e.trigger) {
-      $(e.target).closest('.js-form-item, .js-form-submit, .js-form-wrapper').toggle(e.value);
+      $(e.target)
+        .closest('.js-form-item, .js-form-submit, .js-form-wrapper')
+        .toggle(e.value);
     }
   });
-  $document.on('state:checked', e => {
+
+  $document.on('state:checked', (e) => {
     if (e.trigger) {
       $(e.target).prop('checked', e.value);
     }
   });
-  $document.on('state:collapsed', e => {
+
+  $document.on('state:collapsed', (e) => {
     if (e.trigger) {
       if ($(e.target).is('[open]') === e.value) {
         $(e.target).find('> summary').trigger('click');
       }
     }
   });
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/misc/tabbingmanager.es6.js b/core/misc/tabbingmanager.es6.js
deleted file mode 100644
index 3d4a0f840ea9..000000000000
--- a/core/misc/tabbingmanager.es6.js
+++ /dev/null
@@ -1,412 +0,0 @@
-/**
- * @file
- * Manages page tabbing modifications made by modules.
- */
-
-/**
- * Allow modules to respond to the constrain event.
- *
- * @event drupalTabbingConstrained
- */
-
-/**
- * Allow modules to respond to the tabbingContext release event.
- *
- * @event drupalTabbingContextReleased
- */
-
-/**
- * Allow modules to respond to the constrain event.
- *
- * @event drupalTabbingContextActivated
- */
-
-/**
- * Allow modules to respond to the constrain event.
- *
- * @event drupalTabbingContextDeactivated
- */
-
-(function ($, Drupal, { tabbable, isTabbable }) {
-  /**
-   * Provides an API for managing page tabbing order modifications.
-   *
-   * @constructor Drupal~TabbingManager
-   */
-  function TabbingManager() {
-    /**
-     * Tabbing sets are stored as a stack. The active set is at the top of the
-     * stack. We use a JavaScript array as if it were a stack; we consider the
-     * first element to be the bottom and the last element to be the top. This
-     * allows us to use JavaScript's built-in Array.push() and Array.pop()
-     * methods.
-     *
-     * @type {Array.<Drupal~TabbingContext>}
-     */
-    this.stack = [];
-  }
-
-  /**
-   * Stores a set of tabbable elements.
-   *
-   * This constraint can be removed with the release() method.
-   *
-   * @constructor Drupal~TabbingContext
-   *
-   * @param {object} options
-   *   A set of initiating values
-   * @param {number} options.level
-   *   The level in the TabbingManager's stack of this tabbingContext.
-   * @param {jQuery} options.$tabbableElements
-   *   The DOM elements that should be reachable via the tab key when this
-   *   tabbingContext is active.
-   * @param {jQuery} options.$disabledElements
-   *   The DOM elements that should not be reachable via the tab key when this
-   *   tabbingContext is active.
-   * @param {bool} options.released
-   *   A released tabbingContext can never be activated again. It will be
-   *   cleaned up when the TabbingManager unwinds its stack.
-   * @param {bool} options.active
-   *   When true, the tabbable elements of this tabbingContext will be reachable
-   *   via the tab key and the disabled elements will not. Only one
-   *   tabbingContext can be active at a time.
-   *  @param {bool} options.trapFocus
-   *   When true, focus is trapped within the tabbable elements, i.e. focus will
-   *   remain within the browser.
-   */
-  function TabbingContext(options) {
-    $.extend(
-      this,
-      /** @lends Drupal~TabbingContext# */ {
-        /**
-         * @type {?number}
-         */
-        level: null,
-
-        /**
-         * @type {jQuery}
-         */
-        $tabbableElements: $(),
-
-        /**
-         * @type {jQuery}
-         */
-        $disabledElements: $(),
-
-        /**
-         * @type {bool}
-         */
-        released: false,
-
-        /**
-         * @type {bool}
-         */
-        active: false,
-
-        /**
-         * @type {bool}
-         */
-        trapFocus: false,
-      },
-      options,
-    );
-  }
-
-  /**
-   * Add public methods to the TabbingManager class.
-   */
-  $.extend(
-    TabbingManager.prototype,
-    /** @lends Drupal~TabbingManager# */ {
-      /**
-       * Constrain tabbing to the specified set of elements only.
-       *
-       * Makes elements outside of the specified set of elements unreachable via
-       * the tab key.
-       *
-       * @param {jQuery|Selector|Element|ElementArray|object|selection} elements
-       *   The set of elements to which tabbing should be constrained. Can also
-       *   be any jQuery-compatible argument.
-       * @param {object} [options={}]
-       *   Constrain options.
-       * @param {boolean} [options.trapFocus=false]
-       *   When true, tabbing is trapped within the set of elements and can't
-       *   leave the browser. If the final element in the set is tabbed, the
-       *   first element in the set will receive focus. If the first element in
-       *   the set is shift-tabbed, the last element in the set will receive
-       *   focus.
-       *   When false, it is possible to tab out of the browser window by
-       *   tabbing the final element in the set or shift-tabbing the first
-       *   element in the set.
-       *
-       * @return {Drupal~TabbingContext}
-       *   The TabbingContext instance.
-       *
-       * @fires event:drupalTabbingConstrained
-       */
-      constrain(elements, { trapFocus = false } = {}) {
-        // Deactivate all tabbingContexts to prepare for the new constraint. A
-        // tabbingContext instance will only be reactivated if the stack is
-        // unwound to it in the _unwindStack() method.
-        const il = this.stack.length;
-        for (let i = 0; i < il; i++) {
-          this.stack[i].deactivate();
-        }
-
-        // The "active tabbing set" are the elements tabbing should be constrained
-        // to.
-        let tabbableElements = [];
-        $(elements).each((index, rootElement) => {
-          tabbableElements = [...tabbableElements, ...tabbable(rootElement)];
-          if (isTabbable(rootElement)) {
-            tabbableElements = [...tabbableElements, rootElement];
-          }
-        });
-
-        const tabbingContext = new TabbingContext({
-          // The level is the current height of the stack before this new
-          // tabbingContext is pushed on top of the stack.
-          level: this.stack.length,
-          $tabbableElements: $(tabbableElements),
-          trapFocus,
-        });
-
-        this.stack.push(tabbingContext);
-
-        // Activates the tabbingContext; this will manipulate the DOM to constrain
-        // tabbing.
-        tabbingContext.activate();
-
-        // Allow modules to respond to the constrain event.
-        $(document).trigger('drupalTabbingConstrained', tabbingContext);
-
-        return tabbingContext;
-      },
-
-      /**
-       * Restores a former tabbingContext when an active one is released.
-       *
-       * The TabbingManager stack of tabbingContext instances will be unwound
-       * from the top-most released tabbingContext down to the first non-released
-       * tabbingContext instance. This non-released instance is then activated.
-       */
-      release() {
-        // Unwind as far as possible: find the topmost non-released
-        // tabbingContext.
-        let toActivate = this.stack.length - 1;
-        while (toActivate >= 0 && this.stack[toActivate].released) {
-          toActivate--;
-        }
-
-        // Delete all tabbingContexts after the to be activated one. They have
-        // already been deactivated, so their effect on the DOM has been reversed.
-        this.stack.splice(toActivate + 1);
-
-        // Get topmost tabbingContext, if one exists, and activate it.
-        if (toActivate >= 0) {
-          this.stack[toActivate].activate();
-        }
-      },
-
-      /**
-       * Makes all elements outside of the tabbingContext's set untabbable.
-       *
-       * Elements made untabbable have their original tabindex and autofocus
-       * values stored so that they might be restored later when this
-       * tabbingContext is deactivated.
-       *
-       * @param {Drupal~TabbingContext} tabbingContext
-       *   The TabbingContext instance that has been activated.
-       */
-      activate(tabbingContext) {
-        const $set = tabbingContext.$tabbableElements;
-        const level = tabbingContext.level;
-        // Determine which elements are reachable via tabbing by default.
-        const $disabledSet = $(tabbable(document.body))
-          // Exclude elements of the active tabbing set.
-          .not($set);
-        // Set the disabled set on the tabbingContext.
-        tabbingContext.$disabledElements = $disabledSet;
-        // Record the tabindex for each element, so we can restore it later.
-        const il = $disabledSet.length;
-        for (let i = 0; i < il; i++) {
-          this.recordTabindex($disabledSet.eq(i), level);
-        }
-        // Make all tabbable elements outside of the active tabbing set
-        // unreachable.
-        $disabledSet.prop('tabindex', -1).prop('autofocus', false);
-
-        // Set focus on an element in the tabbingContext's set of tabbable
-        // elements. First, check if there is an element with an autofocus
-        // attribute. Select the last one from the DOM order.
-        let $hasFocus = $set.filter('[autofocus]').eq(-1);
-        // If no element in the tabbable set has an autofocus attribute, select
-        // the first element in the set.
-        if ($hasFocus.length === 0) {
-          $hasFocus = $set.eq(0);
-        }
-        $hasFocus.trigger('focus');
-
-        // Trap focus within the set.
-        if ($set.length && tabbingContext.trapFocus) {
-          $set.last().on('keydown.focus-trap', (event) => {
-            if (event.key === 'Tab' && !event.shiftKey) {
-              event.preventDefault();
-              $set.first().focus();
-            }
-          });
-          $set.first().on('keydown.focus-trap', (event) => {
-            if (event.key === 'Tab' && event.shiftKey) {
-              event.preventDefault();
-              $set.last().focus();
-            }
-          });
-        }
-      },
-
-      /**
-       * Restores that tabbable state of a tabbingContext's disabled elements.
-       *
-       * Elements that were made untabbable have their original tabindex and
-       * autofocus values restored.
-       *
-       * @param {Drupal~TabbingContext} tabbingContext
-       *   The TabbingContext instance that has been deactivated.
-       */
-      deactivate(tabbingContext) {
-        const $set = tabbingContext.$disabledElements;
-        const level = tabbingContext.level;
-        const il = $set.length;
-
-        tabbingContext.$tabbableElements.first().off('keydown.focus-trap');
-        tabbingContext.$tabbableElements.last().off('keydown.focus-trap');
-        for (let i = 0; i < il; i++) {
-          this.restoreTabindex($set.eq(i), level);
-        }
-      },
-
-      /**
-       * Records the tabindex and autofocus values of an untabbable element.
-       *
-       * @param {jQuery} $el
-       *   The set of elements that have been disabled.
-       * @param {number} level
-       *   The stack level for which the tabindex attribute should be recorded.
-       */
-      recordTabindex($el, level) {
-        const tabInfo = $el.data('drupalOriginalTabIndices') || {};
-        tabInfo[level] = {
-          tabindex: $el[0].getAttribute('tabindex'),
-          autofocus: $el[0].hasAttribute('autofocus'),
-        };
-        $el.data('drupalOriginalTabIndices', tabInfo);
-      },
-
-      /**
-       * Restores the tabindex and autofocus values of a reactivated element.
-       *
-       * @param {jQuery} $el
-       *   The element that is being reactivated.
-       * @param {number} level
-       *   The stack level for which the tabindex attribute should be restored.
-       */
-      restoreTabindex($el, level) {
-        const tabInfo = $el.data('drupalOriginalTabIndices');
-        if (tabInfo && tabInfo[level]) {
-          const data = tabInfo[level];
-          if (data.tabindex) {
-            $el[0].setAttribute('tabindex', data.tabindex);
-          }
-          // If the element did not have a tabindex at this stack level then
-          // remove it.
-          else {
-            $el[0].removeAttribute('tabindex');
-          }
-          if (data.autofocus) {
-            $el[0].setAttribute('autofocus', 'autofocus');
-          }
-
-          // Clean up $.data.
-          if (level === 0) {
-            // Remove all data.
-            $el.removeData('drupalOriginalTabIndices');
-          } else {
-            // Remove the data for this stack level and higher.
-            let levelToDelete = level;
-            while (tabInfo.hasOwnProperty(levelToDelete)) {
-              delete tabInfo[levelToDelete];
-              levelToDelete++;
-            }
-            $el.data('drupalOriginalTabIndices', tabInfo);
-          }
-        }
-      },
-    },
-  );
-
-  /**
-   * Add public methods to the TabbingContext class.
-   */
-  $.extend(
-    TabbingContext.prototype,
-    /** @lends Drupal~TabbingContext# */ {
-      /**
-       * Releases this TabbingContext.
-       *
-       * Once a TabbingContext object is released, it can never be activated
-       * again.
-       *
-       * @fires event:drupalTabbingContextReleased
-       */
-      release() {
-        if (!this.released) {
-          this.deactivate();
-          this.released = true;
-          Drupal.tabbingManager.release(this);
-          // Allow modules to respond to the tabbingContext release event.
-          $(document).trigger('drupalTabbingContextReleased', this);
-        }
-      },
-
-      /**
-       * Activates this TabbingContext.
-       *
-       * @fires event:drupalTabbingContextActivated
-       */
-      activate() {
-        // A released TabbingContext object can never be activated again.
-        if (!this.active && !this.released) {
-          this.active = true;
-          Drupal.tabbingManager.activate(this);
-          // Allow modules to respond to the constrain event.
-          $(document).trigger('drupalTabbingContextActivated', this);
-        }
-      },
-
-      /**
-       * Deactivates this TabbingContext.
-       *
-       * @fires event:drupalTabbingContextDeactivated
-       */
-      deactivate() {
-        if (this.active) {
-          this.active = false;
-          Drupal.tabbingManager.deactivate(this);
-          // Allow modules to respond to the constrain event.
-          $(document).trigger('drupalTabbingContextDeactivated', this);
-        }
-      },
-    },
-  );
-
-  // Mark this behavior as processed on the first pass and return if it is
-  // already processed.
-  if (Drupal.tabbingManager) {
-    return;
-  }
-
-  /**
-   * @type {Drupal~TabbingManager}
-   */
-  Drupal.tabbingManager = new TabbingManager();
-})(jQuery, Drupal, window.tabbable);
diff --git a/core/misc/tabbingmanager.js b/core/misc/tabbingmanager.js
index a44a0adeb9cb..3d4a0f840ea9 100644
--- a/core/misc/tabbingmanager.js
+++ b/core/misc/tabbingmanager.js
@@ -1,195 +1,412 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(function ($, Drupal, _ref) {
-  let {
-    tabbable,
-    isTabbable
-  } = _ref;
+ * @file
+ * Manages page tabbing modifications made by modules.
+ */
 
+/**
+ * Allow modules to respond to the constrain event.
+ *
+ * @event drupalTabbingConstrained
+ */
+
+/**
+ * Allow modules to respond to the tabbingContext release event.
+ *
+ * @event drupalTabbingContextReleased
+ */
+
+/**
+ * Allow modules to respond to the constrain event.
+ *
+ * @event drupalTabbingContextActivated
+ */
+
+/**
+ * Allow modules to respond to the constrain event.
+ *
+ * @event drupalTabbingContextDeactivated
+ */
+
+(function ($, Drupal, { tabbable, isTabbable }) {
+  /**
+   * Provides an API for managing page tabbing order modifications.
+   *
+   * @constructor Drupal~TabbingManager
+   */
   function TabbingManager() {
+    /**
+     * Tabbing sets are stored as a stack. The active set is at the top of the
+     * stack. We use a JavaScript array as if it were a stack; we consider the
+     * first element to be the bottom and the last element to be the top. This
+     * allows us to use JavaScript's built-in Array.push() and Array.pop()
+     * methods.
+     *
+     * @type {Array.<Drupal~TabbingContext>}
+     */
     this.stack = [];
   }
 
+  /**
+   * Stores a set of tabbable elements.
+   *
+   * This constraint can be removed with the release() method.
+   *
+   * @constructor Drupal~TabbingContext
+   *
+   * @param {object} options
+   *   A set of initiating values
+   * @param {number} options.level
+   *   The level in the TabbingManager's stack of this tabbingContext.
+   * @param {jQuery} options.$tabbableElements
+   *   The DOM elements that should be reachable via the tab key when this
+   *   tabbingContext is active.
+   * @param {jQuery} options.$disabledElements
+   *   The DOM elements that should not be reachable via the tab key when this
+   *   tabbingContext is active.
+   * @param {bool} options.released
+   *   A released tabbingContext can never be activated again. It will be
+   *   cleaned up when the TabbingManager unwinds its stack.
+   * @param {bool} options.active
+   *   When true, the tabbable elements of this tabbingContext will be reachable
+   *   via the tab key and the disabled elements will not. Only one
+   *   tabbingContext can be active at a time.
+   *  @param {bool} options.trapFocus
+   *   When true, focus is trapped within the tabbable elements, i.e. focus will
+   *   remain within the browser.
+   */
   function TabbingContext(options) {
-    $.extend(this, {
-      level: null,
-      $tabbableElements: $(),
-      $disabledElements: $(),
-      released: false,
-      active: false,
-      trapFocus: false
-    }, options);
+    $.extend(
+      this,
+      /** @lends Drupal~TabbingContext# */ {
+        /**
+         * @type {?number}
+         */
+        level: null,
+
+        /**
+         * @type {jQuery}
+         */
+        $tabbableElements: $(),
+
+        /**
+         * @type {jQuery}
+         */
+        $disabledElements: $(),
+
+        /**
+         * @type {bool}
+         */
+        released: false,
+
+        /**
+         * @type {bool}
+         */
+        active: false,
+
+        /**
+         * @type {bool}
+         */
+        trapFocus: false,
+      },
+      options,
+    );
   }
 
-  $.extend(TabbingManager.prototype, {
-    constrain(elements) {
-      let {
-        trapFocus = false
-      } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
-      const il = this.stack.length;
-
-      for (let i = 0; i < il; i++) {
-        this.stack[i].deactivate();
-      }
-
-      let tabbableElements = [];
-      $(elements).each((index, rootElement) => {
-        tabbableElements = [...tabbableElements, ...tabbable(rootElement)];
-
-        if (isTabbable(rootElement)) {
-          tabbableElements = [...tabbableElements, rootElement];
+  /**
+   * Add public methods to the TabbingManager class.
+   */
+  $.extend(
+    TabbingManager.prototype,
+    /** @lends Drupal~TabbingManager# */ {
+      /**
+       * Constrain tabbing to the specified set of elements only.
+       *
+       * Makes elements outside of the specified set of elements unreachable via
+       * the tab key.
+       *
+       * @param {jQuery|Selector|Element|ElementArray|object|selection} elements
+       *   The set of elements to which tabbing should be constrained. Can also
+       *   be any jQuery-compatible argument.
+       * @param {object} [options={}]
+       *   Constrain options.
+       * @param {boolean} [options.trapFocus=false]
+       *   When true, tabbing is trapped within the set of elements and can't
+       *   leave the browser. If the final element in the set is tabbed, the
+       *   first element in the set will receive focus. If the first element in
+       *   the set is shift-tabbed, the last element in the set will receive
+       *   focus.
+       *   When false, it is possible to tab out of the browser window by
+       *   tabbing the final element in the set or shift-tabbing the first
+       *   element in the set.
+       *
+       * @return {Drupal~TabbingContext}
+       *   The TabbingContext instance.
+       *
+       * @fires event:drupalTabbingConstrained
+       */
+      constrain(elements, { trapFocus = false } = {}) {
+        // Deactivate all tabbingContexts to prepare for the new constraint. A
+        // tabbingContext instance will only be reactivated if the stack is
+        // unwound to it in the _unwindStack() method.
+        const il = this.stack.length;
+        for (let i = 0; i < il; i++) {
+          this.stack[i].deactivate();
         }
-      });
-      const tabbingContext = new TabbingContext({
-        level: this.stack.length,
-        $tabbableElements: $(tabbableElements),
-        trapFocus
-      });
-      this.stack.push(tabbingContext);
-      tabbingContext.activate();
-      $(document).trigger('drupalTabbingConstrained', tabbingContext);
-      return tabbingContext;
-    },
-
-    release() {
-      let toActivate = this.stack.length - 1;
 
-      while (toActivate >= 0 && this.stack[toActivate].released) {
-        toActivate--;
-      }
-
-      this.stack.splice(toActivate + 1);
-
-      if (toActivate >= 0) {
-        this.stack[toActivate].activate();
-      }
-    },
-
-    activate(tabbingContext) {
-      const $set = tabbingContext.$tabbableElements;
-      const level = tabbingContext.level;
-      const $disabledSet = $(tabbable(document.body)).not($set);
-      tabbingContext.$disabledElements = $disabledSet;
-      const il = $disabledSet.length;
-
-      for (let i = 0; i < il; i++) {
-        this.recordTabindex($disabledSet.eq(i), level);
-      }
-
-      $disabledSet.prop('tabindex', -1).prop('autofocus', false);
-      let $hasFocus = $set.filter('[autofocus]').eq(-1);
-
-      if ($hasFocus.length === 0) {
-        $hasFocus = $set.eq(0);
-      }
-
-      $hasFocus.trigger('focus');
-
-      if ($set.length && tabbingContext.trapFocus) {
-        $set.last().on('keydown.focus-trap', event => {
-          if (event.key === 'Tab' && !event.shiftKey) {
-            event.preventDefault();
-            $set.first().focus();
-          }
-        });
-        $set.first().on('keydown.focus-trap', event => {
-          if (event.key === 'Tab' && event.shiftKey) {
-            event.preventDefault();
-            $set.last().focus();
+        // The "active tabbing set" are the elements tabbing should be constrained
+        // to.
+        let tabbableElements = [];
+        $(elements).each((index, rootElement) => {
+          tabbableElements = [...tabbableElements, ...tabbable(rootElement)];
+          if (isTabbable(rootElement)) {
+            tabbableElements = [...tabbableElements, rootElement];
           }
         });
-      }
-    },
-
-    deactivate(tabbingContext) {
-      const $set = tabbingContext.$disabledElements;
-      const level = tabbingContext.level;
-      const il = $set.length;
-      tabbingContext.$tabbableElements.first().off('keydown.focus-trap');
-      tabbingContext.$tabbableElements.last().off('keydown.focus-trap');
-
-      for (let i = 0; i < il; i++) {
-        this.restoreTabindex($set.eq(i), level);
-      }
-    },
 
-    recordTabindex($el, level) {
-      const tabInfo = $el.data('drupalOriginalTabIndices') || {};
-      tabInfo[level] = {
-        tabindex: $el[0].getAttribute('tabindex'),
-        autofocus: $el[0].hasAttribute('autofocus')
-      };
-      $el.data('drupalOriginalTabIndices', tabInfo);
-    },
+        const tabbingContext = new TabbingContext({
+          // The level is the current height of the stack before this new
+          // tabbingContext is pushed on top of the stack.
+          level: this.stack.length,
+          $tabbableElements: $(tabbableElements),
+          trapFocus,
+        });
 
-    restoreTabindex($el, level) {
-      const tabInfo = $el.data('drupalOriginalTabIndices');
+        this.stack.push(tabbingContext);
+
+        // Activates the tabbingContext; this will manipulate the DOM to constrain
+        // tabbing.
+        tabbingContext.activate();
+
+        // Allow modules to respond to the constrain event.
+        $(document).trigger('drupalTabbingConstrained', tabbingContext);
+
+        return tabbingContext;
+      },
+
+      /**
+       * Restores a former tabbingContext when an active one is released.
+       *
+       * The TabbingManager stack of tabbingContext instances will be unwound
+       * from the top-most released tabbingContext down to the first non-released
+       * tabbingContext instance. This non-released instance is then activated.
+       */
+      release() {
+        // Unwind as far as possible: find the topmost non-released
+        // tabbingContext.
+        let toActivate = this.stack.length - 1;
+        while (toActivate >= 0 && this.stack[toActivate].released) {
+          toActivate--;
+        }
 
-      if (tabInfo && tabInfo[level]) {
-        const data = tabInfo[level];
+        // Delete all tabbingContexts after the to be activated one. They have
+        // already been deactivated, so their effect on the DOM has been reversed.
+        this.stack.splice(toActivate + 1);
 
-        if (data.tabindex) {
-          $el[0].setAttribute('tabindex', data.tabindex);
-        } else {
-          $el[0].removeAttribute('tabindex');
+        // Get topmost tabbingContext, if one exists, and activate it.
+        if (toActivate >= 0) {
+          this.stack[toActivate].activate();
         }
-
-        if (data.autofocus) {
-          $el[0].setAttribute('autofocus', 'autofocus');
+      },
+
+      /**
+       * Makes all elements outside of the tabbingContext's set untabbable.
+       *
+       * Elements made untabbable have their original tabindex and autofocus
+       * values stored so that they might be restored later when this
+       * tabbingContext is deactivated.
+       *
+       * @param {Drupal~TabbingContext} tabbingContext
+       *   The TabbingContext instance that has been activated.
+       */
+      activate(tabbingContext) {
+        const $set = tabbingContext.$tabbableElements;
+        const level = tabbingContext.level;
+        // Determine which elements are reachable via tabbing by default.
+        const $disabledSet = $(tabbable(document.body))
+          // Exclude elements of the active tabbing set.
+          .not($set);
+        // Set the disabled set on the tabbingContext.
+        tabbingContext.$disabledElements = $disabledSet;
+        // Record the tabindex for each element, so we can restore it later.
+        const il = $disabledSet.length;
+        for (let i = 0; i < il; i++) {
+          this.recordTabindex($disabledSet.eq(i), level);
         }
-
-        if (level === 0) {
-          $el.removeData('drupalOriginalTabIndices');
-        } else {
-          let levelToDelete = level;
-
-          while (tabInfo.hasOwnProperty(levelToDelete)) {
-            delete tabInfo[levelToDelete];
-            levelToDelete++;
+        // Make all tabbable elements outside of the active tabbing set
+        // unreachable.
+        $disabledSet.prop('tabindex', -1).prop('autofocus', false);
+
+        // Set focus on an element in the tabbingContext's set of tabbable
+        // elements. First, check if there is an element with an autofocus
+        // attribute. Select the last one from the DOM order.
+        let $hasFocus = $set.filter('[autofocus]').eq(-1);
+        // If no element in the tabbable set has an autofocus attribute, select
+        // the first element in the set.
+        if ($hasFocus.length === 0) {
+          $hasFocus = $set.eq(0);
+        }
+        $hasFocus.trigger('focus');
+
+        // Trap focus within the set.
+        if ($set.length && tabbingContext.trapFocus) {
+          $set.last().on('keydown.focus-trap', (event) => {
+            if (event.key === 'Tab' && !event.shiftKey) {
+              event.preventDefault();
+              $set.first().focus();
+            }
+          });
+          $set.first().on('keydown.focus-trap', (event) => {
+            if (event.key === 'Tab' && event.shiftKey) {
+              event.preventDefault();
+              $set.last().focus();
+            }
+          });
+        }
+      },
+
+      /**
+       * Restores that tabbable state of a tabbingContext's disabled elements.
+       *
+       * Elements that were made untabbable have their original tabindex and
+       * autofocus values restored.
+       *
+       * @param {Drupal~TabbingContext} tabbingContext
+       *   The TabbingContext instance that has been deactivated.
+       */
+      deactivate(tabbingContext) {
+        const $set = tabbingContext.$disabledElements;
+        const level = tabbingContext.level;
+        const il = $set.length;
+
+        tabbingContext.$tabbableElements.first().off('keydown.focus-trap');
+        tabbingContext.$tabbableElements.last().off('keydown.focus-trap');
+        for (let i = 0; i < il; i++) {
+          this.restoreTabindex($set.eq(i), level);
+        }
+      },
+
+      /**
+       * Records the tabindex and autofocus values of an untabbable element.
+       *
+       * @param {jQuery} $el
+       *   The set of elements that have been disabled.
+       * @param {number} level
+       *   The stack level for which the tabindex attribute should be recorded.
+       */
+      recordTabindex($el, level) {
+        const tabInfo = $el.data('drupalOriginalTabIndices') || {};
+        tabInfo[level] = {
+          tabindex: $el[0].getAttribute('tabindex'),
+          autofocus: $el[0].hasAttribute('autofocus'),
+        };
+        $el.data('drupalOriginalTabIndices', tabInfo);
+      },
+
+      /**
+       * Restores the tabindex and autofocus values of a reactivated element.
+       *
+       * @param {jQuery} $el
+       *   The element that is being reactivated.
+       * @param {number} level
+       *   The stack level for which the tabindex attribute should be restored.
+       */
+      restoreTabindex($el, level) {
+        const tabInfo = $el.data('drupalOriginalTabIndices');
+        if (tabInfo && tabInfo[level]) {
+          const data = tabInfo[level];
+          if (data.tabindex) {
+            $el[0].setAttribute('tabindex', data.tabindex);
+          }
+          // If the element did not have a tabindex at this stack level then
+          // remove it.
+          else {
+            $el[0].removeAttribute('tabindex');
+          }
+          if (data.autofocus) {
+            $el[0].setAttribute('autofocus', 'autofocus');
           }
 
-          $el.data('drupalOriginalTabIndices', tabInfo);
+          // Clean up $.data.
+          if (level === 0) {
+            // Remove all data.
+            $el.removeData('drupalOriginalTabIndices');
+          } else {
+            // Remove the data for this stack level and higher.
+            let levelToDelete = level;
+            while (tabInfo.hasOwnProperty(levelToDelete)) {
+              delete tabInfo[levelToDelete];
+              levelToDelete++;
+            }
+            $el.data('drupalOriginalTabIndices', tabInfo);
+          }
         }
-      }
-    }
-
-  });
-  $.extend(TabbingContext.prototype, {
-    release() {
-      if (!this.released) {
-        this.deactivate();
-        this.released = true;
-        Drupal.tabbingManager.release(this);
-        $(document).trigger('drupalTabbingContextReleased', this);
-      }
+      },
     },
-
-    activate() {
-      if (!this.active && !this.released) {
-        this.active = true;
-        Drupal.tabbingManager.activate(this);
-        $(document).trigger('drupalTabbingContextActivated', this);
-      }
+  );
+
+  /**
+   * Add public methods to the TabbingContext class.
+   */
+  $.extend(
+    TabbingContext.prototype,
+    /** @lends Drupal~TabbingContext# */ {
+      /**
+       * Releases this TabbingContext.
+       *
+       * Once a TabbingContext object is released, it can never be activated
+       * again.
+       *
+       * @fires event:drupalTabbingContextReleased
+       */
+      release() {
+        if (!this.released) {
+          this.deactivate();
+          this.released = true;
+          Drupal.tabbingManager.release(this);
+          // Allow modules to respond to the tabbingContext release event.
+          $(document).trigger('drupalTabbingContextReleased', this);
+        }
+      },
+
+      /**
+       * Activates this TabbingContext.
+       *
+       * @fires event:drupalTabbingContextActivated
+       */
+      activate() {
+        // A released TabbingContext object can never be activated again.
+        if (!this.active && !this.released) {
+          this.active = true;
+          Drupal.tabbingManager.activate(this);
+          // Allow modules to respond to the constrain event.
+          $(document).trigger('drupalTabbingContextActivated', this);
+        }
+      },
+
+      /**
+       * Deactivates this TabbingContext.
+       *
+       * @fires event:drupalTabbingContextDeactivated
+       */
+      deactivate() {
+        if (this.active) {
+          this.active = false;
+          Drupal.tabbingManager.deactivate(this);
+          // Allow modules to respond to the constrain event.
+          $(document).trigger('drupalTabbingContextDeactivated', this);
+        }
+      },
     },
+  );
 
-    deactivate() {
-      if (this.active) {
-        this.active = false;
-        Drupal.tabbingManager.deactivate(this);
-        $(document).trigger('drupalTabbingContextDeactivated', this);
-      }
-    }
-
-  });
-
+  // Mark this behavior as processed on the first pass and return if it is
+  // already processed.
   if (Drupal.tabbingManager) {
     return;
   }
 
+  /**
+   * @type {Drupal~TabbingManager}
+   */
   Drupal.tabbingManager = new TabbingManager();
-})(jQuery, Drupal, window.tabbable);
\ No newline at end of file
+})(jQuery, Drupal, window.tabbable);
diff --git a/core/misc/tabledrag.es6.js b/core/misc/tabledrag.es6.js
deleted file mode 100644
index b54ed771491b..000000000000
--- a/core/misc/tabledrag.es6.js
+++ /dev/null
@@ -1,1711 +0,0 @@
-/**
- * @file
- * Provide dragging capabilities to admin uis.
- */
-
-/**
- * Triggers when weights columns are toggled.
- *
- * @event columnschange
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Store the state of weight columns display for all tables.
-   *
-   * Default value is to hide weight columns.
-   */
-  let showWeight = JSON.parse(
-    localStorage.getItem('Drupal.tableDrag.showWeight'),
-  );
-
-  /**
-   * Drag and drop table rows with field manipulation.
-   *
-   * Using the drupal_attach_tabledrag() function, any table with weights or
-   * parent relationships may be made into draggable tables. Columns containing
-   * a field may optionally be hidden, providing a better user experience.
-   *
-   * Created tableDrag instances may be modified with custom behaviors by
-   * overriding the .onDrag, .onDrop, .row.onSwap, and .row.onIndent methods.
-   * See blocks.js for an example of adding additional functionality to
-   * tableDrag.
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.tableDrag = {
-    attach(context, settings) {
-      function initTableDrag(table, base) {
-        if (table.length) {
-          // Create the new tableDrag instance. Save in the Drupal variable
-          // to allow other scripts access to the object.
-          Drupal.tableDrag[base] = new Drupal.tableDrag(
-            table[0],
-            settings.tableDrag[base],
-          );
-        }
-      }
-
-      Object.keys(settings.tableDrag || {}).forEach((base) => {
-        initTableDrag($(once('tabledrag', `#${base}`, context)), base);
-      });
-    },
-  };
-
-  /**
-   * Provides table and field manipulation.
-   *
-   * @constructor
-   *
-   * @param {HTMLElement} table
-   *   DOM object for the table to be made draggable.
-   * @param {object} tableSettings
-   *   Settings for the table added via drupal_add_dragtable().
-   */
-  Drupal.tableDrag = function (table, tableSettings) {
-    const self = this;
-    const $table = $(table);
-
-    /**
-     * @type {jQuery}
-     */
-    this.$table = $(table);
-
-    /**
-     *
-     * @type {HTMLElement}
-     */
-    this.table = table;
-
-    /**
-     * @type {object}
-     */
-    this.tableSettings = tableSettings;
-
-    /**
-     * Used to hold information about a current drag operation.
-     *
-     * @type {?HTMLElement}
-     */
-    this.dragObject = null;
-
-    /**
-     * Provides operations for row manipulation.
-     *
-     * @type {?HTMLElement}
-     */
-    this.rowObject = null;
-
-    /**
-     * Remember the previous element.
-     *
-     * @type {?HTMLElement}
-     */
-    this.oldRowElement = null;
-
-    /**
-     * Used to determine up or down direction from last mouse move.
-     *
-     * @type {?number}
-     */
-    this.oldY = null;
-
-    /**
-     * Whether anything in the entire table has changed.
-     *
-     * @type {bool}
-     */
-    this.changed = false;
-
-    /**
-     * Maximum amount of allowed parenting.
-     *
-     * @type {number}
-     */
-    this.maxDepth = 0;
-
-    /**
-     * Direction of the table.
-     *
-     * @type {number}
-     */
-    this.rtl = $(this.table).css('direction') === 'rtl' ? -1 : 1;
-
-    /**
-     *
-     * @type {bool}
-     */
-    this.striping = $(this.table).data('striping') === 1;
-
-    /**
-     * Configure the scroll settings.
-     *
-     * @type {object}
-     *
-     * @prop {number} amount
-     * @prop {number} interval
-     * @prop {number} trigger
-     */
-    this.scrollSettings = { amount: 4, interval: 50, trigger: 70 };
-
-    /**
-     *
-     * @type {?number}
-     */
-    this.scrollInterval = null;
-
-    /**
-     *
-     * @type {number}
-     */
-    this.scrollY = 0;
-
-    /**
-     *
-     * @type {number}
-     */
-    this.windowHeight = 0;
-
-    /**
-     * @type {?jQuery}
-     */
-    this.$toggleWeightButton = null;
-
-    /**
-     * Check this table's settings for parent relationships.
-     *
-     * For efficiency, large sections of code can be skipped if we don't need to
-     * track horizontal movement and indentations.
-     *
-     * @type {bool}
-     */
-    this.indentEnabled = false;
-    Object.keys(tableSettings || {}).forEach((group) => {
-      Object.keys(tableSettings[group] || {}).forEach((n) => {
-        if (tableSettings[group][n].relationship === 'parent') {
-          this.indentEnabled = true;
-        }
-        if (tableSettings[group][n].limit > 0) {
-          this.maxDepth = tableSettings[group][n].limit;
-        }
-      });
-    });
-    if (this.indentEnabled) {
-      /**
-       * Total width of indents, set in makeDraggable.
-       *
-       * @type {number}
-       */
-      this.indentCount = 1;
-      // Find the width of indentations to measure mouse movements against.
-      // Because the table doesn't need to start with any indentations, we
-      // manually append 2 indentations in the first draggable row, measure
-      // the offset, then remove.
-      const indent = Drupal.theme('tableDragIndentation');
-      const testRow = $('<tr></tr>').addClass('draggable').appendTo(table);
-      const testCell = $('<td></td>')
-        .appendTo(testRow)
-        .prepend(indent)
-        .prepend(indent);
-      const $indentation = testCell.find('.js-indentation');
-
-      /**
-       *
-       * @type {number}
-       */
-      this.indentAmount =
-        $indentation.get(1).offsetLeft - $indentation.get(0).offsetLeft;
-      testRow.remove();
-    }
-
-    // Make each applicable row draggable.
-    // Match immediate children of the parent element to allow nesting.
-    $table.find('> tr.draggable, > tbody > tr.draggable').each(function () {
-      self.makeDraggable(this);
-    });
-
-    const $toggleWeightWrapper = $(Drupal.theme('tableDragToggle'));
-    this.$toggleWeightButton = $toggleWeightWrapper.find(
-      '[data-drupal-selector="tabledrag-toggle-weight"]',
-    );
-    this.$toggleWeightButton.on(
-      'click',
-      $.proxy(function (e) {
-        e.preventDefault();
-        this.toggleColumns();
-      }, this),
-    );
-    $table.before($toggleWeightWrapper);
-
-    // Initialize the specified columns (for example, weight or parent columns)
-    // to show or hide according to user preference. This aids accessibility
-    // so that, e.g., screen reader users can choose to enter weight values and
-    // manipulate form elements directly, rather than using drag-and-drop..
-    self.initColumns();
-
-    // Add event bindings to the document. The self variable is passed along
-    // as event handlers do not have direct access to the tableDrag object.
-    $(document).on('touchmove', (event) =>
-      self.dragRow(event.originalEvent.touches[0], self),
-    );
-    $(document).on('touchend', (event) =>
-      self.dropRow(event.originalEvent.touches[0], self),
-    );
-    $(document).on('mousemove pointermove', (event) =>
-      self.dragRow(event, self),
-    );
-    $(document).on('mouseup pointerup', (event) => self.dropRow(event, self));
-
-    // React to localStorage event showing or hiding weight columns.
-    $(window).on(
-      'storage',
-      $.proxy(function (e) {
-        // Only react to 'Drupal.tableDrag.showWeight' value change.
-        if (e.originalEvent.key === 'Drupal.tableDrag.showWeight') {
-          // This was changed in another window, get the new value for this
-          // window.
-          showWeight = JSON.parse(e.originalEvent.newValue);
-          this.displayColumns(showWeight);
-        }
-      }, this),
-    );
-  };
-
-  /**
-   * Initialize columns containing form elements to be hidden by default.
-   *
-   * Identify and mark each cell with a CSS class so we can easily toggle
-   * show/hide it. Finally, hide columns if user does not have a
-   * 'Drupal.tableDrag.showWeight' localStorage value.
-   */
-  Drupal.tableDrag.prototype.initColumns = function () {
-    const $table = this.$table;
-    let hidden;
-    let cell;
-    let columnIndex;
-    Object.keys(this.tableSettings || {}).forEach((group) => {
-      // Find the first field in this group.
-      Object.keys(this.tableSettings[group]).some((tableSetting) => {
-        const field = $table
-          .find(`.${this.tableSettings[group][tableSetting].target}`)
-          .eq(0);
-        if (field.length && this.tableSettings[group][tableSetting].hidden) {
-          hidden = this.tableSettings[group][tableSetting].hidden;
-          cell = field.closest('td');
-          return true;
-        }
-        return false;
-      });
-
-      // Mark the column containing this field so it can be hidden.
-      if (hidden && cell[0]) {
-        // Add 1 to our indexes. The nth-child selector is 1 based, not 0
-        // based. Match immediate children of the parent element to allow
-        // nesting.
-        columnIndex = cell.parent().find('> td').index(cell.get(0)) + 1;
-        $table
-          .find('> thead > tr, > tbody > tr, > tr')
-          .each(this.addColspanClass(columnIndex));
-      }
-    });
-    this.displayColumns(showWeight);
-  };
-
-  /**
-   * Mark cells that have colspan.
-   *
-   * In order to adjust the colspan instead of hiding them altogether.
-   *
-   * @param {number} columnIndex
-   *   The column index to add colspan class to.
-   *
-   * @return {function}
-   *   Function to add colspan class.
-   */
-  Drupal.tableDrag.prototype.addColspanClass = function (columnIndex) {
-    return function () {
-      // Get the columnIndex and adjust for any colspans in this row.
-      const $row = $(this);
-      let index = columnIndex;
-      const cells = $row.children();
-      let cell;
-      cells.each(function (n) {
-        if (n < index && this.colSpan && this.colSpan > 1) {
-          index -= this.colSpan - 1;
-        }
-      });
-      if (index > 0) {
-        cell = cells.filter(`:nth-child(${index})`);
-        if (cell[0].colSpan && cell[0].colSpan > 1) {
-          // If this cell has a colspan, mark it so we can reduce the colspan.
-          cell.addClass('tabledrag-has-colspan');
-        } else {
-          // Mark this cell so we can hide it.
-          cell.addClass('tabledrag-hide');
-        }
-      }
-    };
-  };
-
-  /**
-   * Hide or display weight columns. Triggers an event on change.
-   *
-   * @fires event:columnschange
-   *
-   * @param {bool} displayWeight
-   *   'true' will show weight columns.
-   */
-  Drupal.tableDrag.prototype.displayColumns = function (displayWeight) {
-    if (displayWeight) {
-      this.showColumns();
-    }
-    // Default action is to hide columns.
-    else {
-      this.hideColumns();
-    }
-
-    this.$toggleWeightButton.html(
-      Drupal.theme('toggleButtonContent', displayWeight),
-    );
-
-    // Trigger an event to allow other scripts to react to this display change.
-    // Force the extra parameter as a bool.
-    $(once.filter('tabledrag', 'table')).trigger(
-      'columnschange',
-      !!displayWeight,
-    );
-  };
-
-  /**
-   * Toggle the weight column depending on 'showWeight' value.
-   *
-   * Store only default override.
-   */
-  Drupal.tableDrag.prototype.toggleColumns = function () {
-    showWeight = !showWeight;
-    this.displayColumns(showWeight);
-    if (showWeight) {
-      // Save default override.
-      localStorage.setItem('Drupal.tableDrag.showWeight', showWeight);
-    } else {
-      // Reset the value to its default.
-      localStorage.removeItem('Drupal.tableDrag.showWeight');
-    }
-  };
-
-  /**
-   * Hide the columns containing weight/parent form elements.
-   *
-   * Undo showColumns().
-   */
-  Drupal.tableDrag.prototype.hideColumns = function () {
-    const $tables = $(once.filter('tabledrag', 'table'));
-    // Hide weight/parent cells and headers.
-    $tables.find('.tabledrag-hide').css('display', 'none');
-    // Show TableDrag handles.
-    $tables.find('.tabledrag-handle').css('display', '');
-    // Reduce the colspan of any effected multi-span columns.
-    $tables.find('.tabledrag-has-colspan').each(function () {
-      this.colSpan -= 1;
-    });
-  };
-
-  /**
-   * Show the columns containing weight/parent form elements.
-   *
-   * Undo hideColumns().
-   */
-  Drupal.tableDrag.prototype.showColumns = function () {
-    const $tables = $(once.filter('tabledrag', 'table'));
-    // Show weight/parent cells and headers.
-    $tables.find('.tabledrag-hide').css('display', '');
-    // Hide TableDrag handles.
-    $tables.find('.tabledrag-handle').css('display', 'none');
-    // Increase the colspan for any columns where it was previously reduced.
-    $tables.find('.tabledrag-has-colspan').each(function () {
-      this.colSpan += 1;
-    });
-  };
-
-  /**
-   * Find the target used within a particular row and group.
-   *
-   * @param {string} group
-   *   Group selector.
-   * @param {HTMLElement} row
-   *   The row HTML element.
-   *
-   * @return {object}
-   *   The table row settings.
-   */
-  Drupal.tableDrag.prototype.rowSettings = function (group, row) {
-    const field = $(row).find(`.${group}`);
-    const tableSettingsGroup = this.tableSettings[group];
-    return Object.keys(tableSettingsGroup)
-      .map((delta) => {
-        const targetClass = tableSettingsGroup[delta].target;
-        let rowSettings;
-        if (field.is(`.${targetClass}`)) {
-          // Return a copy of the row settings.
-          rowSettings = {};
-          Object.keys(tableSettingsGroup[delta]).forEach((n) => {
-            rowSettings[n] = tableSettingsGroup[delta][n];
-          });
-        }
-        return rowSettings;
-      })
-      .filter((rowSetting) => rowSetting)[0];
-  };
-
-  /**
-   * Take an item and add event handlers to make it become draggable.
-   *
-   * @param {HTMLElement} item
-   *   The item to add event handlers to.
-   */
-  Drupal.tableDrag.prototype.makeDraggable = function (item) {
-    const self = this;
-    const $item = $(item);
-    // Add a class to the title link.
-    $item.find('td:first-of-type').find('a').addClass('menu-item__link');
-    // Create the handle.
-    const $handle = $(Drupal.theme('tableDragHandle'));
-    // Insert the handle after indentations (if any).
-    const $indentationLast = $item
-      .find('td:first-of-type')
-      .find('.js-indentation')
-      .eq(-1);
-    if ($indentationLast.length) {
-      $indentationLast.after($handle);
-      // Update the total width of indentation in this entire table.
-      self.indentCount = Math.max(
-        $item.find('.js-indentation').length,
-        self.indentCount,
-      );
-    } else {
-      $item.find('td').eq(0).prepend($handle);
-    }
-
-    $handle.on('mousedown touchstart pointerdown', (event) => {
-      event.preventDefault();
-      if (event.originalEvent.type === 'touchstart') {
-        event = event.originalEvent.touches[0];
-      }
-      self.dragStart(event, self, item);
-    });
-
-    // Prevent the anchor tag from jumping us to the top of the page.
-    $handle.on('click', (e) => {
-      e.preventDefault();
-    });
-
-    // Set blur cleanup when a handle is focused.
-    $handle.on('focus', () => {
-      self.safeBlur = true;
-    });
-
-    // On blur, fire the same function as a touchend/mouseup. This is used to
-    // update values after a row has been moved through the keyboard support.
-    $handle.on('blur', (event) => {
-      if (self.rowObject && self.safeBlur) {
-        self.dropRow(event, self);
-      }
-    });
-
-    // Add arrow-key support to the handle.
-    $handle.on('keydown', (event) => {
-      // If a rowObject doesn't yet exist and this isn't the tab key.
-      if (event.keyCode !== 9 && !self.rowObject) {
-        self.rowObject = new self.row(
-          item,
-          'keyboard',
-          self.indentEnabled,
-          self.maxDepth,
-          true,
-        );
-      }
-
-      let keyChange = false;
-      let groupHeight;
-
-      /* eslint-disable no-fallthrough */
-
-      switch (event.keyCode) {
-        // Left arrow.
-        case 37:
-        // Safari left arrow.
-        case 63234:
-          keyChange = true;
-          self.rowObject.indent(-1 * self.rtl);
-          break;
-
-        // Up arrow.
-        case 38:
-        // Safari up arrow.
-        case 63232: {
-          let $previousRow = $(self.rowObject.element).prev('tr').eq(0);
-          let previousRow = $previousRow.get(0);
-          while (previousRow && $previousRow.is(':hidden')) {
-            $previousRow = $(previousRow).prev('tr').eq(0);
-            previousRow = $previousRow.get(0);
-          }
-          if (previousRow) {
-            // Do not allow the onBlur cleanup.
-            self.safeBlur = false;
-            self.rowObject.direction = 'up';
-            keyChange = true;
-
-            if ($(item).is('.tabledrag-root')) {
-              // Swap with the previous top-level row.
-              groupHeight = 0;
-              while (
-                previousRow &&
-                $previousRow.find('.js-indentation').length
-              ) {
-                $previousRow = $(previousRow).prev('tr').eq(0);
-                previousRow = $previousRow.get(0);
-                groupHeight += $previousRow.is(':hidden')
-                  ? 0
-                  : previousRow.offsetHeight;
-              }
-              if (previousRow) {
-                self.rowObject.swap('before', previousRow);
-                // No need to check for indentation, 0 is the only valid one.
-                window.scrollBy(0, -groupHeight);
-              }
-            } else if (
-              self.table.tBodies[0].rows[0] !== previousRow ||
-              $previousRow.is('.draggable')
-            ) {
-              // Swap with the previous row (unless previous row is the first
-              // one and undraggable).
-              self.rowObject.swap('before', previousRow);
-              self.rowObject.interval = null;
-              self.rowObject.indent(0);
-              window.scrollBy(0, -parseInt(item.offsetHeight, 10));
-            }
-            // Regain focus after the DOM manipulation.
-            $handle.trigger('focus');
-          }
-          break;
-        }
-        // Right arrow.
-        case 39:
-        // Safari right arrow.
-        case 63235:
-          keyChange = true;
-          self.rowObject.indent(self.rtl);
-          break;
-
-        // Down arrow.
-        case 40:
-        // Safari down arrow.
-        case 63233: {
-          let $nextRow = $(self.rowObject.group).eq(-1).next('tr').eq(0);
-          let nextRow = $nextRow.get(0);
-          while (nextRow && $nextRow.is(':hidden')) {
-            $nextRow = $(nextRow).next('tr').eq(0);
-            nextRow = $nextRow.get(0);
-          }
-          if (nextRow) {
-            // Do not allow the onBlur cleanup.
-            self.safeBlur = false;
-            self.rowObject.direction = 'down';
-            keyChange = true;
-
-            if ($(item).is('.tabledrag-root')) {
-              // Swap with the next group (necessarily a top-level one).
-              groupHeight = 0;
-              const nextGroup = new self.row(
-                nextRow,
-                'keyboard',
-                self.indentEnabled,
-                self.maxDepth,
-                false,
-              );
-              if (nextGroup) {
-                $(nextGroup.group).each(function () {
-                  groupHeight += $(this).is(':hidden') ? 0 : this.offsetHeight;
-                });
-                const nextGroupRow = $(nextGroup.group).eq(-1).get(0);
-                self.rowObject.swap('after', nextGroupRow);
-                // No need to check for indentation, 0 is the only valid one.
-                window.scrollBy(0, parseInt(groupHeight, 10));
-              }
-            } else {
-              // Swap with the next row.
-              self.rowObject.swap('after', nextRow);
-              self.rowObject.interval = null;
-              self.rowObject.indent(0);
-              window.scrollBy(0, parseInt(item.offsetHeight, 10));
-            }
-            // Regain focus after the DOM manipulation.
-            $handle.trigger('focus');
-          }
-          break;
-        }
-      }
-
-      /* eslint-enable no-fallthrough */
-
-      if (self.rowObject && self.rowObject.changed === true) {
-        $(item).addClass('drag');
-        if (self.oldRowElement) {
-          $(self.oldRowElement).removeClass('drag-previous');
-        }
-        self.oldRowElement = item;
-        if (self.striping === true) {
-          self.restripeTable();
-        }
-        self.onDrag();
-      }
-
-      // Returning false if we have an arrow key to prevent scrolling.
-      if (keyChange) {
-        return false;
-      }
-    });
-
-    // Compatibility addition, return false on keypress to prevent unwanted
-    // scrolling. IE and Safari will suppress scrolling on keydown, but all
-    // other browsers need to return false on keypress.
-    // http://www.quirksmode.org/js/keys.html
-    $handle.on('keypress', (event) => {
-      /* eslint-disable no-fallthrough */
-
-      switch (event.keyCode) {
-        // Left arrow.
-        case 37:
-        // Up arrow.
-        case 38:
-        // Right arrow.
-        case 39:
-        // Down arrow.
-        case 40:
-          return false;
-      }
-
-      /* eslint-enable no-fallthrough */
-    });
-  };
-
-  /**
-   * Pointer event initiator, creates drag object and information.
-   *
-   * @param {jQuery.Event} event
-   *   The event object that trigger the drag.
-   * @param {Drupal.tableDrag} self
-   *   The drag handle.
-   * @param {HTMLElement} item
-   *   The item that is being dragged.
-   */
-  Drupal.tableDrag.prototype.dragStart = function (event, self, item) {
-    // Create a new dragObject recording the pointer information.
-    self.dragObject = {};
-    self.dragObject.initOffset = self.getPointerOffset(item, event);
-    self.dragObject.initPointerCoords = self.pointerCoords(event);
-    if (self.indentEnabled) {
-      self.dragObject.indentPointerPos = self.dragObject.initPointerCoords;
-    }
-
-    // If there's a lingering row object from the keyboard, remove its focus.
-    if (self.rowObject) {
-      $(self.rowObject.element).find('a.tabledrag-handle').trigger('blur');
-    }
-
-    // Create a new rowObject for manipulation of this row.
-    self.rowObject = new self.row(
-      item,
-      'pointer',
-      self.indentEnabled,
-      self.maxDepth,
-      true,
-    );
-
-    // Save the position of the table.
-    self.table.topY = $(self.table).offset().top;
-    self.table.bottomY = self.table.topY + self.table.offsetHeight;
-
-    // Add classes to the handle and row.
-    $(item).addClass('drag');
-
-    // Set the document to use the move cursor during drag.
-    $('body').addClass('drag');
-    if (self.oldRowElement) {
-      $(self.oldRowElement).removeClass('drag-previous');
-    }
-
-    // Set the initial y coordinate so the direction can be calculated in
-    // dragRow().
-    self.oldY = self.pointerCoords(event).y;
-  };
-
-  /**
-   * Pointer movement handler, bound to document.
-   *
-   * @param {jQuery.Event} event
-   *   The pointer event.
-   * @param {Drupal.tableDrag} self
-   *   The tableDrag instance.
-   *
-   * @return {bool|undefined}
-   *   Undefined if no dragObject is defined, false otherwise.
-   */
-  Drupal.tableDrag.prototype.dragRow = function (event, self) {
-    if (self.dragObject) {
-      self.currentPointerCoords = self.pointerCoords(event);
-      const y = self.currentPointerCoords.y - self.dragObject.initOffset.y;
-      const x = self.currentPointerCoords.x - self.dragObject.initOffset.x;
-
-      // Check for row swapping and vertical scrolling.
-      if (y !== self.oldY) {
-        self.rowObject.direction = y > self.oldY ? 'down' : 'up';
-        // Update the old value.
-        self.oldY = y;
-        // Check if the window should be scrolled (and how fast).
-        const scrollAmount = self.checkScroll(self.currentPointerCoords.y);
-        // Stop any current scrolling.
-        clearInterval(self.scrollInterval);
-        // Continue scrolling if the mouse has moved in the scroll direction.
-        if (
-          (scrollAmount > 0 && self.rowObject.direction === 'down') ||
-          (scrollAmount < 0 && self.rowObject.direction === 'up')
-        ) {
-          self.setScroll(scrollAmount);
-        }
-
-        // If we have a valid target, perform the swap and restripe the table.
-        const currentRow = self.findDropTargetRow(x, y);
-        if (currentRow) {
-          if (self.rowObject.direction === 'down') {
-            self.rowObject.swap('after', currentRow, self);
-          } else {
-            self.rowObject.swap('before', currentRow, self);
-          }
-          if (self.striping === true) {
-            self.restripeTable();
-          }
-        }
-      }
-
-      // Similar to row swapping, handle indentations.
-      if (self.indentEnabled) {
-        const xDiff =
-          self.currentPointerCoords.x - self.dragObject.indentPointerPos.x;
-        // Set the number of indentations the pointer has been moved left or
-        // right.
-        const indentDiff = Math.round(xDiff / self.indentAmount);
-        // Indent the row with our estimated diff, which may be further
-        // restricted according to the rows around this row.
-        const indentChange = self.rowObject.indent(indentDiff);
-        // Update table and pointer indentations.
-        self.dragObject.indentPointerPos.x +=
-          self.indentAmount * indentChange * self.rtl;
-        self.indentCount = Math.max(self.indentCount, self.rowObject.indents);
-      }
-
-      return false;
-    }
-  };
-
-  /**
-   * Pointerup behavior.
-   *
-   * @param {jQuery.Event} event
-   *   The pointer event.
-   * @param {Drupal.tableDrag} self
-   *   The tableDrag instance.
-   */
-  Drupal.tableDrag.prototype.dropRow = function (event, self) {
-    let droppedRow;
-    let $droppedRow;
-
-    // Drop row functionality.
-    if (self.rowObject !== null) {
-      droppedRow = self.rowObject.element;
-      $droppedRow = $(droppedRow);
-      // The row is already in the right place so we just release it.
-      if (self.rowObject.changed === true) {
-        // Update the fields in the dropped row.
-        self.updateFields(droppedRow);
-
-        // If a setting exists for affecting the entire group, update all the
-        // fields in the entire dragged group.
-        Object.keys(self.tableSettings || {}).forEach((group) => {
-          const rowSettings = self.rowSettings(group, droppedRow);
-          if (rowSettings.relationship === 'group') {
-            Object.keys(self.rowObject.children || {}).forEach((n) => {
-              self.updateField(self.rowObject.children[n], group);
-            });
-          }
-        });
-
-        self.rowObject.markChanged();
-        if (self.changed === false) {
-          $(Drupal.theme('tableDragChangedWarning'))
-            .insertBefore(self.table)
-            .hide()
-            .fadeIn('slow');
-          self.changed = true;
-        }
-      }
-
-      if (self.indentEnabled) {
-        self.rowObject.removeIndentClasses();
-      }
-      if (self.oldRowElement) {
-        $(self.oldRowElement).removeClass('drag-previous');
-      }
-      $droppedRow.removeClass('drag').addClass('drag-previous');
-      self.oldRowElement = droppedRow;
-      self.onDrop();
-      self.rowObject = null;
-    }
-
-    // Functionality specific only to pointerup events.
-    if (self.dragObject !== null) {
-      self.dragObject = null;
-      $('body').removeClass('drag');
-      clearInterval(self.scrollInterval);
-    }
-  };
-
-  /**
-   * Get the coordinates from the event (allowing for browser differences).
-   *
-   * @param {jQuery.Event} event
-   *   The pointer event.
-   *
-   * @return {object}
-   *   An object with `x` and `y` keys indicating the position.
-   */
-  Drupal.tableDrag.prototype.pointerCoords = function (event) {
-    if (event.pageX || event.pageY) {
-      return { x: event.pageX, y: event.pageY };
-    }
-    return {
-      x: event.clientX + document.body.scrollLeft - document.body.clientLeft,
-      y: event.clientY + document.body.scrollTop - document.body.clientTop,
-    };
-  };
-
-  /**
-   * Get the event offset from the target element.
-   *
-   * Given a target element and a pointer event, get the event offset from that
-   * element. To do this we need the element's position and the target position.
-   *
-   * @param {HTMLElement} target
-   *   The target HTML element.
-   * @param {jQuery.Event} event
-   *   The pointer event.
-   *
-   * @return {object}
-   *   An object with `x` and `y` keys indicating the position.
-   */
-  Drupal.tableDrag.prototype.getPointerOffset = function (target, event) {
-    const docPos = $(target).offset();
-    const pointerPos = this.pointerCoords(event);
-    return { x: pointerPos.x - docPos.left, y: pointerPos.y - docPos.top };
-  };
-
-  /**
-   * Find the row the mouse is currently over.
-   *
-   * This row is then taken and swapped with the one being dragged.
-   *
-   * @param {number} x
-   *   The x coordinate of the mouse on the page (not the screen).
-   * @param {number} y
-   *   The y coordinate of the mouse on the page (not the screen).
-   *
-   * @return {*}
-   *   The drop target row, if found.
-   */
-  Drupal.tableDrag.prototype.findDropTargetRow = function (x, y) {
-    const rows = $(this.table.tBodies[0].rows).not(':hidden');
-    for (let n = 0; n < rows.length; n++) {
-      let row = rows[n];
-      let $row = $(row);
-      const rowY = $row.offset().top;
-      let rowHeight;
-      // Because Safari does not report offsetHeight on table rows, but does on
-      // table cells, grab the firstChild of the row and use that instead.
-      // http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari.
-      if (row.offsetHeight === 0) {
-        rowHeight = parseInt(row.firstChild.offsetHeight, 10) / 2;
-      }
-      // Other browsers.
-      else {
-        rowHeight = parseInt(row.offsetHeight, 10) / 2;
-      }
-
-      // Because we always insert before, we need to offset the height a bit.
-      if (y > rowY - rowHeight && y < rowY + rowHeight) {
-        if (this.indentEnabled) {
-          // Check that this row is not a child of the row being dragged.
-          if (
-            Object.keys(this.rowObject.group).some(
-              (o) => this.rowObject.group[o] === row,
-            )
-          ) {
-            return null;
-          }
-        }
-        // Do not allow a row to be swapped with itself.
-        else if (row === this.rowObject.element) {
-          return null;
-        }
-
-        // Check that swapping with this row is allowed.
-        if (!this.rowObject.isValidSwap(row)) {
-          return null;
-        }
-
-        // We may have found the row the mouse just passed over, but it doesn't
-        // take into account hidden rows. Skip backwards until we find a
-        // draggable row.
-        while ($row.is(':hidden') && $row.prev('tr').is(':hidden')) {
-          $row = $row.prev('tr:first-of-type');
-          row = $row.get(0);
-        }
-        return row;
-      }
-    }
-    return null;
-  };
-
-  /**
-   * After the row is dropped, update the table fields.
-   *
-   * @param {HTMLElement} changedRow
-   *   DOM object for the row that was just dropped.
-   */
-  Drupal.tableDrag.prototype.updateFields = function (changedRow) {
-    Object.keys(this.tableSettings || {}).forEach((group) => {
-      // Each group may have a different setting for relationship, so we find
-      // the source rows for each separately.
-      this.updateField(changedRow, group);
-    });
-  };
-
-  /**
-   * After the row is dropped, update a single table field.
-   *
-   * @param {HTMLElement} changedRow
-   *   DOM object for the row that was just dropped.
-   * @param {string} group
-   *   The settings group on which field updates will occur.
-   */
-  Drupal.tableDrag.prototype.updateField = function (changedRow, group) {
-    let rowSettings = this.rowSettings(group, changedRow);
-    const $changedRow = $(changedRow);
-    let sourceRow;
-    let $previousRow;
-    let previousRow;
-    let useSibling;
-    // Set the row as its own target.
-    if (
-      rowSettings.relationship === 'self' ||
-      rowSettings.relationship === 'group'
-    ) {
-      sourceRow = changedRow;
-    }
-    // Siblings are easy, check previous and next rows.
-    else if (rowSettings.relationship === 'sibling') {
-      $previousRow = $changedRow.prev('tr:first-of-type');
-      previousRow = $previousRow.get(0);
-      const $nextRow = $changedRow.next('tr:first-of-type');
-      const nextRow = $nextRow.get(0);
-      sourceRow = changedRow;
-      if (
-        $previousRow.is('.draggable') &&
-        $previousRow.find(`.${group}`).length
-      ) {
-        if (this.indentEnabled) {
-          if (
-            $previousRow.find('.js-indentations').length ===
-            $changedRow.find('.js-indentations').length
-          ) {
-            sourceRow = previousRow;
-          }
-        } else {
-          sourceRow = previousRow;
-        }
-      } else if (
-        $nextRow.is('.draggable') &&
-        $nextRow.find(`.${group}`).length
-      ) {
-        if (this.indentEnabled) {
-          if (
-            $nextRow.find('.js-indentations').length ===
-            $changedRow.find('.js-indentations').length
-          ) {
-            sourceRow = nextRow;
-          }
-        } else {
-          sourceRow = nextRow;
-        }
-      }
-    }
-    // Parents, look up the tree until we find a field not in this group.
-    // Go up as many parents as indentations in the changed row.
-    else if (rowSettings.relationship === 'parent') {
-      $previousRow = $changedRow.prev('tr');
-      previousRow = $previousRow;
-      while (
-        $previousRow.length &&
-        $previousRow.find('.js-indentation').length >= this.rowObject.indents
-      ) {
-        $previousRow = $previousRow.prev('tr');
-        previousRow = $previousRow;
-      }
-      // If we found a row.
-      if ($previousRow.length) {
-        sourceRow = $previousRow.get(0);
-      }
-      // Otherwise we went all the way to the left of the table without finding
-      // a parent, meaning this item has been placed at the root level.
-      else {
-        // Use the first row in the table as source, because it's guaranteed to
-        // be at the root level. Find the first item, then compare this row
-        // against it as a sibling.
-        sourceRow = $(this.table).find('tr.draggable:first-of-type').get(0);
-        if (sourceRow === this.rowObject.element) {
-          sourceRow = $(this.rowObject.group[this.rowObject.group.length - 1])
-            .next('tr.draggable')
-            .get(0);
-        }
-        useSibling = true;
-      }
-    }
-
-    // Because we may have moved the row from one category to another,
-    // take a look at our sibling and borrow its sources and targets.
-    this.copyDragClasses(sourceRow, changedRow, group);
-    rowSettings = this.rowSettings(group, changedRow);
-
-    // In the case that we're looking for a parent, but the row is at the top
-    // of the tree, copy our sibling's values.
-    if (useSibling) {
-      rowSettings.relationship = 'sibling';
-      rowSettings.source = rowSettings.target;
-    }
-
-    const targetClass = `.${rowSettings.target}`;
-    const targetElement = $changedRow.find(targetClass).get(0);
-
-    // Check if a target element exists in this row.
-    if (targetElement) {
-      const sourceClass = `.${rowSettings.source}`;
-      const sourceElement = $(sourceClass, sourceRow).get(0);
-      switch (rowSettings.action) {
-        case 'depth':
-          // Get the depth of the target row.
-          targetElement.value = $(sourceElement)
-            .closest('tr')
-            .find('.js-indentation').length;
-          break;
-
-        case 'match':
-          // Update the value.
-          targetElement.value = sourceElement.value;
-          break;
-
-        case 'order': {
-          const siblings = this.rowObject.findSiblings(rowSettings);
-          if ($(targetElement).is('select')) {
-            // Get a list of acceptable values.
-            const values = [];
-            $(targetElement)
-              .find('option')
-              .each(function () {
-                values.push(this.value);
-              });
-            const maxVal = values[values.length - 1];
-            // Populate the values in the siblings.
-            $(siblings)
-              .find(targetClass)
-              .each(function () {
-                // If there are more items than possible values, assign the
-                // maximum value to the row.
-                if (values.length > 0) {
-                  this.value = values.shift();
-                } else {
-                  this.value = maxVal;
-                }
-              });
-          } else {
-            // Assume a numeric input field.
-            let weight = 0;
-            const $siblingTarget = $(siblings[0]).find(targetClass);
-            if ($siblingTarget.length) {
-              weight = parseInt($siblingTarget[0].value, 10) || 0;
-            }
-            $(siblings)
-              .find(targetClass)
-              .each(function () {
-                this.value = weight;
-                weight++;
-              });
-          }
-          break;
-        }
-      }
-    }
-  };
-
-  /**
-   * Copy all tableDrag related classes from one row to another.
-   *
-   * Copy all special tableDrag classes from one row's form elements to a
-   * different one, removing any special classes that the destination row
-   * may have had.
-   *
-   * @param {HTMLElement} sourceRow
-   *   The element for the source row.
-   * @param {HTMLElement} targetRow
-   *   The element for the target row.
-   * @param {string} group
-   *   The group selector.
-   */
-  Drupal.tableDrag.prototype.copyDragClasses = function (
-    sourceRow,
-    targetRow,
-    group,
-  ) {
-    const sourceElement = $(sourceRow).find(`.${group}`);
-    const targetElement = $(targetRow).find(`.${group}`);
-    if (sourceElement.length && targetElement.length) {
-      targetElement[0].className = sourceElement[0].className;
-    }
-  };
-
-  /**
-   * Check the suggested scroll of the table.
-   *
-   * @param {number} cursorY
-   *   The Y position of the cursor.
-   *
-   * @return {number}
-   *   The suggested scroll.
-   */
-  Drupal.tableDrag.prototype.checkScroll = function (cursorY) {
-    const de = document.documentElement;
-    const b = document.body;
-
-    const windowHeight =
-      window.innerHeight ||
-      (de.clientHeight && de.clientWidth !== 0
-        ? de.clientHeight
-        : b.offsetHeight);
-    this.windowHeight = windowHeight;
-    let scrollY;
-    if (document.all) {
-      scrollY = !de.scrollTop ? b.scrollTop : de.scrollTop;
-    } else {
-      scrollY = window.pageYOffset ? window.pageYOffset : window.scrollY;
-    }
-    this.scrollY = scrollY;
-    const trigger = this.scrollSettings.trigger;
-    let delta = 0;
-
-    // Return a scroll speed relative to the edge of the screen.
-    if (cursorY - scrollY > windowHeight - trigger) {
-      delta = trigger / (windowHeight + scrollY - cursorY);
-      delta = delta > 0 && delta < trigger ? delta : trigger;
-      return delta * this.scrollSettings.amount;
-    }
-    if (cursorY - scrollY < trigger) {
-      delta = trigger / (cursorY - scrollY);
-      delta = delta > 0 && delta < trigger ? delta : trigger;
-      return -delta * this.scrollSettings.amount;
-    }
-  };
-
-  /**
-   * Set the scroll for the table.
-   *
-   * @param {number} scrollAmount
-   *   The amount of scroll to apply to the window.
-   */
-  Drupal.tableDrag.prototype.setScroll = function (scrollAmount) {
-    const self = this;
-
-    this.scrollInterval = setInterval(() => {
-      // Update the scroll values stored in the object.
-      self.checkScroll(self.currentPointerCoords.y);
-      const aboveTable = self.scrollY > self.table.topY;
-      const belowTable = self.scrollY + self.windowHeight < self.table.bottomY;
-      if (
-        (scrollAmount > 0 && belowTable) ||
-        (scrollAmount < 0 && aboveTable)
-      ) {
-        window.scrollBy(0, scrollAmount);
-      }
-    }, this.scrollSettings.interval);
-  };
-
-  /**
-   * Command to restripe table properly.
-   */
-  Drupal.tableDrag.prototype.restripeTable = function () {
-    // :even and :odd are reversed because jQuery counts from 0 and
-    // we count from 1, so we're out of sync.
-    // Match immediate children of the parent element to allow nesting.
-    $(this.table)
-      .find('> tbody > tr.draggable, > tr.draggable')
-      .filter(':visible')
-      .filter(':odd')
-      .removeClass('odd')
-      .addClass('even')
-      .end()
-      .filter(':even')
-      .removeClass('even')
-      .addClass('odd');
-  };
-
-  /**
-   * Stub function. Allows a custom handler when a row begins dragging.
-   *
-   * @return {null}
-   *   Returns null when the stub function is used.
-   */
-  Drupal.tableDrag.prototype.onDrag = function () {
-    return null;
-  };
-
-  /**
-   * Stub function. Allows a custom handler when a row is dropped.
-   *
-   * @return {null}
-   *   Returns null when the stub function is used.
-   */
-  Drupal.tableDrag.prototype.onDrop = function () {
-    return null;
-  };
-
-  /**
-   * Constructor to make a new object to manipulate a table row.
-   *
-   * @param {HTMLElement} tableRow
-   *   The DOM element for the table row we will be manipulating.
-   * @param {string} method
-   *   The method in which this row is being moved. Either 'keyboard' or
-   *   'mouse'.
-   * @param {bool} indentEnabled
-   *   Whether the containing table uses indentations. Used for optimizations.
-   * @param {number} maxDepth
-   *   The maximum amount of indentations this row may contain.
-   * @param {bool} addClasses
-   *   Whether we want to add classes to this row to indicate child
-   *   relationships.
-   */
-  Drupal.tableDrag.prototype.row = function (
-    tableRow,
-    method,
-    indentEnabled,
-    maxDepth,
-    addClasses,
-  ) {
-    const $tableRow = $(tableRow);
-
-    this.element = tableRow;
-    this.method = method;
-    this.group = [tableRow];
-    this.groupDepth = $tableRow.find('.js-indentation').length;
-    this.changed = false;
-    this.table = $tableRow.closest('table')[0];
-    this.indentEnabled = indentEnabled;
-    this.maxDepth = maxDepth;
-    // Direction the row is being moved.
-    this.direction = '';
-    if (this.indentEnabled) {
-      this.indents = $tableRow.find('.js-indentation').length;
-      this.children = this.findChildren(addClasses);
-      this.group = this.group.concat(this.children);
-      // Find the depth of this entire group.
-      for (let n = 0; n < this.group.length; n++) {
-        this.groupDepth = Math.max(
-          $(this.group[n]).find('.js-indentation').length,
-          this.groupDepth,
-        );
-      }
-    }
-  };
-
-  /**
-   * Find all children of rowObject by indentation.
-   *
-   * @param {bool} addClasses
-   *   Whether we want to add classes to this row to indicate child
-   *   relationships.
-   *
-   * @return {Array}
-   *   An array of children of the row.
-   */
-  Drupal.tableDrag.prototype.row.prototype.findChildren = function (
-    addClasses,
-  ) {
-    const parentIndentation = this.indents;
-    let currentRow = $(this.element, this.table).next('tr.draggable');
-    const rows = [];
-    let child = 0;
-
-    function rowIndentation(indentNum, el) {
-      const self = $(el);
-      if (child === 1 && indentNum === parentIndentation) {
-        self.addClass('tree-child-first');
-      }
-      if (indentNum === parentIndentation) {
-        self.addClass('tree-child');
-      } else if (indentNum > parentIndentation) {
-        self.addClass('tree-child-horizontal');
-      }
-    }
-
-    while (currentRow.length) {
-      // A greater indentation indicates this is a child.
-      if (currentRow.find('.js-indentation').length > parentIndentation) {
-        child++;
-        rows.push(currentRow[0]);
-        if (addClasses) {
-          currentRow.find('.js-indentation').each(rowIndentation);
-        }
-      } else {
-        break;
-      }
-      currentRow = currentRow.next('tr.draggable');
-    }
-    if (addClasses && rows.length) {
-      $(rows[rows.length - 1])
-        .find(`.js-indentation:nth-child(${parentIndentation + 1})`)
-        .addClass('tree-child-last');
-    }
-    return rows;
-  };
-
-  /**
-   * Ensure that two rows are allowed to be swapped.
-   *
-   * @param {HTMLElement} row
-   *   DOM object for the row being considered for swapping.
-   *
-   * @return {bool}
-   *   Whether the swap is a valid swap or not.
-   */
-  Drupal.tableDrag.prototype.row.prototype.isValidSwap = function (row) {
-    const $row = $(row);
-    if (this.indentEnabled) {
-      let prevRow;
-      let nextRow;
-      if (this.direction === 'down') {
-        prevRow = row;
-        nextRow = $row.next('tr').get(0);
-      } else {
-        prevRow = $row.prev('tr').get(0);
-        nextRow = row;
-      }
-      this.interval = this.validIndentInterval(prevRow, nextRow);
-
-      // We have an invalid swap if the valid indentations interval is empty.
-      if (this.interval.min > this.interval.max) {
-        return false;
-      }
-    }
-
-    // Do not let an un-draggable first row have anything put before it.
-    if (this.table.tBodies[0].rows[0] === row && $row.is(':not(.draggable)')) {
-      return false;
-    }
-
-    return true;
-  };
-
-  /**
-   * Perform the swap between two rows.
-   *
-   * @param {string} position
-   *   Whether the swap will occur 'before' or 'after' the given row.
-   * @param {HTMLElement} row
-   *   DOM element what will be swapped with the row group.
-   */
-  Drupal.tableDrag.prototype.row.prototype.swap = function (position, row) {
-    // Makes sure only DOM object are passed to Drupal.detachBehaviors().
-    this.group.forEach((row) => {
-      Drupal.detachBehaviors(row, drupalSettings, 'move');
-    });
-    $(row)[position](this.group);
-    // Makes sure only DOM object are passed to Drupal.attachBehaviors()s.
-    this.group.forEach((row) => {
-      Drupal.attachBehaviors(row, drupalSettings);
-    });
-    this.changed = true;
-    this.onSwap(row);
-  };
-
-  /**
-   * Determine the valid indentations interval for the row at a given position.
-   *
-   * @param {?HTMLElement} prevRow
-   *   DOM object for the row before the tested position
-   *   (or null for first position in the table).
-   * @param {?HTMLElement} nextRow
-   *   DOM object for the row after the tested position
-   *   (or null for last position in the table).
-   *
-   * @return {object}
-   *   An object with the keys `min` and `max` to indicate the valid indent
-   *   interval.
-   */
-  Drupal.tableDrag.prototype.row.prototype.validIndentInterval = function (
-    prevRow,
-    nextRow,
-  ) {
-    const $prevRow = $(prevRow);
-    let maxIndent;
-
-    // Minimum indentation:
-    // Do not orphan the next row.
-    const minIndent = nextRow ? $(nextRow).find('.js-indentation').length : 0;
-
-    // Maximum indentation:
-    if (
-      !prevRow ||
-      $prevRow.is(':not(.draggable)') ||
-      $(this.element).is('.tabledrag-root')
-    ) {
-      // Do not indent:
-      // - the first row in the table,
-      // - rows dragged below a non-draggable row,
-      // - 'root' rows.
-      maxIndent = 0;
-    } else {
-      // Do not go deeper than as a child of the previous row.
-      maxIndent =
-        $prevRow.find('.js-indentation').length +
-        ($prevRow.is('.tabledrag-leaf') ? 0 : 1);
-      // Limit by the maximum allowed depth for the table.
-      if (this.maxDepth) {
-        maxIndent = Math.min(
-          maxIndent,
-          this.maxDepth - (this.groupDepth - this.indents),
-        );
-      }
-    }
-
-    return { min: minIndent, max: maxIndent };
-  };
-
-  /**
-   * Indent a row within the legal bounds of the table.
-   *
-   * @param {number} indentDiff
-   *   The number of additional indentations proposed for the row (can be
-   *   positive or negative). This number will be adjusted to nearest valid
-   *   indentation level for the row.
-   *
-   * @return {number}
-   *   The number of indentations applied.
-   */
-  Drupal.tableDrag.prototype.row.prototype.indent = function (indentDiff) {
-    const $group = $(this.group);
-    // Determine the valid indentations interval if not available yet.
-    if (!this.interval) {
-      const prevRow = $(this.element).prev('tr').get(0);
-      const nextRow = $group.eq(-1).next('tr').get(0);
-      this.interval = this.validIndentInterval(prevRow, nextRow);
-    }
-
-    // Adjust to the nearest valid indentation.
-    let indent = this.indents + indentDiff;
-    indent = Math.max(indent, this.interval.min);
-    indent = Math.min(indent, this.interval.max);
-    indentDiff = indent - this.indents;
-
-    for (let n = 1; n <= Math.abs(indentDiff); n++) {
-      // Add or remove indentations.
-      if (indentDiff < 0) {
-        $group.find('.js-indentation:first-of-type').remove();
-        this.indents--;
-      } else {
-        $group
-          .find('td:first-of-type')
-          .prepend(Drupal.theme('tableDragIndentation'));
-        this.indents++;
-      }
-    }
-    if (indentDiff) {
-      // Update indentation for this row.
-      this.changed = true;
-      this.groupDepth += indentDiff;
-      this.onIndent();
-    }
-
-    return indentDiff;
-  };
-
-  /**
-   * Find all siblings for a row.
-   *
-   * According to its subgroup or indentation. Note that the passed-in row is
-   * included in the list of siblings.
-   *
-   * @param {object} rowSettings
-   *   The field settings we're using to identify what constitutes a sibling.
-   *
-   * @return {Array}
-   *   An array of siblings.
-   */
-  Drupal.tableDrag.prototype.row.prototype.findSiblings = function (
-    rowSettings,
-  ) {
-    const siblings = [];
-    const directions = ['prev', 'next'];
-    const rowIndentation = this.indents;
-    let checkRowIndentation;
-    for (let d = 0; d < directions.length; d++) {
-      let checkRow = $(this.element)[directions[d]]();
-      while (checkRow.length) {
-        // Check that the sibling contains a similar target field.
-        if (checkRow.find(`.${rowSettings.target}`)) {
-          // Either add immediately if this is a flat table, or check to ensure
-          // that this row has the same level of indentation.
-          if (this.indentEnabled) {
-            checkRowIndentation = checkRow.find('.js-indentation').length;
-          }
-
-          if (!this.indentEnabled || checkRowIndentation === rowIndentation) {
-            siblings.push(checkRow[0]);
-          } else if (checkRowIndentation < rowIndentation) {
-            // No need to keep looking for siblings when we get to a parent.
-            break;
-          }
-        } else {
-          break;
-        }
-        checkRow = checkRow[directions[d]]();
-      }
-      // Since siblings are added in reverse order for previous, reverse the
-      // completed list of previous siblings. Add the current row and continue.
-      if (directions[d] === 'prev') {
-        siblings.reverse();
-        siblings.push(this.element);
-      }
-    }
-    return siblings;
-  };
-
-  /**
-   * Remove indentation helper classes from the current row group.
-   */
-  Drupal.tableDrag.prototype.row.prototype.removeIndentClasses = function () {
-    Object.keys(this.children || {}).forEach((n) => {
-      $(this.children[n])
-        .find('.js-indentation')
-        .removeClass('tree-child')
-        .removeClass('tree-child-first')
-        .removeClass('tree-child-last')
-        .removeClass('tree-child-horizontal');
-    });
-  };
-
-  /**
-   * Add an asterisk or other marker to the changed row.
-   */
-  Drupal.tableDrag.prototype.row.prototype.markChanged = function () {
-    const marker = Drupal.theme('tableDragChangedMarker');
-    const cell = $(this.element).find('td:first-of-type');
-    if (cell.find('abbr.tabledrag-changed').length === 0) {
-      cell.append(marker);
-    }
-  };
-
-  /**
-   * Stub function. Allows a custom handler when a row is indented.
-   *
-   * @return {null}
-   *   Returns null when the stub function is used.
-   */
-  Drupal.tableDrag.prototype.row.prototype.onIndent = function () {
-    return null;
-  };
-
-  /**
-   * Stub function. Allows a custom handler when a row is swapped.
-   *
-   * @param {HTMLElement} swappedRow
-   *   The element for the swapped row.
-   *
-   * @return {null}
-   *   Returns null when the stub function is used.
-   */
-  Drupal.tableDrag.prototype.row.prototype.onSwap = function (swappedRow) {
-    return null;
-  };
-
-  $.extend(
-    Drupal.theme,
-    /** @lends Drupal.theme */ {
-      /**
-       * @return {string}
-       *  Markup for the marker.
-       */
-      tableDragChangedMarker() {
-        return `<abbr class="warning tabledrag-changed" title="${Drupal.t(
-          'Changed',
-        )}">*</abbr>`;
-      },
-
-      /**
-       * @return {string}
-       *   Markup for the indentation.
-       */
-      tableDragIndentation() {
-        return '<div class="js-indentation indentation">&nbsp;</div>';
-      },
-
-      /**
-       * @return {string}
-       *   Markup for the warning.
-       */
-      tableDragChangedWarning() {
-        return `<div class="tabledrag-changed-warning messages messages--warning" role="alert">${Drupal.theme(
-          'tableDragChangedMarker',
-        )} ${Drupal.t('You have unsaved changes.')}</div>`;
-      },
-
-      /**
-       * The button for toggling table row weight visibility.
-       *
-       * @return {string}
-       *   HTML markup for the weight toggle button and its container.
-       */
-      tableDragToggle: () =>
-        `<div class="tabledrag-toggle-weight-wrapper" data-drupal-selector="tabledrag-toggle-weight-wrapper">
-            <button type="button" class="link tabledrag-toggle-weight" data-drupal-selector="tabledrag-toggle-weight"></button>
-            </div>`,
-
-      /**
-       * The contents of the toggle weight button.
-       *
-       * @param {boolean} show
-       *   If the table weights are currently displayed.
-       *
-       * @return {string}
-       *  HTML markup for the weight toggle button content.s
-       */
-      toggleButtonContent: (show) =>
-        show ? Drupal.t('Hide row weights') : Drupal.t('Show row weights'),
-
-      /**
-       * @return {string}
-       *   HTML markup for a tableDrag handle.
-       */
-      tableDragHandle() {
-        return `<a href="#" title="${Drupal.t('Drag to re-order')}"
-        class="tabledrag-handle"><div class="handle"></div></a>`;
-      },
-    },
-  );
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/misc/tabledrag.js b/core/misc/tabledrag.js
index 2b287f49e973..b54ed771491b 100644
--- a/core/misc/tabledrag.js
+++ b/core/misc/tabledrag.js
@@ -1,124 +1,330 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Provide dragging capabilities to admin uis.
+ */
+
+/**
+ * Triggers when weights columns are toggled.
+ *
+ * @event columnschange
+ */
 
 (function ($, Drupal, drupalSettings) {
-  let showWeight = JSON.parse(localStorage.getItem('Drupal.tableDrag.showWeight'));
+  /**
+   * Store the state of weight columns display for all tables.
+   *
+   * Default value is to hide weight columns.
+   */
+  let showWeight = JSON.parse(
+    localStorage.getItem('Drupal.tableDrag.showWeight'),
+  );
+
+  /**
+   * Drag and drop table rows with field manipulation.
+   *
+   * Using the drupal_attach_tabledrag() function, any table with weights or
+   * parent relationships may be made into draggable tables. Columns containing
+   * a field may optionally be hidden, providing a better user experience.
+   *
+   * Created tableDrag instances may be modified with custom behaviors by
+   * overriding the .onDrag, .onDrop, .row.onSwap, and .row.onIndent methods.
+   * See blocks.js for an example of adding additional functionality to
+   * tableDrag.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.tableDrag = {
     attach(context, settings) {
       function initTableDrag(table, base) {
         if (table.length) {
-          Drupal.tableDrag[base] = new Drupal.tableDrag(table[0], settings.tableDrag[base]);
+          // Create the new tableDrag instance. Save in the Drupal variable
+          // to allow other scripts access to the object.
+          Drupal.tableDrag[base] = new Drupal.tableDrag(
+            table[0],
+            settings.tableDrag[base],
+          );
         }
       }
 
-      Object.keys(settings.tableDrag || {}).forEach(base => {
+      Object.keys(settings.tableDrag || {}).forEach((base) => {
         initTableDrag($(once('tabledrag', `#${base}`, context)), base);
       });
-    }
-
+    },
   };
 
+  /**
+   * Provides table and field manipulation.
+   *
+   * @constructor
+   *
+   * @param {HTMLElement} table
+   *   DOM object for the table to be made draggable.
+   * @param {object} tableSettings
+   *   Settings for the table added via drupal_add_dragtable().
+   */
   Drupal.tableDrag = function (table, tableSettings) {
     const self = this;
     const $table = $(table);
+
+    /**
+     * @type {jQuery}
+     */
     this.$table = $(table);
+
+    /**
+     *
+     * @type {HTMLElement}
+     */
     this.table = table;
+
+    /**
+     * @type {object}
+     */
     this.tableSettings = tableSettings;
+
+    /**
+     * Used to hold information about a current drag operation.
+     *
+     * @type {?HTMLElement}
+     */
     this.dragObject = null;
+
+    /**
+     * Provides operations for row manipulation.
+     *
+     * @type {?HTMLElement}
+     */
     this.rowObject = null;
+
+    /**
+     * Remember the previous element.
+     *
+     * @type {?HTMLElement}
+     */
     this.oldRowElement = null;
+
+    /**
+     * Used to determine up or down direction from last mouse move.
+     *
+     * @type {?number}
+     */
     this.oldY = null;
+
+    /**
+     * Whether anything in the entire table has changed.
+     *
+     * @type {bool}
+     */
     this.changed = false;
+
+    /**
+     * Maximum amount of allowed parenting.
+     *
+     * @type {number}
+     */
     this.maxDepth = 0;
+
+    /**
+     * Direction of the table.
+     *
+     * @type {number}
+     */
     this.rtl = $(this.table).css('direction') === 'rtl' ? -1 : 1;
+
+    /**
+     *
+     * @type {bool}
+     */
     this.striping = $(this.table).data('striping') === 1;
-    this.scrollSettings = {
-      amount: 4,
-      interval: 50,
-      trigger: 70
-    };
+
+    /**
+     * Configure the scroll settings.
+     *
+     * @type {object}
+     *
+     * @prop {number} amount
+     * @prop {number} interval
+     * @prop {number} trigger
+     */
+    this.scrollSettings = { amount: 4, interval: 50, trigger: 70 };
+
+    /**
+     *
+     * @type {?number}
+     */
     this.scrollInterval = null;
+
+    /**
+     *
+     * @type {number}
+     */
     this.scrollY = 0;
+
+    /**
+     *
+     * @type {number}
+     */
     this.windowHeight = 0;
+
+    /**
+     * @type {?jQuery}
+     */
     this.$toggleWeightButton = null;
+
+    /**
+     * Check this table's settings for parent relationships.
+     *
+     * For efficiency, large sections of code can be skipped if we don't need to
+     * track horizontal movement and indentations.
+     *
+     * @type {bool}
+     */
     this.indentEnabled = false;
-    Object.keys(tableSettings || {}).forEach(group => {
-      Object.keys(tableSettings[group] || {}).forEach(n => {
+    Object.keys(tableSettings || {}).forEach((group) => {
+      Object.keys(tableSettings[group] || {}).forEach((n) => {
         if (tableSettings[group][n].relationship === 'parent') {
           this.indentEnabled = true;
         }
-
         if (tableSettings[group][n].limit > 0) {
           this.maxDepth = tableSettings[group][n].limit;
         }
       });
     });
-
     if (this.indentEnabled) {
+      /**
+       * Total width of indents, set in makeDraggable.
+       *
+       * @type {number}
+       */
       this.indentCount = 1;
+      // Find the width of indentations to measure mouse movements against.
+      // Because the table doesn't need to start with any indentations, we
+      // manually append 2 indentations in the first draggable row, measure
+      // the offset, then remove.
       const indent = Drupal.theme('tableDragIndentation');
       const testRow = $('<tr></tr>').addClass('draggable').appendTo(table);
-      const testCell = $('<td></td>').appendTo(testRow).prepend(indent).prepend(indent);
+      const testCell = $('<td></td>')
+        .appendTo(testRow)
+        .prepend(indent)
+        .prepend(indent);
       const $indentation = testCell.find('.js-indentation');
-      this.indentAmount = $indentation.get(1).offsetLeft - $indentation.get(0).offsetLeft;
+
+      /**
+       *
+       * @type {number}
+       */
+      this.indentAmount =
+        $indentation.get(1).offsetLeft - $indentation.get(0).offsetLeft;
       testRow.remove();
     }
 
+    // Make each applicable row draggable.
+    // Match immediate children of the parent element to allow nesting.
     $table.find('> tr.draggable, > tbody > tr.draggable').each(function () {
       self.makeDraggable(this);
     });
+
     const $toggleWeightWrapper = $(Drupal.theme('tableDragToggle'));
-    this.$toggleWeightButton = $toggleWeightWrapper.find('[data-drupal-selector="tabledrag-toggle-weight"]');
-    this.$toggleWeightButton.on('click', $.proxy(function (e) {
-      e.preventDefault();
-      this.toggleColumns();
-    }, this));
+    this.$toggleWeightButton = $toggleWeightWrapper.find(
+      '[data-drupal-selector="tabledrag-toggle-weight"]',
+    );
+    this.$toggleWeightButton.on(
+      'click',
+      $.proxy(function (e) {
+        e.preventDefault();
+        this.toggleColumns();
+      }, this),
+    );
     $table.before($toggleWeightWrapper);
+
+    // Initialize the specified columns (for example, weight or parent columns)
+    // to show or hide according to user preference. This aids accessibility
+    // so that, e.g., screen reader users can choose to enter weight values and
+    // manipulate form elements directly, rather than using drag-and-drop..
     self.initColumns();
-    $(document).on('touchmove', event => self.dragRow(event.originalEvent.touches[0], self));
-    $(document).on('touchend', event => self.dropRow(event.originalEvent.touches[0], self));
-    $(document).on('mousemove pointermove', event => self.dragRow(event, self));
-    $(document).on('mouseup pointerup', event => self.dropRow(event, self));
-    $(window).on('storage', $.proxy(function (e) {
-      if (e.originalEvent.key === 'Drupal.tableDrag.showWeight') {
-        showWeight = JSON.parse(e.originalEvent.newValue);
-        this.displayColumns(showWeight);
-      }
-    }, this));
+
+    // Add event bindings to the document. The self variable is passed along
+    // as event handlers do not have direct access to the tableDrag object.
+    $(document).on('touchmove', (event) =>
+      self.dragRow(event.originalEvent.touches[0], self),
+    );
+    $(document).on('touchend', (event) =>
+      self.dropRow(event.originalEvent.touches[0], self),
+    );
+    $(document).on('mousemove pointermove', (event) =>
+      self.dragRow(event, self),
+    );
+    $(document).on('mouseup pointerup', (event) => self.dropRow(event, self));
+
+    // React to localStorage event showing or hiding weight columns.
+    $(window).on(
+      'storage',
+      $.proxy(function (e) {
+        // Only react to 'Drupal.tableDrag.showWeight' value change.
+        if (e.originalEvent.key === 'Drupal.tableDrag.showWeight') {
+          // This was changed in another window, get the new value for this
+          // window.
+          showWeight = JSON.parse(e.originalEvent.newValue);
+          this.displayColumns(showWeight);
+        }
+      }, this),
+    );
   };
 
+  /**
+   * Initialize columns containing form elements to be hidden by default.
+   *
+   * Identify and mark each cell with a CSS class so we can easily toggle
+   * show/hide it. Finally, hide columns if user does not have a
+   * 'Drupal.tableDrag.showWeight' localStorage value.
+   */
   Drupal.tableDrag.prototype.initColumns = function () {
     const $table = this.$table;
     let hidden;
     let cell;
     let columnIndex;
-    Object.keys(this.tableSettings || {}).forEach(group => {
-      Object.keys(this.tableSettings[group]).some(tableSetting => {
-        const field = $table.find(`.${this.tableSettings[group][tableSetting].target}`).eq(0);
-
+    Object.keys(this.tableSettings || {}).forEach((group) => {
+      // Find the first field in this group.
+      Object.keys(this.tableSettings[group]).some((tableSetting) => {
+        const field = $table
+          .find(`.${this.tableSettings[group][tableSetting].target}`)
+          .eq(0);
         if (field.length && this.tableSettings[group][tableSetting].hidden) {
           hidden = this.tableSettings[group][tableSetting].hidden;
           cell = field.closest('td');
           return true;
         }
-
         return false;
       });
 
+      // Mark the column containing this field so it can be hidden.
       if (hidden && cell[0]) {
+        // Add 1 to our indexes. The nth-child selector is 1 based, not 0
+        // based. Match immediate children of the parent element to allow
+        // nesting.
         columnIndex = cell.parent().find('> td').index(cell.get(0)) + 1;
-        $table.find('> thead > tr, > tbody > tr, > tr').each(this.addColspanClass(columnIndex));
+        $table
+          .find('> thead > tr, > tbody > tr, > tr')
+          .each(this.addColspanClass(columnIndex));
       }
     });
     this.displayColumns(showWeight);
   };
 
+  /**
+   * Mark cells that have colspan.
+   *
+   * In order to adjust the colspan instead of hiding them altogether.
+   *
+   * @param {number} columnIndex
+   *   The column index to add colspan class to.
+   *
+   * @return {function}
+   *   Function to add colspan class.
+   */
   Drupal.tableDrag.prototype.addColspanClass = function (columnIndex) {
     return function () {
+      // Get the columnIndex and adjust for any colspans in this row.
       const $row = $(this);
       let index = columnIndex;
       const cells = $row.children();
@@ -128,309 +334,473 @@
           index -= this.colSpan - 1;
         }
       });
-
       if (index > 0) {
         cell = cells.filter(`:nth-child(${index})`);
-
         if (cell[0].colSpan && cell[0].colSpan > 1) {
+          // If this cell has a colspan, mark it so we can reduce the colspan.
           cell.addClass('tabledrag-has-colspan');
         } else {
+          // Mark this cell so we can hide it.
           cell.addClass('tabledrag-hide');
         }
       }
     };
   };
 
+  /**
+   * Hide or display weight columns. Triggers an event on change.
+   *
+   * @fires event:columnschange
+   *
+   * @param {bool} displayWeight
+   *   'true' will show weight columns.
+   */
   Drupal.tableDrag.prototype.displayColumns = function (displayWeight) {
     if (displayWeight) {
       this.showColumns();
-    } else {
+    }
+    // Default action is to hide columns.
+    else {
       this.hideColumns();
     }
 
-    this.$toggleWeightButton.html(Drupal.theme('toggleButtonContent', displayWeight));
-    $(once.filter('tabledrag', 'table')).trigger('columnschange', !!displayWeight);
+    this.$toggleWeightButton.html(
+      Drupal.theme('toggleButtonContent', displayWeight),
+    );
+
+    // Trigger an event to allow other scripts to react to this display change.
+    // Force the extra parameter as a bool.
+    $(once.filter('tabledrag', 'table')).trigger(
+      'columnschange',
+      !!displayWeight,
+    );
   };
 
+  /**
+   * Toggle the weight column depending on 'showWeight' value.
+   *
+   * Store only default override.
+   */
   Drupal.tableDrag.prototype.toggleColumns = function () {
     showWeight = !showWeight;
     this.displayColumns(showWeight);
-
     if (showWeight) {
+      // Save default override.
       localStorage.setItem('Drupal.tableDrag.showWeight', showWeight);
     } else {
+      // Reset the value to its default.
       localStorage.removeItem('Drupal.tableDrag.showWeight');
     }
   };
 
+  /**
+   * Hide the columns containing weight/parent form elements.
+   *
+   * Undo showColumns().
+   */
   Drupal.tableDrag.prototype.hideColumns = function () {
     const $tables = $(once.filter('tabledrag', 'table'));
+    // Hide weight/parent cells and headers.
     $tables.find('.tabledrag-hide').css('display', 'none');
+    // Show TableDrag handles.
     $tables.find('.tabledrag-handle').css('display', '');
+    // Reduce the colspan of any effected multi-span columns.
     $tables.find('.tabledrag-has-colspan').each(function () {
       this.colSpan -= 1;
     });
   };
 
+  /**
+   * Show the columns containing weight/parent form elements.
+   *
+   * Undo hideColumns().
+   */
   Drupal.tableDrag.prototype.showColumns = function () {
     const $tables = $(once.filter('tabledrag', 'table'));
+    // Show weight/parent cells and headers.
     $tables.find('.tabledrag-hide').css('display', '');
+    // Hide TableDrag handles.
     $tables.find('.tabledrag-handle').css('display', 'none');
+    // Increase the colspan for any columns where it was previously reduced.
     $tables.find('.tabledrag-has-colspan').each(function () {
       this.colSpan += 1;
     });
   };
 
+  /**
+   * Find the target used within a particular row and group.
+   *
+   * @param {string} group
+   *   Group selector.
+   * @param {HTMLElement} row
+   *   The row HTML element.
+   *
+   * @return {object}
+   *   The table row settings.
+   */
   Drupal.tableDrag.prototype.rowSettings = function (group, row) {
     const field = $(row).find(`.${group}`);
     const tableSettingsGroup = this.tableSettings[group];
-    return Object.keys(tableSettingsGroup).map(delta => {
-      const targetClass = tableSettingsGroup[delta].target;
-      let rowSettings;
-
-      if (field.is(`.${targetClass}`)) {
-        rowSettings = {};
-        Object.keys(tableSettingsGroup[delta]).forEach(n => {
-          rowSettings[n] = tableSettingsGroup[delta][n];
-        });
-      }
-
-      return rowSettings;
-    }).filter(rowSetting => rowSetting)[0];
+    return Object.keys(tableSettingsGroup)
+      .map((delta) => {
+        const targetClass = tableSettingsGroup[delta].target;
+        let rowSettings;
+        if (field.is(`.${targetClass}`)) {
+          // Return a copy of the row settings.
+          rowSettings = {};
+          Object.keys(tableSettingsGroup[delta]).forEach((n) => {
+            rowSettings[n] = tableSettingsGroup[delta][n];
+          });
+        }
+        return rowSettings;
+      })
+      .filter((rowSetting) => rowSetting)[0];
   };
 
+  /**
+   * Take an item and add event handlers to make it become draggable.
+   *
+   * @param {HTMLElement} item
+   *   The item to add event handlers to.
+   */
   Drupal.tableDrag.prototype.makeDraggable = function (item) {
     const self = this;
     const $item = $(item);
+    // Add a class to the title link.
     $item.find('td:first-of-type').find('a').addClass('menu-item__link');
+    // Create the handle.
     const $handle = $(Drupal.theme('tableDragHandle'));
-    const $indentationLast = $item.find('td:first-of-type').find('.js-indentation').eq(-1);
-
+    // Insert the handle after indentations (if any).
+    const $indentationLast = $item
+      .find('td:first-of-type')
+      .find('.js-indentation')
+      .eq(-1);
     if ($indentationLast.length) {
       $indentationLast.after($handle);
-      self.indentCount = Math.max($item.find('.js-indentation').length, self.indentCount);
+      // Update the total width of indentation in this entire table.
+      self.indentCount = Math.max(
+        $item.find('.js-indentation').length,
+        self.indentCount,
+      );
     } else {
       $item.find('td').eq(0).prepend($handle);
     }
 
-    $handle.on('mousedown touchstart pointerdown', event => {
+    $handle.on('mousedown touchstart pointerdown', (event) => {
       event.preventDefault();
-
       if (event.originalEvent.type === 'touchstart') {
         event = event.originalEvent.touches[0];
       }
-
       self.dragStart(event, self, item);
     });
-    $handle.on('click', e => {
+
+    // Prevent the anchor tag from jumping us to the top of the page.
+    $handle.on('click', (e) => {
       e.preventDefault();
     });
+
+    // Set blur cleanup when a handle is focused.
     $handle.on('focus', () => {
       self.safeBlur = true;
     });
-    $handle.on('blur', event => {
+
+    // On blur, fire the same function as a touchend/mouseup. This is used to
+    // update values after a row has been moved through the keyboard support.
+    $handle.on('blur', (event) => {
       if (self.rowObject && self.safeBlur) {
         self.dropRow(event, self);
       }
     });
-    $handle.on('keydown', event => {
+
+    // Add arrow-key support to the handle.
+    $handle.on('keydown', (event) => {
+      // If a rowObject doesn't yet exist and this isn't the tab key.
       if (event.keyCode !== 9 && !self.rowObject) {
-        self.rowObject = new self.row(item, 'keyboard', self.indentEnabled, self.maxDepth, true);
+        self.rowObject = new self.row(
+          item,
+          'keyboard',
+          self.indentEnabled,
+          self.maxDepth,
+          true,
+        );
       }
 
       let keyChange = false;
       let groupHeight;
 
+      /* eslint-disable no-fallthrough */
+
       switch (event.keyCode) {
+        // Left arrow.
         case 37:
+        // Safari left arrow.
         case 63234:
           keyChange = true;
           self.rowObject.indent(-1 * self.rtl);
           break;
 
+        // Up arrow.
         case 38:
-        case 63232:
-          {
-            let $previousRow = $(self.rowObject.element).prev('tr').eq(0);
-            let previousRow = $previousRow.get(0);
-
-            while (previousRow && $previousRow.is(':hidden')) {
-              $previousRow = $(previousRow).prev('tr').eq(0);
-              previousRow = $previousRow.get(0);
-            }
-
-            if (previousRow) {
-              self.safeBlur = false;
-              self.rowObject.direction = 'up';
-              keyChange = true;
-
-              if ($(item).is('.tabledrag-root')) {
-                groupHeight = 0;
-
-                while (previousRow && $previousRow.find('.js-indentation').length) {
-                  $previousRow = $(previousRow).prev('tr').eq(0);
-                  previousRow = $previousRow.get(0);
-                  groupHeight += $previousRow.is(':hidden') ? 0 : previousRow.offsetHeight;
-                }
-
-                if (previousRow) {
-                  self.rowObject.swap('before', previousRow);
-                  window.scrollBy(0, -groupHeight);
-                }
-              } else if (self.table.tBodies[0].rows[0] !== previousRow || $previousRow.is('.draggable')) {
+        // Safari up arrow.
+        case 63232: {
+          let $previousRow = $(self.rowObject.element).prev('tr').eq(0);
+          let previousRow = $previousRow.get(0);
+          while (previousRow && $previousRow.is(':hidden')) {
+            $previousRow = $(previousRow).prev('tr').eq(0);
+            previousRow = $previousRow.get(0);
+          }
+          if (previousRow) {
+            // Do not allow the onBlur cleanup.
+            self.safeBlur = false;
+            self.rowObject.direction = 'up';
+            keyChange = true;
+
+            if ($(item).is('.tabledrag-root')) {
+              // Swap with the previous top-level row.
+              groupHeight = 0;
+              while (
+                previousRow &&
+                $previousRow.find('.js-indentation').length
+              ) {
+                $previousRow = $(previousRow).prev('tr').eq(0);
+                previousRow = $previousRow.get(0);
+                groupHeight += $previousRow.is(':hidden')
+                  ? 0
+                  : previousRow.offsetHeight;
+              }
+              if (previousRow) {
                 self.rowObject.swap('before', previousRow);
-                self.rowObject.interval = null;
-                self.rowObject.indent(0);
-                window.scrollBy(0, -parseInt(item.offsetHeight, 10));
+                // No need to check for indentation, 0 is the only valid one.
+                window.scrollBy(0, -groupHeight);
               }
-
-              $handle.trigger('focus');
+            } else if (
+              self.table.tBodies[0].rows[0] !== previousRow ||
+              $previousRow.is('.draggable')
+            ) {
+              // Swap with the previous row (unless previous row is the first
+              // one and undraggable).
+              self.rowObject.swap('before', previousRow);
+              self.rowObject.interval = null;
+              self.rowObject.indent(0);
+              window.scrollBy(0, -parseInt(item.offsetHeight, 10));
             }
-
-            break;
+            // Regain focus after the DOM manipulation.
+            $handle.trigger('focus');
           }
-
+          break;
+        }
+        // Right arrow.
         case 39:
+        // Safari right arrow.
         case 63235:
           keyChange = true;
           self.rowObject.indent(self.rtl);
           break;
 
+        // Down arrow.
         case 40:
-        case 63233:
-          {
-            let $nextRow = $(self.rowObject.group).eq(-1).next('tr').eq(0);
-            let nextRow = $nextRow.get(0);
-
-            while (nextRow && $nextRow.is(':hidden')) {
-              $nextRow = $(nextRow).next('tr').eq(0);
-              nextRow = $nextRow.get(0);
-            }
-
-            if (nextRow) {
-              self.safeBlur = false;
-              self.rowObject.direction = 'down';
-              keyChange = true;
-
-              if ($(item).is('.tabledrag-root')) {
-                groupHeight = 0;
-                const nextGroup = new self.row(nextRow, 'keyboard', self.indentEnabled, self.maxDepth, false);
-
-                if (nextGroup) {
-                  $(nextGroup.group).each(function () {
-                    groupHeight += $(this).is(':hidden') ? 0 : this.offsetHeight;
-                  });
-                  const nextGroupRow = $(nextGroup.group).eq(-1).get(0);
-                  self.rowObject.swap('after', nextGroupRow);
-                  window.scrollBy(0, parseInt(groupHeight, 10));
-                }
-              } else {
-                self.rowObject.swap('after', nextRow);
-                self.rowObject.interval = null;
-                self.rowObject.indent(0);
-                window.scrollBy(0, parseInt(item.offsetHeight, 10));
+        // Safari down arrow.
+        case 63233: {
+          let $nextRow = $(self.rowObject.group).eq(-1).next('tr').eq(0);
+          let nextRow = $nextRow.get(0);
+          while (nextRow && $nextRow.is(':hidden')) {
+            $nextRow = $(nextRow).next('tr').eq(0);
+            nextRow = $nextRow.get(0);
+          }
+          if (nextRow) {
+            // Do not allow the onBlur cleanup.
+            self.safeBlur = false;
+            self.rowObject.direction = 'down';
+            keyChange = true;
+
+            if ($(item).is('.tabledrag-root')) {
+              // Swap with the next group (necessarily a top-level one).
+              groupHeight = 0;
+              const nextGroup = new self.row(
+                nextRow,
+                'keyboard',
+                self.indentEnabled,
+                self.maxDepth,
+                false,
+              );
+              if (nextGroup) {
+                $(nextGroup.group).each(function () {
+                  groupHeight += $(this).is(':hidden') ? 0 : this.offsetHeight;
+                });
+                const nextGroupRow = $(nextGroup.group).eq(-1).get(0);
+                self.rowObject.swap('after', nextGroupRow);
+                // No need to check for indentation, 0 is the only valid one.
+                window.scrollBy(0, parseInt(groupHeight, 10));
               }
-
-              $handle.trigger('focus');
+            } else {
+              // Swap with the next row.
+              self.rowObject.swap('after', nextRow);
+              self.rowObject.interval = null;
+              self.rowObject.indent(0);
+              window.scrollBy(0, parseInt(item.offsetHeight, 10));
             }
-
-            break;
+            // Regain focus after the DOM manipulation.
+            $handle.trigger('focus');
           }
+          break;
+        }
       }
 
+      /* eslint-enable no-fallthrough */
+
       if (self.rowObject && self.rowObject.changed === true) {
         $(item).addClass('drag');
-
         if (self.oldRowElement) {
           $(self.oldRowElement).removeClass('drag-previous');
         }
-
         self.oldRowElement = item;
-
         if (self.striping === true) {
           self.restripeTable();
         }
-
         self.onDrag();
       }
 
+      // Returning false if we have an arrow key to prevent scrolling.
       if (keyChange) {
         return false;
       }
     });
-    $handle.on('keypress', event => {
+
+    // Compatibility addition, return false on keypress to prevent unwanted
+    // scrolling. IE and Safari will suppress scrolling on keydown, but all
+    // other browsers need to return false on keypress.
+    // http://www.quirksmode.org/js/keys.html
+    $handle.on('keypress', (event) => {
+      /* eslint-disable no-fallthrough */
+
       switch (event.keyCode) {
+        // Left arrow.
         case 37:
+        // Up arrow.
         case 38:
+        // Right arrow.
         case 39:
+        // Down arrow.
         case 40:
           return false;
       }
+
+      /* eslint-enable no-fallthrough */
     });
   };
 
+  /**
+   * Pointer event initiator, creates drag object and information.
+   *
+   * @param {jQuery.Event} event
+   *   The event object that trigger the drag.
+   * @param {Drupal.tableDrag} self
+   *   The drag handle.
+   * @param {HTMLElement} item
+   *   The item that is being dragged.
+   */
   Drupal.tableDrag.prototype.dragStart = function (event, self, item) {
+    // Create a new dragObject recording the pointer information.
     self.dragObject = {};
     self.dragObject.initOffset = self.getPointerOffset(item, event);
     self.dragObject.initPointerCoords = self.pointerCoords(event);
-
     if (self.indentEnabled) {
       self.dragObject.indentPointerPos = self.dragObject.initPointerCoords;
     }
 
+    // If there's a lingering row object from the keyboard, remove its focus.
     if (self.rowObject) {
       $(self.rowObject.element).find('a.tabledrag-handle').trigger('blur');
     }
 
-    self.rowObject = new self.row(item, 'pointer', self.indentEnabled, self.maxDepth, true);
+    // Create a new rowObject for manipulation of this row.
+    self.rowObject = new self.row(
+      item,
+      'pointer',
+      self.indentEnabled,
+      self.maxDepth,
+      true,
+    );
+
+    // Save the position of the table.
     self.table.topY = $(self.table).offset().top;
     self.table.bottomY = self.table.topY + self.table.offsetHeight;
+
+    // Add classes to the handle and row.
     $(item).addClass('drag');
-    $('body').addClass('drag');
 
+    // Set the document to use the move cursor during drag.
+    $('body').addClass('drag');
     if (self.oldRowElement) {
       $(self.oldRowElement).removeClass('drag-previous');
     }
 
+    // Set the initial y coordinate so the direction can be calculated in
+    // dragRow().
     self.oldY = self.pointerCoords(event).y;
   };
 
+  /**
+   * Pointer movement handler, bound to document.
+   *
+   * @param {jQuery.Event} event
+   *   The pointer event.
+   * @param {Drupal.tableDrag} self
+   *   The tableDrag instance.
+   *
+   * @return {bool|undefined}
+   *   Undefined if no dragObject is defined, false otherwise.
+   */
   Drupal.tableDrag.prototype.dragRow = function (event, self) {
     if (self.dragObject) {
       self.currentPointerCoords = self.pointerCoords(event);
       const y = self.currentPointerCoords.y - self.dragObject.initOffset.y;
       const x = self.currentPointerCoords.x - self.dragObject.initOffset.x;
 
+      // Check for row swapping and vertical scrolling.
       if (y !== self.oldY) {
         self.rowObject.direction = y > self.oldY ? 'down' : 'up';
+        // Update the old value.
         self.oldY = y;
+        // Check if the window should be scrolled (and how fast).
         const scrollAmount = self.checkScroll(self.currentPointerCoords.y);
+        // Stop any current scrolling.
         clearInterval(self.scrollInterval);
-
-        if (scrollAmount > 0 && self.rowObject.direction === 'down' || scrollAmount < 0 && self.rowObject.direction === 'up') {
+        // Continue scrolling if the mouse has moved in the scroll direction.
+        if (
+          (scrollAmount > 0 && self.rowObject.direction === 'down') ||
+          (scrollAmount < 0 && self.rowObject.direction === 'up')
+        ) {
           self.setScroll(scrollAmount);
         }
 
+        // If we have a valid target, perform the swap and restripe the table.
         const currentRow = self.findDropTargetRow(x, y);
-
         if (currentRow) {
           if (self.rowObject.direction === 'down') {
             self.rowObject.swap('after', currentRow, self);
           } else {
             self.rowObject.swap('before', currentRow, self);
           }
-
           if (self.striping === true) {
             self.restripeTable();
           }
         }
       }
 
+      // Similar to row swapping, handle indentations.
       if (self.indentEnabled) {
-        const xDiff = self.currentPointerCoords.x - self.dragObject.indentPointerPos.x;
+        const xDiff =
+          self.currentPointerCoords.x - self.dragObject.indentPointerPos.x;
+        // Set the number of indentations the pointer has been moved left or
+        // right.
         const indentDiff = Math.round(xDiff / self.indentAmount);
+        // Indent the row with our estimated diff, which may be further
+        // restricted according to the rows around this row.
         const indentChange = self.rowObject.indent(indentDiff);
-        self.dragObject.indentPointerPos.x += self.indentAmount * indentChange * self.rtl;
+        // Update table and pointer indentations.
+        self.dragObject.indentPointerPos.x +=
+          self.indentAmount * indentChange * self.rtl;
         self.indentCount = Math.max(self.indentCount, self.rowObject.indents);
       }
 
@@ -438,29 +808,44 @@
     }
   };
 
+  /**
+   * Pointerup behavior.
+   *
+   * @param {jQuery.Event} event
+   *   The pointer event.
+   * @param {Drupal.tableDrag} self
+   *   The tableDrag instance.
+   */
   Drupal.tableDrag.prototype.dropRow = function (event, self) {
     let droppedRow;
     let $droppedRow;
 
+    // Drop row functionality.
     if (self.rowObject !== null) {
       droppedRow = self.rowObject.element;
       $droppedRow = $(droppedRow);
-
+      // The row is already in the right place so we just release it.
       if (self.rowObject.changed === true) {
+        // Update the fields in the dropped row.
         self.updateFields(droppedRow);
-        Object.keys(self.tableSettings || {}).forEach(group => {
-          const rowSettings = self.rowSettings(group, droppedRow);
 
+        // If a setting exists for affecting the entire group, update all the
+        // fields in the entire dragged group.
+        Object.keys(self.tableSettings || {}).forEach((group) => {
+          const rowSettings = self.rowSettings(group, droppedRow);
           if (rowSettings.relationship === 'group') {
-            Object.keys(self.rowObject.children || {}).forEach(n => {
+            Object.keys(self.rowObject.children || {}).forEach((n) => {
               self.updateField(self.rowObject.children[n], group);
             });
           }
         });
-        self.rowObject.markChanged();
 
+        self.rowObject.markChanged();
         if (self.changed === false) {
-          $(Drupal.theme('tableDragChangedWarning')).insertBefore(self.table).hide().fadeIn('slow');
+          $(Drupal.theme('tableDragChangedWarning'))
+            .insertBefore(self.table)
+            .hide()
+            .fadeIn('slow');
           self.changed = true;
         }
       }
@@ -468,17 +853,16 @@
       if (self.indentEnabled) {
         self.rowObject.removeIndentClasses();
       }
-
       if (self.oldRowElement) {
         $(self.oldRowElement).removeClass('drag-previous');
       }
-
       $droppedRow.removeClass('drag').addClass('drag-previous');
       self.oldRowElement = droppedRow;
       self.onDrop();
       self.rowObject = null;
     }
 
+    // Functionality specific only to pointerup events.
     if (self.dragObject !== null) {
       self.dragObject = null;
       $('body').removeClass('drag');
@@ -486,75 +870,133 @@
     }
   };
 
+  /**
+   * Get the coordinates from the event (allowing for browser differences).
+   *
+   * @param {jQuery.Event} event
+   *   The pointer event.
+   *
+   * @return {object}
+   *   An object with `x` and `y` keys indicating the position.
+   */
   Drupal.tableDrag.prototype.pointerCoords = function (event) {
     if (event.pageX || event.pageY) {
-      return {
-        x: event.pageX,
-        y: event.pageY
-      };
+      return { x: event.pageX, y: event.pageY };
     }
-
     return {
       x: event.clientX + document.body.scrollLeft - document.body.clientLeft,
-      y: event.clientY + document.body.scrollTop - document.body.clientTop
+      y: event.clientY + document.body.scrollTop - document.body.clientTop,
     };
   };
 
+  /**
+   * Get the event offset from the target element.
+   *
+   * Given a target element and a pointer event, get the event offset from that
+   * element. To do this we need the element's position and the target position.
+   *
+   * @param {HTMLElement} target
+   *   The target HTML element.
+   * @param {jQuery.Event} event
+   *   The pointer event.
+   *
+   * @return {object}
+   *   An object with `x` and `y` keys indicating the position.
+   */
   Drupal.tableDrag.prototype.getPointerOffset = function (target, event) {
     const docPos = $(target).offset();
     const pointerPos = this.pointerCoords(event);
-    return {
-      x: pointerPos.x - docPos.left,
-      y: pointerPos.y - docPos.top
-    };
+    return { x: pointerPos.x - docPos.left, y: pointerPos.y - docPos.top };
   };
 
+  /**
+   * Find the row the mouse is currently over.
+   *
+   * This row is then taken and swapped with the one being dragged.
+   *
+   * @param {number} x
+   *   The x coordinate of the mouse on the page (not the screen).
+   * @param {number} y
+   *   The y coordinate of the mouse on the page (not the screen).
+   *
+   * @return {*}
+   *   The drop target row, if found.
+   */
   Drupal.tableDrag.prototype.findDropTargetRow = function (x, y) {
     const rows = $(this.table.tBodies[0].rows).not(':hidden');
-
     for (let n = 0; n < rows.length; n++) {
       let row = rows[n];
       let $row = $(row);
       const rowY = $row.offset().top;
       let rowHeight;
-
+      // Because Safari does not report offsetHeight on table rows, but does on
+      // table cells, grab the firstChild of the row and use that instead.
+      // http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari.
       if (row.offsetHeight === 0) {
         rowHeight = parseInt(row.firstChild.offsetHeight, 10) / 2;
-      } else {
+      }
+      // Other browsers.
+      else {
         rowHeight = parseInt(row.offsetHeight, 10) / 2;
       }
 
+      // Because we always insert before, we need to offset the height a bit.
       if (y > rowY - rowHeight && y < rowY + rowHeight) {
         if (this.indentEnabled) {
-          if (Object.keys(this.rowObject.group).some(o => this.rowObject.group[o] === row)) {
+          // Check that this row is not a child of the row being dragged.
+          if (
+            Object.keys(this.rowObject.group).some(
+              (o) => this.rowObject.group[o] === row,
+            )
+          ) {
             return null;
           }
-        } else if (row === this.rowObject.element) {
+        }
+        // Do not allow a row to be swapped with itself.
+        else if (row === this.rowObject.element) {
           return null;
         }
 
+        // Check that swapping with this row is allowed.
         if (!this.rowObject.isValidSwap(row)) {
           return null;
         }
 
+        // We may have found the row the mouse just passed over, but it doesn't
+        // take into account hidden rows. Skip backwards until we find a
+        // draggable row.
         while ($row.is(':hidden') && $row.prev('tr').is(':hidden')) {
           $row = $row.prev('tr:first-of-type');
           row = $row.get(0);
         }
-
         return row;
       }
     }
-
     return null;
   };
 
+  /**
+   * After the row is dropped, update the table fields.
+   *
+   * @param {HTMLElement} changedRow
+   *   DOM object for the row that was just dropped.
+   */
   Drupal.tableDrag.prototype.updateFields = function (changedRow) {
-    Object.keys(this.tableSettings || {}).forEach(group => {
+    Object.keys(this.tableSettings || {}).forEach((group) => {
+      // Each group may have a different setting for relationship, so we find
+      // the source rows for each separately.
       this.updateField(changedRow, group);
     });
   };
 
+  /**
+   * After the row is dropped, update a single table field.
+   *
+   * @param {HTMLElement} changedRow
+   *   DOM object for the row that was just dropped.
+   * @param {string} group
+   *   The settings group on which field updates will occur.
+   */
   Drupal.tableDrag.prototype.updateField = function (changedRow, group) {
     let rowSettings = this.rowSettings(group, changedRow);
     const $changedRow = $(changedRow);
@@ -562,58 +1004,89 @@
     let $previousRow;
     let previousRow;
     let useSibling;
-
-    if (rowSettings.relationship === 'self' || rowSettings.relationship === 'group') {
+    // Set the row as its own target.
+    if (
+      rowSettings.relationship === 'self' ||
+      rowSettings.relationship === 'group'
+    ) {
       sourceRow = changedRow;
-    } else if (rowSettings.relationship === 'sibling') {
+    }
+    // Siblings are easy, check previous and next rows.
+    else if (rowSettings.relationship === 'sibling') {
       $previousRow = $changedRow.prev('tr:first-of-type');
       previousRow = $previousRow.get(0);
       const $nextRow = $changedRow.next('tr:first-of-type');
       const nextRow = $nextRow.get(0);
       sourceRow = changedRow;
-
-      if ($previousRow.is('.draggable') && $previousRow.find(`.${group}`).length) {
+      if (
+        $previousRow.is('.draggable') &&
+        $previousRow.find(`.${group}`).length
+      ) {
         if (this.indentEnabled) {
-          if ($previousRow.find('.js-indentations').length === $changedRow.find('.js-indentations').length) {
+          if (
+            $previousRow.find('.js-indentations').length ===
+            $changedRow.find('.js-indentations').length
+          ) {
             sourceRow = previousRow;
           }
         } else {
           sourceRow = previousRow;
         }
-      } else if ($nextRow.is('.draggable') && $nextRow.find(`.${group}`).length) {
+      } else if (
+        $nextRow.is('.draggable') &&
+        $nextRow.find(`.${group}`).length
+      ) {
         if (this.indentEnabled) {
-          if ($nextRow.find('.js-indentations').length === $changedRow.find('.js-indentations').length) {
+          if (
+            $nextRow.find('.js-indentations').length ===
+            $changedRow.find('.js-indentations').length
+          ) {
             sourceRow = nextRow;
           }
         } else {
           sourceRow = nextRow;
         }
       }
-    } else if (rowSettings.relationship === 'parent') {
+    }
+    // Parents, look up the tree until we find a field not in this group.
+    // Go up as many parents as indentations in the changed row.
+    else if (rowSettings.relationship === 'parent') {
       $previousRow = $changedRow.prev('tr');
       previousRow = $previousRow;
-
-      while ($previousRow.length && $previousRow.find('.js-indentation').length >= this.rowObject.indents) {
+      while (
+        $previousRow.length &&
+        $previousRow.find('.js-indentation').length >= this.rowObject.indents
+      ) {
         $previousRow = $previousRow.prev('tr');
         previousRow = $previousRow;
       }
-
+      // If we found a row.
       if ($previousRow.length) {
         sourceRow = $previousRow.get(0);
-      } else {
+      }
+      // Otherwise we went all the way to the left of the table without finding
+      // a parent, meaning this item has been placed at the root level.
+      else {
+        // Use the first row in the table as source, because it's guaranteed to
+        // be at the root level. Find the first item, then compare this row
+        // against it as a sibling.
         sourceRow = $(this.table).find('tr.draggable:first-of-type').get(0);
-
         if (sourceRow === this.rowObject.element) {
-          sourceRow = $(this.rowObject.group[this.rowObject.group.length - 1]).next('tr.draggable').get(0);
+          sourceRow = $(this.rowObject.group[this.rowObject.group.length - 1])
+            .next('tr.draggable')
+            .get(0);
         }
-
         useSibling = true;
       }
     }
 
+    // Because we may have moved the row from one category to another,
+    // take a look at our sibling and borrow its sources and targets.
     this.copyDragClasses(sourceRow, changedRow, group);
     rowSettings = this.rowSettings(group, changedRow);
 
+    // In the case that we're looking for a parent, but the row is at the top
+    // of the tree, copy our sibling's values.
     if (useSibling) {
       rowSettings.relationship = 'sibling';
       rowSettings.source = rowSettings.target;
@@ -622,88 +1095,127 @@
     const targetClass = `.${rowSettings.target}`;
     const targetElement = $changedRow.find(targetClass).get(0);
 
+    // Check if a target element exists in this row.
     if (targetElement) {
       const sourceClass = `.${rowSettings.source}`;
       const sourceElement = $(sourceClass, sourceRow).get(0);
-
       switch (rowSettings.action) {
         case 'depth':
-          targetElement.value = $(sourceElement).closest('tr').find('.js-indentation').length;
+          // Get the depth of the target row.
+          targetElement.value = $(sourceElement)
+            .closest('tr')
+            .find('.js-indentation').length;
           break;
 
         case 'match':
+          // Update the value.
           targetElement.value = sourceElement.value;
           break;
 
-        case 'order':
-          {
-            const siblings = this.rowObject.findSiblings(rowSettings);
-
-            if ($(targetElement).is('select')) {
-              const values = [];
-              $(targetElement).find('option').each(function () {
+        case 'order': {
+          const siblings = this.rowObject.findSiblings(rowSettings);
+          if ($(targetElement).is('select')) {
+            // Get a list of acceptable values.
+            const values = [];
+            $(targetElement)
+              .find('option')
+              .each(function () {
                 values.push(this.value);
               });
-              const maxVal = values[values.length - 1];
-              $(siblings).find(targetClass).each(function () {
+            const maxVal = values[values.length - 1];
+            // Populate the values in the siblings.
+            $(siblings)
+              .find(targetClass)
+              .each(function () {
+                // If there are more items than possible values, assign the
+                // maximum value to the row.
                 if (values.length > 0) {
                   this.value = values.shift();
                 } else {
                   this.value = maxVal;
                 }
               });
-            } else {
-              let weight = 0;
-              const $siblingTarget = $(siblings[0]).find(targetClass);
-
-              if ($siblingTarget.length) {
-                weight = parseInt($siblingTarget[0].value, 10) || 0;
-              }
-
-              $(siblings).find(targetClass).each(function () {
+          } else {
+            // Assume a numeric input field.
+            let weight = 0;
+            const $siblingTarget = $(siblings[0]).find(targetClass);
+            if ($siblingTarget.length) {
+              weight = parseInt($siblingTarget[0].value, 10) || 0;
+            }
+            $(siblings)
+              .find(targetClass)
+              .each(function () {
                 this.value = weight;
                 weight++;
               });
-            }
-
-            break;
           }
+          break;
+        }
       }
     }
   };
 
-  Drupal.tableDrag.prototype.copyDragClasses = function (sourceRow, targetRow, group) {
+  /**
+   * Copy all tableDrag related classes from one row to another.
+   *
+   * Copy all special tableDrag classes from one row's form elements to a
+   * different one, removing any special classes that the destination row
+   * may have had.
+   *
+   * @param {HTMLElement} sourceRow
+   *   The element for the source row.
+   * @param {HTMLElement} targetRow
+   *   The element for the target row.
+   * @param {string} group
+   *   The group selector.
+   */
+  Drupal.tableDrag.prototype.copyDragClasses = function (
+    sourceRow,
+    targetRow,
+    group,
+  ) {
     const sourceElement = $(sourceRow).find(`.${group}`);
     const targetElement = $(targetRow).find(`.${group}`);
-
     if (sourceElement.length && targetElement.length) {
       targetElement[0].className = sourceElement[0].className;
     }
   };
 
+  /**
+   * Check the suggested scroll of the table.
+   *
+   * @param {number} cursorY
+   *   The Y position of the cursor.
+   *
+   * @return {number}
+   *   The suggested scroll.
+   */
   Drupal.tableDrag.prototype.checkScroll = function (cursorY) {
     const de = document.documentElement;
     const b = document.body;
-    const windowHeight = window.innerHeight || (de.clientHeight && de.clientWidth !== 0 ? de.clientHeight : b.offsetHeight);
+
+    const windowHeight =
+      window.innerHeight ||
+      (de.clientHeight && de.clientWidth !== 0
+        ? de.clientHeight
+        : b.offsetHeight);
     this.windowHeight = windowHeight;
     let scrollY;
-
     if (document.all) {
       scrollY = !de.scrollTop ? b.scrollTop : de.scrollTop;
     } else {
       scrollY = window.pageYOffset ? window.pageYOffset : window.scrollY;
     }
-
     this.scrollY = scrollY;
     const trigger = this.scrollSettings.trigger;
     let delta = 0;
 
+    // Return a scroll speed relative to the edge of the screen.
     if (cursorY - scrollY > windowHeight - trigger) {
       delta = trigger / (windowHeight + scrollY - cursorY);
       delta = delta > 0 && delta < trigger ? delta : trigger;
       return delta * this.scrollSettings.amount;
     }
-
     if (cursorY - scrollY < trigger) {
       delta = trigger / (cursorY - scrollY);
       delta = delta > 0 && delta < trigger ? delta : trigger;
@@ -711,33 +1223,93 @@
     }
   };
 
+  /**
+   * Set the scroll for the table.
+   *
+   * @param {number} scrollAmount
+   *   The amount of scroll to apply to the window.
+   */
   Drupal.tableDrag.prototype.setScroll = function (scrollAmount) {
     const self = this;
+
     this.scrollInterval = setInterval(() => {
+      // Update the scroll values stored in the object.
       self.checkScroll(self.currentPointerCoords.y);
       const aboveTable = self.scrollY > self.table.topY;
       const belowTable = self.scrollY + self.windowHeight < self.table.bottomY;
-
-      if (scrollAmount > 0 && belowTable || scrollAmount < 0 && aboveTable) {
+      if (
+        (scrollAmount > 0 && belowTable) ||
+        (scrollAmount < 0 && aboveTable)
+      ) {
         window.scrollBy(0, scrollAmount);
       }
     }, this.scrollSettings.interval);
   };
 
+  /**
+   * Command to restripe table properly.
+   */
   Drupal.tableDrag.prototype.restripeTable = function () {
-    $(this.table).find('> tbody > tr.draggable, > tr.draggable').filter(':visible').filter(':odd').removeClass('odd').addClass('even').end().filter(':even').removeClass('even').addClass('odd');
+    // :even and :odd are reversed because jQuery counts from 0 and
+    // we count from 1, so we're out of sync.
+    // Match immediate children of the parent element to allow nesting.
+    $(this.table)
+      .find('> tbody > tr.draggable, > tr.draggable')
+      .filter(':visible')
+      .filter(':odd')
+      .removeClass('odd')
+      .addClass('even')
+      .end()
+      .filter(':even')
+      .removeClass('even')
+      .addClass('odd');
   };
 
+  /**
+   * Stub function. Allows a custom handler when a row begins dragging.
+   *
+   * @return {null}
+   *   Returns null when the stub function is used.
+   */
   Drupal.tableDrag.prototype.onDrag = function () {
     return null;
   };
 
+  /**
+   * Stub function. Allows a custom handler when a row is dropped.
+   *
+   * @return {null}
+   *   Returns null when the stub function is used.
+   */
   Drupal.tableDrag.prototype.onDrop = function () {
     return null;
   };
 
-  Drupal.tableDrag.prototype.row = function (tableRow, method, indentEnabled, maxDepth, addClasses) {
+  /**
+   * Constructor to make a new object to manipulate a table row.
+   *
+   * @param {HTMLElement} tableRow
+   *   The DOM element for the table row we will be manipulating.
+   * @param {string} method
+   *   The method in which this row is being moved. Either 'keyboard' or
+   *   'mouse'.
+   * @param {bool} indentEnabled
+   *   Whether the containing table uses indentations. Used for optimizations.
+   * @param {number} maxDepth
+   *   The maximum amount of indentations this row may contain.
+   * @param {bool} addClasses
+   *   Whether we want to add classes to this row to indicate child
+   *   relationships.
+   */
+  Drupal.tableDrag.prototype.row = function (
+    tableRow,
+    method,
+    indentEnabled,
+    maxDepth,
+    addClasses,
+  ) {
     const $tableRow = $(tableRow);
+
     this.element = tableRow;
     this.method = method;
     this.group = [tableRow];
@@ -746,20 +1318,35 @@
     this.table = $tableRow.closest('table')[0];
     this.indentEnabled = indentEnabled;
     this.maxDepth = maxDepth;
+    // Direction the row is being moved.
     this.direction = '';
-
     if (this.indentEnabled) {
       this.indents = $tableRow.find('.js-indentation').length;
       this.children = this.findChildren(addClasses);
       this.group = this.group.concat(this.children);
-
+      // Find the depth of this entire group.
       for (let n = 0; n < this.group.length; n++) {
-        this.groupDepth = Math.max($(this.group[n]).find('.js-indentation').length, this.groupDepth);
+        this.groupDepth = Math.max(
+          $(this.group[n]).find('.js-indentation').length,
+          this.groupDepth,
+        );
       }
     }
   };
 
-  Drupal.tableDrag.prototype.row.prototype.findChildren = function (addClasses) {
+  /**
+   * Find all children of rowObject by indentation.
+   *
+   * @param {bool} addClasses
+   *   Whether we want to add classes to this row to indicate child
+   *   relationships.
+   *
+   * @return {Array}
+   *   An array of children of the row.
+   */
+  Drupal.tableDrag.prototype.row.prototype.findChildren = function (
+    addClasses,
+  ) {
     const parentIndentation = this.indents;
     let currentRow = $(this.element, this.table).next('tr.draggable');
     const rows = [];
@@ -767,11 +1354,9 @@
 
     function rowIndentation(indentNum, el) {
       const self = $(el);
-
       if (child === 1 && indentNum === parentIndentation) {
         self.addClass('tree-child-first');
       }
-
       if (indentNum === parentIndentation) {
         self.addClass('tree-child');
       } else if (indentNum > parentIndentation) {
@@ -780,34 +1365,40 @@
     }
 
     while (currentRow.length) {
+      // A greater indentation indicates this is a child.
       if (currentRow.find('.js-indentation').length > parentIndentation) {
         child++;
         rows.push(currentRow[0]);
-
         if (addClasses) {
           currentRow.find('.js-indentation').each(rowIndentation);
         }
       } else {
         break;
       }
-
       currentRow = currentRow.next('tr.draggable');
     }
-
     if (addClasses && rows.length) {
-      $(rows[rows.length - 1]).find(`.js-indentation:nth-child(${parentIndentation + 1})`).addClass('tree-child-last');
+      $(rows[rows.length - 1])
+        .find(`.js-indentation:nth-child(${parentIndentation + 1})`)
+        .addClass('tree-child-last');
     }
-
     return rows;
   };
 
+  /**
+   * Ensure that two rows are allowed to be swapped.
+   *
+   * @param {HTMLElement} row
+   *   DOM object for the row being considered for swapping.
+   *
+   * @return {bool}
+   *   Whether the swap is a valid swap or not.
+   */
   Drupal.tableDrag.prototype.row.prototype.isValidSwap = function (row) {
     const $row = $(row);
-
     if (this.indentEnabled) {
       let prevRow;
       let nextRow;
-
       if (this.direction === 'down') {
         prevRow = row;
         nextRow = $row.next('tr').get(0);
@@ -815,14 +1406,15 @@
         prevRow = $row.prev('tr').get(0);
         nextRow = row;
       }
-
       this.interval = this.validIndentInterval(prevRow, nextRow);
 
+      // We have an invalid swap if the valid indentations interval is empty.
       if (this.interval.min > this.interval.max) {
         return false;
       }
     }
 
+    // Do not let an un-draggable first row have anything put before it.
     if (this.table.tBodies[0].rows[0] === row && $row.is(':not(.draggable)')) {
       return false;
     }
@@ -830,64 +1422,121 @@
     return true;
   };
 
+  /**
+   * Perform the swap between two rows.
+   *
+   * @param {string} position
+   *   Whether the swap will occur 'before' or 'after' the given row.
+   * @param {HTMLElement} row
+   *   DOM element what will be swapped with the row group.
+   */
   Drupal.tableDrag.prototype.row.prototype.swap = function (position, row) {
-    this.group.forEach(row => {
+    // Makes sure only DOM object are passed to Drupal.detachBehaviors().
+    this.group.forEach((row) => {
       Drupal.detachBehaviors(row, drupalSettings, 'move');
     });
     $(row)[position](this.group);
-    this.group.forEach(row => {
+    // Makes sure only DOM object are passed to Drupal.attachBehaviors()s.
+    this.group.forEach((row) => {
       Drupal.attachBehaviors(row, drupalSettings);
     });
     this.changed = true;
     this.onSwap(row);
   };
 
-  Drupal.tableDrag.prototype.row.prototype.validIndentInterval = function (prevRow, nextRow) {
+  /**
+   * Determine the valid indentations interval for the row at a given position.
+   *
+   * @param {?HTMLElement} prevRow
+   *   DOM object for the row before the tested position
+   *   (or null for first position in the table).
+   * @param {?HTMLElement} nextRow
+   *   DOM object for the row after the tested position
+   *   (or null for last position in the table).
+   *
+   * @return {object}
+   *   An object with the keys `min` and `max` to indicate the valid indent
+   *   interval.
+   */
+  Drupal.tableDrag.prototype.row.prototype.validIndentInterval = function (
+    prevRow,
+    nextRow,
+  ) {
     const $prevRow = $(prevRow);
     let maxIndent;
+
+    // Minimum indentation:
+    // Do not orphan the next row.
     const minIndent = nextRow ? $(nextRow).find('.js-indentation').length : 0;
 
-    if (!prevRow || $prevRow.is(':not(.draggable)') || $(this.element).is('.tabledrag-root')) {
+    // Maximum indentation:
+    if (
+      !prevRow ||
+      $prevRow.is(':not(.draggable)') ||
+      $(this.element).is('.tabledrag-root')
+    ) {
+      // Do not indent:
+      // - the first row in the table,
+      // - rows dragged below a non-draggable row,
+      // - 'root' rows.
       maxIndent = 0;
     } else {
-      maxIndent = $prevRow.find('.js-indentation').length + ($prevRow.is('.tabledrag-leaf') ? 0 : 1);
-
+      // Do not go deeper than as a child of the previous row.
+      maxIndent =
+        $prevRow.find('.js-indentation').length +
+        ($prevRow.is('.tabledrag-leaf') ? 0 : 1);
+      // Limit by the maximum allowed depth for the table.
       if (this.maxDepth) {
-        maxIndent = Math.min(maxIndent, this.maxDepth - (this.groupDepth - this.indents));
+        maxIndent = Math.min(
+          maxIndent,
+          this.maxDepth - (this.groupDepth - this.indents),
+        );
       }
     }
 
-    return {
-      min: minIndent,
-      max: maxIndent
-    };
+    return { min: minIndent, max: maxIndent };
   };
 
+  /**
+   * Indent a row within the legal bounds of the table.
+   *
+   * @param {number} indentDiff
+   *   The number of additional indentations proposed for the row (can be
+   *   positive or negative). This number will be adjusted to nearest valid
+   *   indentation level for the row.
+   *
+   * @return {number}
+   *   The number of indentations applied.
+   */
   Drupal.tableDrag.prototype.row.prototype.indent = function (indentDiff) {
     const $group = $(this.group);
-
+    // Determine the valid indentations interval if not available yet.
     if (!this.interval) {
       const prevRow = $(this.element).prev('tr').get(0);
       const nextRow = $group.eq(-1).next('tr').get(0);
       this.interval = this.validIndentInterval(prevRow, nextRow);
     }
 
+    // Adjust to the nearest valid indentation.
     let indent = this.indents + indentDiff;
     indent = Math.max(indent, this.interval.min);
     indent = Math.min(indent, this.interval.max);
     indentDiff = indent - this.indents;
 
     for (let n = 1; n <= Math.abs(indentDiff); n++) {
+      // Add or remove indentations.
       if (indentDiff < 0) {
         $group.find('.js-indentation:first-of-type').remove();
         this.indents--;
       } else {
-        $group.find('td:first-of-type').prepend(Drupal.theme('tableDragIndentation'));
+        $group
+          .find('td:first-of-type')
+          .prepend(Drupal.theme('tableDragIndentation'));
         this.indents++;
       }
     }
-
     if (indentDiff) {
+      // Update indentation for this row.
       this.changed = true;
       this.groupDepth += indentDiff;
       this.onIndent();
@@ -896,17 +1545,32 @@
     return indentDiff;
   };
 
-  Drupal.tableDrag.prototype.row.prototype.findSiblings = function (rowSettings) {
+  /**
+   * Find all siblings for a row.
+   *
+   * According to its subgroup or indentation. Note that the passed-in row is
+   * included in the list of siblings.
+   *
+   * @param {object} rowSettings
+   *   The field settings we're using to identify what constitutes a sibling.
+   *
+   * @return {Array}
+   *   An array of siblings.
+   */
+  Drupal.tableDrag.prototype.row.prototype.findSiblings = function (
+    rowSettings,
+  ) {
     const siblings = [];
     const directions = ['prev', 'next'];
     const rowIndentation = this.indents;
     let checkRowIndentation;
-
     for (let d = 0; d < directions.length; d++) {
       let checkRow = $(this.element)[directions[d]]();
-
       while (checkRow.length) {
+        // Check that the sibling contains a similar target field.
         if (checkRow.find(`.${rowSettings.target}`)) {
+          // Either add immediately if this is a flat table, or check to ensure
+          // that this row has the same level of indentation.
           if (this.indentEnabled) {
             checkRowIndentation = checkRow.find('.js-indentation').length;
           }
@@ -914,69 +1578,134 @@
           if (!this.indentEnabled || checkRowIndentation === rowIndentation) {
             siblings.push(checkRow[0]);
           } else if (checkRowIndentation < rowIndentation) {
+            // No need to keep looking for siblings when we get to a parent.
             break;
           }
         } else {
           break;
         }
-
         checkRow = checkRow[directions[d]]();
       }
-
+      // Since siblings are added in reverse order for previous, reverse the
+      // completed list of previous siblings. Add the current row and continue.
       if (directions[d] === 'prev') {
         siblings.reverse();
         siblings.push(this.element);
       }
     }
-
     return siblings;
   };
 
+  /**
+   * Remove indentation helper classes from the current row group.
+   */
   Drupal.tableDrag.prototype.row.prototype.removeIndentClasses = function () {
-    Object.keys(this.children || {}).forEach(n => {
-      $(this.children[n]).find('.js-indentation').removeClass('tree-child').removeClass('tree-child-first').removeClass('tree-child-last').removeClass('tree-child-horizontal');
+    Object.keys(this.children || {}).forEach((n) => {
+      $(this.children[n])
+        .find('.js-indentation')
+        .removeClass('tree-child')
+        .removeClass('tree-child-first')
+        .removeClass('tree-child-last')
+        .removeClass('tree-child-horizontal');
     });
   };
 
+  /**
+   * Add an asterisk or other marker to the changed row.
+   */
   Drupal.tableDrag.prototype.row.prototype.markChanged = function () {
     const marker = Drupal.theme('tableDragChangedMarker');
     const cell = $(this.element).find('td:first-of-type');
-
     if (cell.find('abbr.tabledrag-changed').length === 0) {
       cell.append(marker);
     }
   };
 
+  /**
+   * Stub function. Allows a custom handler when a row is indented.
+   *
+   * @return {null}
+   *   Returns null when the stub function is used.
+   */
   Drupal.tableDrag.prototype.row.prototype.onIndent = function () {
     return null;
   };
 
+  /**
+   * Stub function. Allows a custom handler when a row is swapped.
+   *
+   * @param {HTMLElement} swappedRow
+   *   The element for the swapped row.
+   *
+   * @return {null}
+   *   Returns null when the stub function is used.
+   */
   Drupal.tableDrag.prototype.row.prototype.onSwap = function (swappedRow) {
     return null;
   };
 
-  $.extend(Drupal.theme, {
-    tableDragChangedMarker() {
-      return `<abbr class="warning tabledrag-changed" title="${Drupal.t('Changed')}">*</abbr>`;
-    },
-
-    tableDragIndentation() {
-      return '<div class="js-indentation indentation">&nbsp;</div>';
-    },
-
-    tableDragChangedWarning() {
-      return `<div class="tabledrag-changed-warning messages messages--warning" role="alert">${Drupal.theme('tableDragChangedMarker')} ${Drupal.t('You have unsaved changes.')}</div>`;
-    },
-
-    tableDragToggle: () => `<div class="tabledrag-toggle-weight-wrapper" data-drupal-selector="tabledrag-toggle-weight-wrapper">
+  $.extend(
+    Drupal.theme,
+    /** @lends Drupal.theme */ {
+      /**
+       * @return {string}
+       *  Markup for the marker.
+       */
+      tableDragChangedMarker() {
+        return `<abbr class="warning tabledrag-changed" title="${Drupal.t(
+          'Changed',
+        )}">*</abbr>`;
+      },
+
+      /**
+       * @return {string}
+       *   Markup for the indentation.
+       */
+      tableDragIndentation() {
+        return '<div class="js-indentation indentation">&nbsp;</div>';
+      },
+
+      /**
+       * @return {string}
+       *   Markup for the warning.
+       */
+      tableDragChangedWarning() {
+        return `<div class="tabledrag-changed-warning messages messages--warning" role="alert">${Drupal.theme(
+          'tableDragChangedMarker',
+        )} ${Drupal.t('You have unsaved changes.')}</div>`;
+      },
+
+      /**
+       * The button for toggling table row weight visibility.
+       *
+       * @return {string}
+       *   HTML markup for the weight toggle button and its container.
+       */
+      tableDragToggle: () =>
+        `<div class="tabledrag-toggle-weight-wrapper" data-drupal-selector="tabledrag-toggle-weight-wrapper">
             <button type="button" class="link tabledrag-toggle-weight" data-drupal-selector="tabledrag-toggle-weight"></button>
             </div>`,
-    toggleButtonContent: show => show ? Drupal.t('Hide row weights') : Drupal.t('Show row weights'),
 
-    tableDragHandle() {
-      return `<a href="#" title="${Drupal.t('Drag to re-order')}"
+      /**
+       * The contents of the toggle weight button.
+       *
+       * @param {boolean} show
+       *   If the table weights are currently displayed.
+       *
+       * @return {string}
+       *  HTML markup for the weight toggle button content.s
+       */
+      toggleButtonContent: (show) =>
+        show ? Drupal.t('Hide row weights') : Drupal.t('Show row weights'),
+
+      /**
+       * @return {string}
+       *   HTML markup for a tableDrag handle.
+       */
+      tableDragHandle() {
+        return `<a href="#" title="${Drupal.t('Drag to re-order')}"
         class="tabledrag-handle"><div class="handle"></div></a>`;
-    }
-
-  });
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+      },
+    },
+  );
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/misc/tableheader.es6.js b/core/misc/tableheader.es6.js
deleted file mode 100644
index 1d4eca7e69e5..000000000000
--- a/core/misc/tableheader.es6.js
+++ /dev/null
@@ -1,335 +0,0 @@
-/**
- * @file
- * Sticky table headers.
- */
-
-(function ($, Drupal, displace) {
-  /**
-   * Constructor for the tableHeader object. Provides sticky table headers.
-   *
-   * TableHeader will make the current table header stick to the top of the page
-   * if the table is very long.
-   *
-   * @constructor Drupal.TableHeader
-   *
-   * @param {HTMLElement} table
-   *   DOM object for the table to add a sticky header to.
-   *
-   * @listens event:columnschange
-   */
-  function TableHeader(table) {
-    const $table = $(table);
-
-    /**
-     * @name Drupal.TableHeader#$originalTable
-     *
-     * @type {HTMLElement}
-     */
-    this.$originalTable = $table;
-
-    /**
-     * @type {jQuery}
-     */
-    this.$originalHeader = $table.children('thead');
-
-    /**
-     * @type {jQuery}
-     */
-    this.$originalHeaderCells = this.$originalHeader.find('> tr > th');
-
-    /**
-     * @type {null|bool}
-     */
-    this.displayWeight = null;
-    this.$originalTable.addClass('sticky-table');
-    this.tableHeight = $table[0].clientHeight;
-    this.tableOffset = this.$originalTable.offset();
-
-    // React to columns change to avoid making checks in the scroll callback.
-    this.$originalTable.on(
-      'columnschange',
-      { tableHeader: this },
-      (e, display) => {
-        const tableHeader = e.data.tableHeader;
-        if (
-          tableHeader.displayWeight === null ||
-          tableHeader.displayWeight !== display
-        ) {
-          tableHeader.recalculateSticky();
-        }
-        tableHeader.displayWeight = display;
-      },
-    );
-
-    // Create and display sticky header.
-    this.createSticky();
-  }
-
-  // Helper method to loop through tables and execute a method.
-  function forTables(method, arg) {
-    const tables = TableHeader.tables;
-    const il = tables.length;
-    for (let i = 0; i < il; i++) {
-      tables[i][method](arg);
-    }
-  }
-
-  // Select and initialize sticky table headers.
-  function tableHeaderInitHandler(e) {
-    once('tableheader', $(e.data.context).find('table.sticky-enabled')).forEach(
-      (table) => {
-        TableHeader.tables.push(new TableHeader(table));
-      },
-    );
-    forTables('onScroll');
-  }
-
-  /**
-   * Attaches sticky table headers.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the sticky table header behavior.
-   */
-  Drupal.behaviors.tableHeader = {
-    attach(context) {
-      $(window).one(
-        'scroll.TableHeaderInit',
-        { context },
-        tableHeaderInitHandler,
-      );
-    },
-  };
-
-  function scrollValue(position) {
-    return document.documentElement[position] || document.body[position];
-  }
-
-  function tableHeaderResizeHandler(e) {
-    forTables('recalculateSticky');
-  }
-
-  function tableHeaderOnScrollHandler(e) {
-    forTables('onScroll');
-  }
-
-  function tableHeaderOffsetChangeHandler(e, offsets) {
-    forTables('stickyPosition', offsets.top);
-  }
-
-  // Bind event that need to change all tables.
-  $(window).on({
-    /**
-     * When resizing table width can change, recalculate everything.
-     *
-     * @ignore
-     */
-    'resize.TableHeader': tableHeaderResizeHandler,
-
-    /**
-     * Bind only one event to take care of calling all scroll callbacks.
-     *
-     * @ignore
-     */
-    'scroll.TableHeader': tableHeaderOnScrollHandler,
-  });
-  // Bind to custom Drupal events.
-  $(document).on({
-    /**
-     * Recalculate columns width when window is resized, when show/hide weight
-     * is triggered, or when toolbar tray is toggled.
-     *
-     * @ignore
-     */
-    'columnschange.TableHeader drupalToolbarTrayChange':
-      tableHeaderResizeHandler,
-
-    /**
-     * Recalculate TableHeader.topOffset when viewport is resized.
-     *
-     * @ignore
-     */
-    'drupalViewportOffsetChange.TableHeader': tableHeaderOffsetChangeHandler,
-  });
-
-  /**
-   * Store the state of TableHeader.
-   */
-  $.extend(
-    TableHeader,
-    /** @lends Drupal.TableHeader */ {
-      /**
-       * This will store the state of all processed tables.
-       *
-       * @type {Array.<Drupal.TableHeader>}
-       */
-      tables: [],
-    },
-  );
-
-  /**
-   * Extend TableHeader prototype.
-   */
-  $.extend(
-    TableHeader.prototype,
-    /** @lends Drupal.TableHeader# */ {
-      /**
-       * Minimum height in pixels for the table to have a sticky header.
-       *
-       * @type {number}
-       */
-      minHeight: 100,
-
-      /**
-       * Absolute position of the table on the page.
-       *
-       * @type {?Drupal~displaceOffset}
-       */
-      tableOffset: null,
-
-      /**
-       * Absolute position of the table on the page.
-       *
-       * @type {?number}
-       */
-      tableHeight: null,
-
-      /**
-       * Boolean storing the sticky header visibility state.
-       *
-       * @type {bool}
-       */
-      stickyVisible: false,
-
-      /**
-       * Create the duplicate header.
-       */
-      createSticky() {
-        // For caching purposes.
-        this.$html = $('html');
-        // Clone the table header so it inherits original jQuery properties.
-        const $stickyHeader = this.$originalHeader.clone(true);
-        // Hide the table to avoid a flash of the header clone upon page load.
-        this.$stickyTable = $('<table class="sticky-header"></table>')
-          .css({
-            visibility: 'hidden',
-            position: 'fixed',
-            top: '0px',
-          })
-          .append($stickyHeader)
-          .insertBefore(this.$originalTable);
-
-        this.$stickyHeaderCells = $stickyHeader.find('> tr > th');
-
-        // Initialize all computations.
-        this.recalculateSticky();
-      },
-
-      /**
-       * Set absolute position of sticky.
-       *
-       * @param {number} offsetTop
-       *   The top offset for the sticky header.
-       * @param {number} offsetLeft
-       *   The left offset for the sticky header.
-       *
-       * @return {jQuery}
-       *   The sticky table as a jQuery collection.
-       */
-      stickyPosition(offsetTop, offsetLeft) {
-        const css = {};
-        if (typeof offsetTop === 'number') {
-          css.top = `${offsetTop}px`;
-        }
-        if (typeof offsetLeft === 'number') {
-          css.left = `${this.tableOffset.left - offsetLeft}px`;
-        }
-        this.$html.css(
-          'scroll-padding-top',
-          displace.offsets.top +
-            (this.stickyVisible ? this.$stickyTable.height() : 0),
-        );
-        return this.$stickyTable.css(css);
-      },
-
-      /**
-       * Returns true if sticky is currently visible.
-       *
-       * @return {bool}
-       *   The visibility status.
-       */
-      checkStickyVisible() {
-        const scrollTop = scrollValue('scrollTop');
-        const tableTop = this.tableOffset.top - displace.offsets.top;
-        const tableBottom = tableTop + this.tableHeight;
-        let visible = false;
-
-        if (tableTop < scrollTop && scrollTop < tableBottom - this.minHeight) {
-          visible = true;
-        }
-
-        this.stickyVisible = visible;
-        return visible;
-      },
-
-      /**
-       * Check if sticky header should be displayed.
-       *
-       * This function is throttled to once every 250ms to avoid unnecessary
-       * calls.
-       *
-       * @param {jQuery.Event} e
-       *   The scroll event.
-       */
-      onScroll(e) {
-        this.checkStickyVisible();
-        // Track horizontal positioning relative to the viewport.
-        this.stickyPosition(null, scrollValue('scrollLeft'));
-        this.$stickyTable.css(
-          'visibility',
-          this.stickyVisible ? 'visible' : 'hidden',
-        );
-      },
-
-      /**
-       * Event handler: recalculates position of the sticky table header.
-       *
-       * @param {jQuery.Event} event
-       *   Event being triggered.
-       */
-      recalculateSticky(event) {
-        // Update table size.
-        this.tableHeight = this.$originalTable[0].clientHeight;
-
-        // Update offset top.
-        displace.offsets.top = displace.calculateOffset('top');
-        this.tableOffset = this.$originalTable.offset();
-        this.stickyPosition(displace.offsets.top, scrollValue('scrollLeft'));
-
-        // Update columns width.
-        let $that = null;
-        let $stickyCell = null;
-        let display = null;
-        // Resize header and its cell widths.
-        // Only apply width to visible table cells. This prevents the header from
-        // displaying incorrectly when the sticky header is no longer visible.
-        const il = this.$originalHeaderCells.length;
-        for (let i = 0; i < il; i++) {
-          $that = $(this.$originalHeaderCells[i]);
-          $stickyCell = this.$stickyHeaderCells.eq($that.index());
-          display = $that.css('display');
-          if (display !== 'none') {
-            $stickyCell.css({ width: $that.css('width'), display });
-          } else {
-            $stickyCell.css('display', 'none');
-          }
-        }
-        this.$stickyTable.css('width', this.$originalTable.outerWidth());
-      },
-    },
-  );
-
-  // Expose constructor in the public space.
-  Drupal.TableHeader = TableHeader;
-})(jQuery, Drupal, window.Drupal.displace);
diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js
index 35eef3057373..1d4eca7e69e5 100644
--- a/core/misc/tableheader.js
+++ b/core/misc/tableheader.js
@@ -1,57 +1,105 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Sticky table headers.
+ */
 
 (function ($, Drupal, displace) {
+  /**
+   * Constructor for the tableHeader object. Provides sticky table headers.
+   *
+   * TableHeader will make the current table header stick to the top of the page
+   * if the table is very long.
+   *
+   * @constructor Drupal.TableHeader
+   *
+   * @param {HTMLElement} table
+   *   DOM object for the table to add a sticky header to.
+   *
+   * @listens event:columnschange
+   */
   function TableHeader(table) {
     const $table = $(table);
+
+    /**
+     * @name Drupal.TableHeader#$originalTable
+     *
+     * @type {HTMLElement}
+     */
     this.$originalTable = $table;
+
+    /**
+     * @type {jQuery}
+     */
     this.$originalHeader = $table.children('thead');
+
+    /**
+     * @type {jQuery}
+     */
     this.$originalHeaderCells = this.$originalHeader.find('> tr > th');
+
+    /**
+     * @type {null|bool}
+     */
     this.displayWeight = null;
     this.$originalTable.addClass('sticky-table');
     this.tableHeight = $table[0].clientHeight;
     this.tableOffset = this.$originalTable.offset();
-    this.$originalTable.on('columnschange', {
-      tableHeader: this
-    }, (e, display) => {
-      const tableHeader = e.data.tableHeader;
 
-      if (tableHeader.displayWeight === null || tableHeader.displayWeight !== display) {
-        tableHeader.recalculateSticky();
-      }
+    // React to columns change to avoid making checks in the scroll callback.
+    this.$originalTable.on(
+      'columnschange',
+      { tableHeader: this },
+      (e, display) => {
+        const tableHeader = e.data.tableHeader;
+        if (
+          tableHeader.displayWeight === null ||
+          tableHeader.displayWeight !== display
+        ) {
+          tableHeader.recalculateSticky();
+        }
+        tableHeader.displayWeight = display;
+      },
+    );
 
-      tableHeader.displayWeight = display;
-    });
+    // Create and display sticky header.
     this.createSticky();
   }
 
+  // Helper method to loop through tables and execute a method.
   function forTables(method, arg) {
     const tables = TableHeader.tables;
     const il = tables.length;
-
     for (let i = 0; i < il; i++) {
       tables[i][method](arg);
     }
   }
 
+  // Select and initialize sticky table headers.
   function tableHeaderInitHandler(e) {
-    once('tableheader', $(e.data.context).find('table.sticky-enabled')).forEach(table => {
-      TableHeader.tables.push(new TableHeader(table));
-    });
+    once('tableheader', $(e.data.context).find('table.sticky-enabled')).forEach(
+      (table) => {
+        TableHeader.tables.push(new TableHeader(table));
+      },
+    );
     forTables('onScroll');
   }
 
+  /**
+   * Attaches sticky table headers.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the sticky table header behavior.
+   */
   Drupal.behaviors.tableHeader = {
     attach(context) {
-      $(window).one('scroll.TableHeaderInit', {
-        context
-      }, tableHeaderInitHandler);
-    }
-
+      $(window).one(
+        'scroll.TableHeaderInit',
+        { context },
+        tableHeaderInitHandler,
+      );
+    },
   };
 
   function scrollValue(position) {
@@ -70,98 +118,218 @@
     forTables('stickyPosition', offsets.top);
   }
 
+  // Bind event that need to change all tables.
   $(window).on({
+    /**
+     * When resizing table width can change, recalculate everything.
+     *
+     * @ignore
+     */
     'resize.TableHeader': tableHeaderResizeHandler,
-    'scroll.TableHeader': tableHeaderOnScrollHandler
+
+    /**
+     * Bind only one event to take care of calling all scroll callbacks.
+     *
+     * @ignore
+     */
+    'scroll.TableHeader': tableHeaderOnScrollHandler,
   });
+  // Bind to custom Drupal events.
   $(document).on({
-    'columnschange.TableHeader drupalToolbarTrayChange': tableHeaderResizeHandler,
-    'drupalViewportOffsetChange.TableHeader': tableHeaderOffsetChangeHandler
-  });
-  $.extend(TableHeader, {
-    tables: []
+    /**
+     * Recalculate columns width when window is resized, when show/hide weight
+     * is triggered, or when toolbar tray is toggled.
+     *
+     * @ignore
+     */
+    'columnschange.TableHeader drupalToolbarTrayChange':
+      tableHeaderResizeHandler,
+
+    /**
+     * Recalculate TableHeader.topOffset when viewport is resized.
+     *
+     * @ignore
+     */
+    'drupalViewportOffsetChange.TableHeader': tableHeaderOffsetChangeHandler,
   });
-  $.extend(TableHeader.prototype, {
-    minHeight: 100,
-    tableOffset: null,
-    tableHeight: null,
-    stickyVisible: false,
-
-    createSticky() {
-      this.$html = $('html');
-      const $stickyHeader = this.$originalHeader.clone(true);
-      this.$stickyTable = $('<table class="sticky-header"></table>').css({
-        visibility: 'hidden',
-        position: 'fixed',
-        top: '0px'
-      }).append($stickyHeader).insertBefore(this.$originalTable);
-      this.$stickyHeaderCells = $stickyHeader.find('> tr > th');
-      this.recalculateSticky();
+
+  /**
+   * Store the state of TableHeader.
+   */
+  $.extend(
+    TableHeader,
+    /** @lends Drupal.TableHeader */ {
+      /**
+       * This will store the state of all processed tables.
+       *
+       * @type {Array.<Drupal.TableHeader>}
+       */
+      tables: [],
     },
+  );
 
-    stickyPosition(offsetTop, offsetLeft) {
-      const css = {};
+  /**
+   * Extend TableHeader prototype.
+   */
+  $.extend(
+    TableHeader.prototype,
+    /** @lends Drupal.TableHeader# */ {
+      /**
+       * Minimum height in pixels for the table to have a sticky header.
+       *
+       * @type {number}
+       */
+      minHeight: 100,
 
-      if (typeof offsetTop === 'number') {
-        css.top = `${offsetTop}px`;
-      }
+      /**
+       * Absolute position of the table on the page.
+       *
+       * @type {?Drupal~displaceOffset}
+       */
+      tableOffset: null,
 
-      if (typeof offsetLeft === 'number') {
-        css.left = `${this.tableOffset.left - offsetLeft}px`;
-      }
+      /**
+       * Absolute position of the table on the page.
+       *
+       * @type {?number}
+       */
+      tableHeight: null,
 
-      this.$html.css('scroll-padding-top', displace.offsets.top + (this.stickyVisible ? this.$stickyTable.height() : 0));
-      return this.$stickyTable.css(css);
-    },
+      /**
+       * Boolean storing the sticky header visibility state.
+       *
+       * @type {bool}
+       */
+      stickyVisible: false,
 
-    checkStickyVisible() {
-      const scrollTop = scrollValue('scrollTop');
-      const tableTop = this.tableOffset.top - displace.offsets.top;
-      const tableBottom = tableTop + this.tableHeight;
-      let visible = false;
+      /**
+       * Create the duplicate header.
+       */
+      createSticky() {
+        // For caching purposes.
+        this.$html = $('html');
+        // Clone the table header so it inherits original jQuery properties.
+        const $stickyHeader = this.$originalHeader.clone(true);
+        // Hide the table to avoid a flash of the header clone upon page load.
+        this.$stickyTable = $('<table class="sticky-header"></table>')
+          .css({
+            visibility: 'hidden',
+            position: 'fixed',
+            top: '0px',
+          })
+          .append($stickyHeader)
+          .insertBefore(this.$originalTable);
 
-      if (tableTop < scrollTop && scrollTop < tableBottom - this.minHeight) {
-        visible = true;
-      }
+        this.$stickyHeaderCells = $stickyHeader.find('> tr > th');
 
-      this.stickyVisible = visible;
-      return visible;
-    },
+        // Initialize all computations.
+        this.recalculateSticky();
+      },
 
-    onScroll(e) {
-      this.checkStickyVisible();
-      this.stickyPosition(null, scrollValue('scrollLeft'));
-      this.$stickyTable.css('visibility', this.stickyVisible ? 'visible' : 'hidden');
-    },
+      /**
+       * Set absolute position of sticky.
+       *
+       * @param {number} offsetTop
+       *   The top offset for the sticky header.
+       * @param {number} offsetLeft
+       *   The left offset for the sticky header.
+       *
+       * @return {jQuery}
+       *   The sticky table as a jQuery collection.
+       */
+      stickyPosition(offsetTop, offsetLeft) {
+        const css = {};
+        if (typeof offsetTop === 'number') {
+          css.top = `${offsetTop}px`;
+        }
+        if (typeof offsetLeft === 'number') {
+          css.left = `${this.tableOffset.left - offsetLeft}px`;
+        }
+        this.$html.css(
+          'scroll-padding-top',
+          displace.offsets.top +
+            (this.stickyVisible ? this.$stickyTable.height() : 0),
+        );
+        return this.$stickyTable.css(css);
+      },
 
-    recalculateSticky(event) {
-      this.tableHeight = this.$originalTable[0].clientHeight;
-      displace.offsets.top = displace.calculateOffset('top');
-      this.tableOffset = this.$originalTable.offset();
-      this.stickyPosition(displace.offsets.top, scrollValue('scrollLeft'));
-      let $that = null;
-      let $stickyCell = null;
-      let display = null;
-      const il = this.$originalHeaderCells.length;
-
-      for (let i = 0; i < il; i++) {
-        $that = $(this.$originalHeaderCells[i]);
-        $stickyCell = this.$stickyHeaderCells.eq($that.index());
-        display = $that.css('display');
-
-        if (display !== 'none') {
-          $stickyCell.css({
-            width: $that.css('width'),
-            display
-          });
-        } else {
-          $stickyCell.css('display', 'none');
+      /**
+       * Returns true if sticky is currently visible.
+       *
+       * @return {bool}
+       *   The visibility status.
+       */
+      checkStickyVisible() {
+        const scrollTop = scrollValue('scrollTop');
+        const tableTop = this.tableOffset.top - displace.offsets.top;
+        const tableBottom = tableTop + this.tableHeight;
+        let visible = false;
+
+        if (tableTop < scrollTop && scrollTop < tableBottom - this.minHeight) {
+          visible = true;
         }
-      }
 
-      this.$stickyTable.css('width', this.$originalTable.outerWidth());
-    }
+        this.stickyVisible = visible;
+        return visible;
+      },
 
-  });
+      /**
+       * Check if sticky header should be displayed.
+       *
+       * This function is throttled to once every 250ms to avoid unnecessary
+       * calls.
+       *
+       * @param {jQuery.Event} e
+       *   The scroll event.
+       */
+      onScroll(e) {
+        this.checkStickyVisible();
+        // Track horizontal positioning relative to the viewport.
+        this.stickyPosition(null, scrollValue('scrollLeft'));
+        this.$stickyTable.css(
+          'visibility',
+          this.stickyVisible ? 'visible' : 'hidden',
+        );
+      },
+
+      /**
+       * Event handler: recalculates position of the sticky table header.
+       *
+       * @param {jQuery.Event} event
+       *   Event being triggered.
+       */
+      recalculateSticky(event) {
+        // Update table size.
+        this.tableHeight = this.$originalTable[0].clientHeight;
+
+        // Update offset top.
+        displace.offsets.top = displace.calculateOffset('top');
+        this.tableOffset = this.$originalTable.offset();
+        this.stickyPosition(displace.offsets.top, scrollValue('scrollLeft'));
+
+        // Update columns width.
+        let $that = null;
+        let $stickyCell = null;
+        let display = null;
+        // Resize header and its cell widths.
+        // Only apply width to visible table cells. This prevents the header from
+        // displaying incorrectly when the sticky header is no longer visible.
+        const il = this.$originalHeaderCells.length;
+        for (let i = 0; i < il; i++) {
+          $that = $(this.$originalHeaderCells[i]);
+          $stickyCell = this.$stickyHeaderCells.eq($that.index());
+          display = $that.css('display');
+          if (display !== 'none') {
+            $stickyCell.css({ width: $that.css('width'), display });
+          } else {
+            $stickyCell.css('display', 'none');
+          }
+        }
+        this.$stickyTable.css('width', this.$originalTable.outerWidth());
+      },
+    },
+  );
+
+  // Expose constructor in the public space.
   Drupal.TableHeader = TableHeader;
-})(jQuery, Drupal, window.Drupal.displace);
\ No newline at end of file
+})(jQuery, Drupal, window.Drupal.displace);
diff --git a/core/misc/tableresponsive.es6.js b/core/misc/tableresponsive.es6.js
deleted file mode 100644
index 840bbf0e8cb1..000000000000
--- a/core/misc/tableresponsive.es6.js
+++ /dev/null
@@ -1,194 +0,0 @@
-/**
- * @file
- * Responsive table functionality.
- */
-
-(function ($, Drupal, window) {
-  /**
-   * The TableResponsive object optimizes table presentation for screen size.
-   *
-   * A responsive table hides columns at small screen sizes, leaving the most
-   * important columns visible to the end user. Users should not be prevented
-   * from accessing all columns, however. This class adds a toggle to a table
-   * with hidden columns that exposes the columns. Exposing the columns will
-   * likely break layouts, but it provides the user with a means to access
-   * data, which is a guiding principle of responsive design.
-   *
-   * @constructor Drupal.TableResponsive
-   *
-   * @param {HTMLElement} table
-   *   The table element to initialize the responsive table on.
-   */
-  function TableResponsive(table) {
-    this.table = table;
-    this.$table = $(table);
-    this.showText = Drupal.t('Show all columns');
-    this.hideText = Drupal.t('Hide lower priority columns');
-    // Store a reference to the header elements of the table so that the DOM is
-    // traversed only once to find them.
-    this.$headers = this.$table.find('th');
-    // Add a link before the table for users to show or hide weight columns.
-    this.$link = $(
-      '<button type="button" class="link tableresponsive-toggle"></button>',
-    )
-      .attr(
-        'title',
-        Drupal.t(
-          'Show table cells that were hidden to make the table fit within a small screen.',
-        ),
-      )
-      .on('click', $.proxy(this, 'eventhandlerToggleColumns'));
-
-    this.$table.before(
-      $('<div class="tableresponsive-toggle-columns"></div>').append(
-        this.$link,
-      ),
-    );
-
-    // Attach a resize handler to the window.
-    $(window)
-      .on(
-        'resize.tableresponsive',
-        $.proxy(this, 'eventhandlerEvaluateColumnVisibility'),
-      )
-      .trigger('resize.tableresponsive');
-  }
-
-  /**
-   * Attach the tableResponsive function to {@link Drupal.behaviors}.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches tableResponsive functionality.
-   */
-  Drupal.behaviors.tableResponsive = {
-    attach(context, settings) {
-      once('tableresponsive', 'table.responsive-enabled', context).forEach(
-        (table) => {
-          TableResponsive.tables.push(new TableResponsive(table));
-        },
-      );
-    },
-  };
-
-  /**
-   * Extend the TableResponsive function with a list of managed tables.
-   */
-  $.extend(
-    TableResponsive,
-    /** @lends Drupal.TableResponsive */ {
-      /**
-       * Store all created instances.
-       *
-       * @type {Array.<Drupal.TableResponsive>}
-       */
-      tables: [],
-    },
-  );
-
-  /**
-   * Associates an action link with the table that will show hidden columns.
-   *
-   * Columns are assumed to be hidden if their header has the class priority-low
-   * or priority-medium.
-   */
-  $.extend(
-    TableResponsive.prototype,
-    /** @lends Drupal.TableResponsive# */ {
-      /**
-       * @param {jQuery.Event} e
-       *   The event triggered.
-       */
-      eventhandlerEvaluateColumnVisibility(e) {
-        const pegged = parseInt(this.$link.data('pegged'), 10);
-        const hiddenLength = this.$headers.filter(
-          '.priority-medium:hidden, .priority-low:hidden',
-        ).length;
-        // If the table has hidden columns, associate an action link with the
-        // table to show the columns.
-        if (hiddenLength > 0) {
-          this.$link.show();
-          this.$link[0].textContent = this.showText;
-        }
-        // When the toggle is pegged, its presence is maintained because the user
-        // has interacted with it. This is necessary to keep the link visible if
-        // the user adjusts screen size and changes the visibility of columns.
-        if (!pegged && hiddenLength === 0) {
-          this.$link.hide();
-          this.$link[0].textContent = this.hideText;
-        }
-      },
-
-      /**
-       * Toggle the visibility of columns based on their priority.
-       *
-       * Columns are classed with either 'priority-low' or 'priority-medium'.
-       *
-       * @param {jQuery.Event} e
-       *   The event triggered.
-       */
-      eventhandlerToggleColumns(e) {
-        e.preventDefault();
-        const self = this;
-        const $hiddenHeaders = this.$headers.filter(
-          '.priority-medium:hidden, .priority-low:hidden',
-        );
-        this.$revealedCells = this.$revealedCells || $();
-        // Reveal hidden columns.
-        if ($hiddenHeaders.length > 0) {
-          $hiddenHeaders.each(function (index, element) {
-            const $header = $(this);
-            const position = $header.prevAll('th').length;
-            self.$table.find('tbody tr').each(function () {
-              const $cells = $(this).find('td').eq(position);
-              $cells.show();
-              // Keep track of the revealed cells, so they can be hidden later.
-              self.$revealedCells = $().add(self.$revealedCells).add($cells);
-            });
-            $header.show();
-            // Keep track of the revealed headers, so they can be hidden later.
-            self.$revealedCells = $().add(self.$revealedCells).add($header);
-          });
-          this.$link[0].textContent = this.hideText;
-          this.$link.data('pegged', 1);
-        }
-        // Hide revealed columns.
-        else {
-          this.$revealedCells.hide();
-          // Strip the 'display:none' declaration from the style attributes of
-          // the table cells that .hide() added.
-          this.$revealedCells.each(function (index, element) {
-            const $cell = $(this);
-            const properties = $cell.attr('style').split(';');
-            const newProps = [];
-            // The hide method adds display none to the element. The element
-            // should be returned to the same state it was in before the columns
-            // were revealed, so it is necessary to remove the display none value
-            // from the style attribute.
-            const match = /^display\s*:\s*none$/;
-            for (let i = 0; i < properties.length; i++) {
-              const prop = properties[i];
-              prop.trim();
-              // Find the display:none property and remove it.
-              const isDisplayNone = match.exec(prop);
-              if (isDisplayNone) {
-                continue;
-              }
-              newProps.push(prop);
-            }
-            // Return the rest of the style attribute values to the element.
-            $cell.attr('style', newProps.join(';'));
-          });
-          this.$link[0].textContent = this.showText;
-          this.$link.data('pegged', 0);
-          // Refresh the toggle link.
-          $(window).trigger('resize.tableresponsive');
-        }
-      },
-    },
-  );
-
-  // Make the TableResponsive object available in the Drupal namespace.
-  Drupal.TableResponsive = TableResponsive;
-})(jQuery, Drupal, window);
diff --git a/core/misc/tableresponsive.js b/core/misc/tableresponsive.js
index 2f4ad6d20601..840bbf0e8cb1 100644
--- a/core/misc/tableresponsive.js
+++ b/core/misc/tableresponsive.js
@@ -1,97 +1,194 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Responsive table functionality.
+ */
 
 (function ($, Drupal, window) {
+  /**
+   * The TableResponsive object optimizes table presentation for screen size.
+   *
+   * A responsive table hides columns at small screen sizes, leaving the most
+   * important columns visible to the end user. Users should not be prevented
+   * from accessing all columns, however. This class adds a toggle to a table
+   * with hidden columns that exposes the columns. Exposing the columns will
+   * likely break layouts, but it provides the user with a means to access
+   * data, which is a guiding principle of responsive design.
+   *
+   * @constructor Drupal.TableResponsive
+   *
+   * @param {HTMLElement} table
+   *   The table element to initialize the responsive table on.
+   */
   function TableResponsive(table) {
     this.table = table;
     this.$table = $(table);
     this.showText = Drupal.t('Show all columns');
     this.hideText = Drupal.t('Hide lower priority columns');
+    // Store a reference to the header elements of the table so that the DOM is
+    // traversed only once to find them.
     this.$headers = this.$table.find('th');
-    this.$link = $('<button type="button" class="link tableresponsive-toggle"></button>').attr('title', Drupal.t('Show table cells that were hidden to make the table fit within a small screen.')).on('click', $.proxy(this, 'eventhandlerToggleColumns'));
-    this.$table.before($('<div class="tableresponsive-toggle-columns"></div>').append(this.$link));
-    $(window).on('resize.tableresponsive', $.proxy(this, 'eventhandlerEvaluateColumnVisibility')).trigger('resize.tableresponsive');
+    // Add a link before the table for users to show or hide weight columns.
+    this.$link = $(
+      '<button type="button" class="link tableresponsive-toggle"></button>',
+    )
+      .attr(
+        'title',
+        Drupal.t(
+          'Show table cells that were hidden to make the table fit within a small screen.',
+        ),
+      )
+      .on('click', $.proxy(this, 'eventhandlerToggleColumns'));
+
+    this.$table.before(
+      $('<div class="tableresponsive-toggle-columns"></div>').append(
+        this.$link,
+      ),
+    );
+
+    // Attach a resize handler to the window.
+    $(window)
+      .on(
+        'resize.tableresponsive',
+        $.proxy(this, 'eventhandlerEvaluateColumnVisibility'),
+      )
+      .trigger('resize.tableresponsive');
   }
 
+  /**
+   * Attach the tableResponsive function to {@link Drupal.behaviors}.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches tableResponsive functionality.
+   */
   Drupal.behaviors.tableResponsive = {
     attach(context, settings) {
-      once('tableresponsive', 'table.responsive-enabled', context).forEach(table => {
-        TableResponsive.tables.push(new TableResponsive(table));
-      });
-    }
-
+      once('tableresponsive', 'table.responsive-enabled', context).forEach(
+        (table) => {
+          TableResponsive.tables.push(new TableResponsive(table));
+        },
+      );
+    },
   };
-  $.extend(TableResponsive, {
-    tables: []
-  });
-  $.extend(TableResponsive.prototype, {
-    eventhandlerEvaluateColumnVisibility(e) {
-      const pegged = parseInt(this.$link.data('pegged'), 10);
-      const hiddenLength = this.$headers.filter('.priority-medium:hidden, .priority-low:hidden').length;
-
-      if (hiddenLength > 0) {
-        this.$link.show();
-        this.$link[0].textContent = this.showText;
-      }
 
-      if (!pegged && hiddenLength === 0) {
-        this.$link.hide();
-        this.$link[0].textContent = this.hideText;
-      }
+  /**
+   * Extend the TableResponsive function with a list of managed tables.
+   */
+  $.extend(
+    TableResponsive,
+    /** @lends Drupal.TableResponsive */ {
+      /**
+       * Store all created instances.
+       *
+       * @type {Array.<Drupal.TableResponsive>}
+       */
+      tables: [],
     },
+  );
 
-    eventhandlerToggleColumns(e) {
-      e.preventDefault();
-      const self = this;
-      const $hiddenHeaders = this.$headers.filter('.priority-medium:hidden, .priority-low:hidden');
-      this.$revealedCells = this.$revealedCells || $();
+  /**
+   * Associates an action link with the table that will show hidden columns.
+   *
+   * Columns are assumed to be hidden if their header has the class priority-low
+   * or priority-medium.
+   */
+  $.extend(
+    TableResponsive.prototype,
+    /** @lends Drupal.TableResponsive# */ {
+      /**
+       * @param {jQuery.Event} e
+       *   The event triggered.
+       */
+      eventhandlerEvaluateColumnVisibility(e) {
+        const pegged = parseInt(this.$link.data('pegged'), 10);
+        const hiddenLength = this.$headers.filter(
+          '.priority-medium:hidden, .priority-low:hidden',
+        ).length;
+        // If the table has hidden columns, associate an action link with the
+        // table to show the columns.
+        if (hiddenLength > 0) {
+          this.$link.show();
+          this.$link[0].textContent = this.showText;
+        }
+        // When the toggle is pegged, its presence is maintained because the user
+        // has interacted with it. This is necessary to keep the link visible if
+        // the user adjusts screen size and changes the visibility of columns.
+        if (!pegged && hiddenLength === 0) {
+          this.$link.hide();
+          this.$link[0].textContent = this.hideText;
+        }
+      },
 
-      if ($hiddenHeaders.length > 0) {
-        $hiddenHeaders.each(function (index, element) {
-          const $header = $(this);
-          const position = $header.prevAll('th').length;
-          self.$table.find('tbody tr').each(function () {
-            const $cells = $(this).find('td').eq(position);
-            $cells.show();
-            self.$revealedCells = $().add(self.$revealedCells).add($cells);
+      /**
+       * Toggle the visibility of columns based on their priority.
+       *
+       * Columns are classed with either 'priority-low' or 'priority-medium'.
+       *
+       * @param {jQuery.Event} e
+       *   The event triggered.
+       */
+      eventhandlerToggleColumns(e) {
+        e.preventDefault();
+        const self = this;
+        const $hiddenHeaders = this.$headers.filter(
+          '.priority-medium:hidden, .priority-low:hidden',
+        );
+        this.$revealedCells = this.$revealedCells || $();
+        // Reveal hidden columns.
+        if ($hiddenHeaders.length > 0) {
+          $hiddenHeaders.each(function (index, element) {
+            const $header = $(this);
+            const position = $header.prevAll('th').length;
+            self.$table.find('tbody tr').each(function () {
+              const $cells = $(this).find('td').eq(position);
+              $cells.show();
+              // Keep track of the revealed cells, so they can be hidden later.
+              self.$revealedCells = $().add(self.$revealedCells).add($cells);
+            });
+            $header.show();
+            // Keep track of the revealed headers, so they can be hidden later.
+            self.$revealedCells = $().add(self.$revealedCells).add($header);
           });
-          $header.show();
-          self.$revealedCells = $().add(self.$revealedCells).add($header);
-        });
-        this.$link[0].textContent = this.hideText;
-        this.$link.data('pegged', 1);
-      } else {
-        this.$revealedCells.hide();
-        this.$revealedCells.each(function (index, element) {
-          const $cell = $(this);
-          const properties = $cell.attr('style').split(';');
-          const newProps = [];
-          const match = /^display\s*:\s*none$/;
-
-          for (let i = 0; i < properties.length; i++) {
-            const prop = properties[i];
-            prop.trim();
-            const isDisplayNone = match.exec(prop);
-
-            if (isDisplayNone) {
-              continue;
+          this.$link[0].textContent = this.hideText;
+          this.$link.data('pegged', 1);
+        }
+        // Hide revealed columns.
+        else {
+          this.$revealedCells.hide();
+          // Strip the 'display:none' declaration from the style attributes of
+          // the table cells that .hide() added.
+          this.$revealedCells.each(function (index, element) {
+            const $cell = $(this);
+            const properties = $cell.attr('style').split(';');
+            const newProps = [];
+            // The hide method adds display none to the element. The element
+            // should be returned to the same state it was in before the columns
+            // were revealed, so it is necessary to remove the display none value
+            // from the style attribute.
+            const match = /^display\s*:\s*none$/;
+            for (let i = 0; i < properties.length; i++) {
+              const prop = properties[i];
+              prop.trim();
+              // Find the display:none property and remove it.
+              const isDisplayNone = match.exec(prop);
+              if (isDisplayNone) {
+                continue;
+              }
+              newProps.push(prop);
             }
+            // Return the rest of the style attribute values to the element.
+            $cell.attr('style', newProps.join(';'));
+          });
+          this.$link[0].textContent = this.showText;
+          this.$link.data('pegged', 0);
+          // Refresh the toggle link.
+          $(window).trigger('resize.tableresponsive');
+        }
+      },
+    },
+  );
 
-            newProps.push(prop);
-          }
-
-          $cell.attr('style', newProps.join(';'));
-        });
-        this.$link[0].textContent = this.showText;
-        this.$link.data('pegged', 0);
-        $(window).trigger('resize.tableresponsive');
-      }
-    }
-
-  });
+  // Make the TableResponsive object available in the Drupal namespace.
   Drupal.TableResponsive = TableResponsive;
-})(jQuery, Drupal, window);
\ No newline at end of file
+})(jQuery, Drupal, window);
diff --git a/core/misc/tableselect.es6.js b/core/misc/tableselect.es6.js
deleted file mode 100644
index 785198a5d9b7..000000000000
--- a/core/misc/tableselect.es6.js
+++ /dev/null
@@ -1,177 +0,0 @@
-/**
- * @file
- * Table select functionality.
- */
-
-(function ($, Drupal) {
-  /**
-   * Initialize tableSelects.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches tableSelect functionality.
-   */
-  Drupal.behaviors.tableSelect = {
-    attach(context, settings) {
-      // Select the inner-most table in case of nested tables.
-      once(
-        'table-select',
-        $(context).find('th.select-all').closest('table'),
-      ).forEach((table) => Drupal.tableSelect.call(table));
-    },
-  };
-
-  /**
-   * Callback used in {@link Drupal.behaviors.tableSelect}.
-   */
-  Drupal.tableSelect = function () {
-    // Do not add a "Select all" checkbox if there are no rows with checkboxes
-    // in the table.
-    if ($(this).find('td input[type="checkbox"]').length === 0) {
-      return;
-    }
-
-    // Keep track of the table, which checkbox is checked and alias the
-    // settings.
-    const table = this;
-    let checkboxes;
-    let lastChecked;
-    const $table = $(table);
-    const strings = {
-      selectAll: Drupal.t('Select all rows in this table'),
-      selectNone: Drupal.t('Deselect all rows in this table'),
-    };
-    const updateSelectAll = function (state) {
-      // Update table's select-all checkbox (and sticky header's if available).
-      $table
-        .prev('table.sticky-header')
-        .addBack()
-        .find('th.select-all input[type="checkbox"]')
-        .each(function () {
-          const $checkbox = $(this);
-          const stateChanged = $checkbox.prop('checked') !== state;
-
-          $checkbox.attr(
-            'title',
-            state ? strings.selectNone : strings.selectAll,
-          );
-
-          /**
-           * @checkbox {HTMLElement}
-           */
-          if (stateChanged) {
-            $checkbox.prop('checked', state).trigger('change');
-          }
-        });
-    };
-
-    // Find all <th> with class select-all, and insert the check all checkbox.
-    $table
-      .find('th.select-all')
-      .prepend($(Drupal.theme('checkbox')).attr('title', strings.selectAll))
-      .on('click', (event) => {
-        if ($(event.target).is('input[type="checkbox"]')) {
-          // Loop through all checkboxes and set their state to the select all
-          // checkbox' state.
-          checkboxes.each(function () {
-            const $checkbox = $(this);
-            const stateChanged =
-              $checkbox.prop('checked') !== event.target.checked;
-
-            /**
-             * @checkbox {HTMLElement}
-             */
-            if (stateChanged) {
-              $checkbox.prop('checked', event.target.checked).trigger('change');
-            }
-            // Either add or remove the selected class based on the state of the
-            // check all checkbox.
-
-            /**
-             * @checkbox {HTMLElement}
-             */
-            $checkbox.closest('tr').toggleClass('selected', this.checked);
-          });
-          // Update the title and the state of the check all box.
-          updateSelectAll(event.target.checked);
-        }
-      });
-
-    // For each of the checkboxes within the table that are not disabled.
-    checkboxes = $table
-      .find('td input[type="checkbox"]:enabled')
-      .on('click', function (e) {
-        // Either add or remove the selected class based on the state of the
-        // check all checkbox.
-
-        /**
-         * @this {HTMLElement}
-         */
-        $(this).closest('tr').toggleClass('selected', this.checked);
-
-        // If this is a shift click, we need to highlight everything in the
-        // range. Also make sure that we are actually checking checkboxes
-        // over a range and that a checkbox has been checked or unchecked before.
-        if (e.shiftKey && lastChecked && lastChecked !== e.target) {
-          // We use the checkbox's parent <tr> to do our range searching.
-          Drupal.tableSelectRange(
-            $(e.target).closest('tr')[0],
-            $(lastChecked).closest('tr')[0],
-            e.target.checked,
-          );
-        }
-
-        // If all checkboxes are checked, make sure the select-all one is checked
-        // too, otherwise keep unchecked.
-        updateSelectAll(
-          checkboxes.length === checkboxes.filter(':checked').length,
-        );
-
-        // Keep track of the last checked checkbox.
-        lastChecked = e.target;
-      });
-
-    // If all checkboxes are checked on page load, make sure the select-all one
-    // is checked too, otherwise keep unchecked.
-    updateSelectAll(checkboxes.length === checkboxes.filter(':checked').length);
-  };
-
-  /**
-   * @param {HTMLElement} from
-   *   The HTML element representing the "from" part of the range.
-   * @param {HTMLElement} to
-   *   The HTML element representing the "to" part of the range.
-   * @param {bool} state
-   *   The state to set on the range.
-   */
-  Drupal.tableSelectRange = function (from, to, state) {
-    // We determine the looping mode based on the order of from and to.
-    const mode =
-      from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
-
-    // Traverse through the sibling nodes.
-    for (let i = from[mode]; i; i = i[mode]) {
-      const $i = $(i);
-      // Make sure that we're only dealing with elements.
-      if (i.nodeType !== 1) {
-        continue;
-      }
-      // Either add or remove the selected class based on the state of the
-      // target checkbox.
-      $i.toggleClass('selected', state);
-      $i.find('input[type="checkbox"]').prop('checked', state);
-
-      if (to.nodeType) {
-        // If we are at the end of the range, stop.
-        if (i === to) {
-          break;
-        }
-      }
-      // A faster alternative to doing $(i).filter(to).length.
-      else if ($.filter(to, [i]).r.length) {
-        break;
-      }
-    }
-  };
-})(jQuery, Drupal);
diff --git a/core/misc/tableselect.js b/core/misc/tableselect.js
index 4d8712ae3088..785198a5d9b7 100644
--- a/core/misc/tableselect.js
+++ b/core/misc/tableselect.js
@@ -1,92 +1,177 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Table select functionality.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Initialize tableSelects.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches tableSelect functionality.
+   */
   Drupal.behaviors.tableSelect = {
     attach(context, settings) {
-      once('table-select', $(context).find('th.select-all').closest('table')).forEach(table => Drupal.tableSelect.call(table));
-    }
-
+      // Select the inner-most table in case of nested tables.
+      once(
+        'table-select',
+        $(context).find('th.select-all').closest('table'),
+      ).forEach((table) => Drupal.tableSelect.call(table));
+    },
   };
 
+  /**
+   * Callback used in {@link Drupal.behaviors.tableSelect}.
+   */
   Drupal.tableSelect = function () {
+    // Do not add a "Select all" checkbox if there are no rows with checkboxes
+    // in the table.
     if ($(this).find('td input[type="checkbox"]').length === 0) {
       return;
     }
 
+    // Keep track of the table, which checkbox is checked and alias the
+    // settings.
     const table = this;
     let checkboxes;
     let lastChecked;
     const $table = $(table);
     const strings = {
       selectAll: Drupal.t('Select all rows in this table'),
-      selectNone: Drupal.t('Deselect all rows in this table')
+      selectNone: Drupal.t('Deselect all rows in this table'),
     };
-
     const updateSelectAll = function (state) {
-      $table.prev('table.sticky-header').addBack().find('th.select-all input[type="checkbox"]').each(function () {
-        const $checkbox = $(this);
-        const stateChanged = $checkbox.prop('checked') !== state;
-        $checkbox.attr('title', state ? strings.selectNone : strings.selectAll);
-
-        if (stateChanged) {
-          $checkbox.prop('checked', state).trigger('change');
-        }
-      });
-    };
-
-    $table.find('th.select-all').prepend($(Drupal.theme('checkbox')).attr('title', strings.selectAll)).on('click', event => {
-      if ($(event.target).is('input[type="checkbox"]')) {
-        checkboxes.each(function () {
+      // Update table's select-all checkbox (and sticky header's if available).
+      $table
+        .prev('table.sticky-header')
+        .addBack()
+        .find('th.select-all input[type="checkbox"]')
+        .each(function () {
           const $checkbox = $(this);
-          const stateChanged = $checkbox.prop('checked') !== event.target.checked;
+          const stateChanged = $checkbox.prop('checked') !== state;
+
+          $checkbox.attr(
+            'title',
+            state ? strings.selectNone : strings.selectAll,
+          );
 
+          /**
+           * @checkbox {HTMLElement}
+           */
           if (stateChanged) {
-            $checkbox.prop('checked', event.target.checked).trigger('change');
+            $checkbox.prop('checked', state).trigger('change');
           }
-
-          $checkbox.closest('tr').toggleClass('selected', this.checked);
         });
-        updateSelectAll(event.target.checked);
-      }
-    });
-    checkboxes = $table.find('td input[type="checkbox"]:enabled').on('click', function (e) {
-      $(this).closest('tr').toggleClass('selected', this.checked);
+    };
 
-      if (e.shiftKey && lastChecked && lastChecked !== e.target) {
-        Drupal.tableSelectRange($(e.target).closest('tr')[0], $(lastChecked).closest('tr')[0], e.target.checked);
-      }
+    // Find all <th> with class select-all, and insert the check all checkbox.
+    $table
+      .find('th.select-all')
+      .prepend($(Drupal.theme('checkbox')).attr('title', strings.selectAll))
+      .on('click', (event) => {
+        if ($(event.target).is('input[type="checkbox"]')) {
+          // Loop through all checkboxes and set their state to the select all
+          // checkbox' state.
+          checkboxes.each(function () {
+            const $checkbox = $(this);
+            const stateChanged =
+              $checkbox.prop('checked') !== event.target.checked;
+
+            /**
+             * @checkbox {HTMLElement}
+             */
+            if (stateChanged) {
+              $checkbox.prop('checked', event.target.checked).trigger('change');
+            }
+            // Either add or remove the selected class based on the state of the
+            // check all checkbox.
+
+            /**
+             * @checkbox {HTMLElement}
+             */
+            $checkbox.closest('tr').toggleClass('selected', this.checked);
+          });
+          // Update the title and the state of the check all box.
+          updateSelectAll(event.target.checked);
+        }
+      });
+
+    // For each of the checkboxes within the table that are not disabled.
+    checkboxes = $table
+      .find('td input[type="checkbox"]:enabled')
+      .on('click', function (e) {
+        // Either add or remove the selected class based on the state of the
+        // check all checkbox.
+
+        /**
+         * @this {HTMLElement}
+         */
+        $(this).closest('tr').toggleClass('selected', this.checked);
+
+        // If this is a shift click, we need to highlight everything in the
+        // range. Also make sure that we are actually checking checkboxes
+        // over a range and that a checkbox has been checked or unchecked before.
+        if (e.shiftKey && lastChecked && lastChecked !== e.target) {
+          // We use the checkbox's parent <tr> to do our range searching.
+          Drupal.tableSelectRange(
+            $(e.target).closest('tr')[0],
+            $(lastChecked).closest('tr')[0],
+            e.target.checked,
+          );
+        }
+
+        // If all checkboxes are checked, make sure the select-all one is checked
+        // too, otherwise keep unchecked.
+        updateSelectAll(
+          checkboxes.length === checkboxes.filter(':checked').length,
+        );
 
-      updateSelectAll(checkboxes.length === checkboxes.filter(':checked').length);
-      lastChecked = e.target;
-    });
+        // Keep track of the last checked checkbox.
+        lastChecked = e.target;
+      });
+
+    // If all checkboxes are checked on page load, make sure the select-all one
+    // is checked too, otherwise keep unchecked.
     updateSelectAll(checkboxes.length === checkboxes.filter(':checked').length);
   };
 
+  /**
+   * @param {HTMLElement} from
+   *   The HTML element representing the "from" part of the range.
+   * @param {HTMLElement} to
+   *   The HTML element representing the "to" part of the range.
+   * @param {bool} state
+   *   The state to set on the range.
+   */
   Drupal.tableSelectRange = function (from, to, state) {
-    const mode = from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
+    // We determine the looping mode based on the order of from and to.
+    const mode =
+      from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
 
+    // Traverse through the sibling nodes.
     for (let i = from[mode]; i; i = i[mode]) {
       const $i = $(i);
-
+      // Make sure that we're only dealing with elements.
       if (i.nodeType !== 1) {
         continue;
       }
-
+      // Either add or remove the selected class based on the state of the
+      // target checkbox.
       $i.toggleClass('selected', state);
       $i.find('input[type="checkbox"]').prop('checked', state);
 
       if (to.nodeType) {
+        // If we are at the end of the range, stop.
         if (i === to) {
           break;
         }
-      } else if ($.filter(to, [i]).r.length) {
+      }
+      // A faster alternative to doing $(i).filter(to).length.
+      else if ($.filter(to, [i]).r.length) {
         break;
       }
     }
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/misc/timezone.es6.js b/core/misc/timezone.es6.js
deleted file mode 100644
index a8c1a5f7ac58..000000000000
--- a/core/misc/timezone.es6.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * @file
- * Timezone detection.
- */
-
-(function ($, Drupal) {
-  /**
-   * Set the client's system time zone as default values of form fields.
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.setTimezone = {
-    attach(context, settings) {
-      const timezone = once('timezone', '.timezone-detect', context);
-      if (timezone.length) {
-        const tz = new Intl.DateTimeFormat().resolvedOptions().timeZone;
-        // Ensure that the timezone value returned by the browser is supported
-        // by the server.
-        if (tz && $(timezone).find(`option[value="${tz}"]`).length) {
-          timezone.forEach((item) => {
-            item.value = tz;
-          });
-          return;
-        }
-
-        const dateString = Date();
-        // In some client environments, date strings include a time zone
-        // abbreviation, between 3 and 5 letters enclosed in parentheses,
-        // which can be interpreted by PHP.
-        const matches = dateString.match(/\(([A-Z]{3,5})\)/);
-        const abbreviation = matches ? matches[1] : 0;
-
-        // For all other client environments, the abbreviation is set to "0"
-        // and the current offset from UTC and daylight saving time status are
-        // used to guess the time zone.
-        const dateNow = new Date();
-        const offsetNow = dateNow.getTimezoneOffset() * -60;
-
-        // Use January 1 and July 1 as test dates for determining daylight
-        // saving time status by comparing their offsets.
-        const dateJan = new Date(dateNow.getFullYear(), 0, 1, 12, 0, 0, 0);
-        const dateJul = new Date(dateNow.getFullYear(), 6, 1, 12, 0, 0, 0);
-        const offsetJan = dateJan.getTimezoneOffset() * -60;
-        const offsetJul = dateJul.getTimezoneOffset() * -60;
-
-        let isDaylightSavingTime;
-        // If the offset from UTC is identical on January 1 and July 1,
-        // assume daylight saving time is not used in this time zone.
-        if (offsetJan === offsetJul) {
-          isDaylightSavingTime = '';
-        }
-        // If the maximum annual offset is equivalent to the current offset,
-        // assume daylight saving time is in effect.
-        else if (Math.max(offsetJan, offsetJul) === offsetNow) {
-          isDaylightSavingTime = 1;
-        }
-        // Otherwise, assume daylight saving time is not in effect.
-        else {
-          isDaylightSavingTime = 0;
-        }
-
-        // Submit request to the system/timezone callback and set the form
-        // field to the response time zone. The client date is passed to the
-        // callback for debugging purposes. Submit a synchronous request to
-        // avoid database errors associated with concurrent requests
-        // during install.
-        const path = `system/timezone/${abbreviation}/${offsetNow}/${isDaylightSavingTime}`;
-        $.ajax({
-          async: false,
-          url: Drupal.url(path),
-          data: { date: dateString },
-          dataType: 'json',
-          success(data) {
-            if (data) {
-              document.querySelectorAll('.timezone-detect').forEach((item) => {
-                item.value = data;
-              });
-            }
-          },
-        });
-      }
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/misc/timezone.js b/core/misc/timezone.js
index 053182bfbb4d..a8c1a5f7ac58 100644
--- a/core/misc/timezone.js
+++ b/core/misc/timezone.js
@@ -1,64 +1,84 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Timezone detection.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Set the client's system time zone as default values of form fields.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.setTimezone = {
     attach(context, settings) {
       const timezone = once('timezone', '.timezone-detect', context);
-
       if (timezone.length) {
         const tz = new Intl.DateTimeFormat().resolvedOptions().timeZone;
-
+        // Ensure that the timezone value returned by the browser is supported
+        // by the server.
         if (tz && $(timezone).find(`option[value="${tz}"]`).length) {
-          timezone.forEach(item => {
+          timezone.forEach((item) => {
             item.value = tz;
           });
           return;
         }
 
         const dateString = Date();
+        // In some client environments, date strings include a time zone
+        // abbreviation, between 3 and 5 letters enclosed in parentheses,
+        // which can be interpreted by PHP.
         const matches = dateString.match(/\(([A-Z]{3,5})\)/);
         const abbreviation = matches ? matches[1] : 0;
+
+        // For all other client environments, the abbreviation is set to "0"
+        // and the current offset from UTC and daylight saving time status are
+        // used to guess the time zone.
         const dateNow = new Date();
         const offsetNow = dateNow.getTimezoneOffset() * -60;
+
+        // Use January 1 and July 1 as test dates for determining daylight
+        // saving time status by comparing their offsets.
         const dateJan = new Date(dateNow.getFullYear(), 0, 1, 12, 0, 0, 0);
         const dateJul = new Date(dateNow.getFullYear(), 6, 1, 12, 0, 0, 0);
         const offsetJan = dateJan.getTimezoneOffset() * -60;
         const offsetJul = dateJul.getTimezoneOffset() * -60;
-        let isDaylightSavingTime;
 
+        let isDaylightSavingTime;
+        // If the offset from UTC is identical on January 1 and July 1,
+        // assume daylight saving time is not used in this time zone.
         if (offsetJan === offsetJul) {
           isDaylightSavingTime = '';
-        } else if (Math.max(offsetJan, offsetJul) === offsetNow) {
+        }
+        // If the maximum annual offset is equivalent to the current offset,
+        // assume daylight saving time is in effect.
+        else if (Math.max(offsetJan, offsetJul) === offsetNow) {
           isDaylightSavingTime = 1;
-        } else {
+        }
+        // Otherwise, assume daylight saving time is not in effect.
+        else {
           isDaylightSavingTime = 0;
         }
 
+        // Submit request to the system/timezone callback and set the form
+        // field to the response time zone. The client date is passed to the
+        // callback for debugging purposes. Submit a synchronous request to
+        // avoid database errors associated with concurrent requests
+        // during install.
         const path = `system/timezone/${abbreviation}/${offsetNow}/${isDaylightSavingTime}`;
         $.ajax({
           async: false,
           url: Drupal.url(path),
-          data: {
-            date: dateString
-          },
+          data: { date: dateString },
           dataType: 'json',
-
           success(data) {
             if (data) {
-              document.querySelectorAll('.timezone-detect').forEach(item => {
+              document.querySelectorAll('.timezone-detect').forEach((item) => {
                 item.value = data;
               });
             }
-          }
-
+          },
         });
       }
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/misc/touchevents-test.es6.js b/core/misc/touchevents-test.es6.js
deleted file mode 100644
index 8e7ab4831f85..000000000000
--- a/core/misc/touchevents-test.es6.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @file
- * A replacement for Modernizr touch events detection.
- */
-
-document.documentElement.classList.add(
-  'ontouchstart' in window ||
-    (window.DocumentTouch && document instanceof window.DocumentTouch)
-    ? 'touchevents'
-    : 'no-touchevents',
-);
diff --git a/core/misc/touchevents-test.js b/core/misc/touchevents-test.js
index 68efbdf9af81..8e7ab4831f85 100644
--- a/core/misc/touchevents-test.js
+++ b/core/misc/touchevents-test.js
@@ -1,8 +1,11 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A replacement for Modernizr touch events detection.
+ */
 
-document.documentElement.classList.add('ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch ? 'touchevents' : 'no-touchevents');
\ No newline at end of file
+document.documentElement.classList.add(
+  'ontouchstart' in window ||
+    (window.DocumentTouch && document instanceof window.DocumentTouch)
+    ? 'touchevents'
+    : 'no-touchevents',
+);
diff --git a/core/misc/vertical-tabs.es6.js b/core/misc/vertical-tabs.es6.js
deleted file mode 100644
index 85f200f5f809..000000000000
--- a/core/misc/vertical-tabs.es6.js
+++ /dev/null
@@ -1,300 +0,0 @@
-/**
- * @file
- * Define vertical tabs functionality.
- */
-
-/**
- * Triggers when form values inside a vertical tab changes.
- *
- * This is used to update the summary in vertical tabs in order to know what
- * are the important fields' values.
- *
- * @event summaryUpdated
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Show the parent vertical tab pane of a targeted page fragment.
-   *
-   * In order to make sure a targeted element inside a vertical tab pane is
-   * visible on a hash change or fragment link click, show all parent panes.
-   *
-   * @param {jQuery.Event} e
-   *   The event triggered.
-   * @param {jQuery} $target
-   *   The targeted node as a jQuery object.
-   */
-  const handleFragmentLinkClickOrHashChange = (e, $target) => {
-    $target.parents('.vertical-tabs__pane').each((index, pane) => {
-      $(pane).data('verticalTab').focus();
-    });
-  };
-
-  /**
-   * This script transforms a set of details into a stack of vertical tabs.
-   *
-   * Each tab may have a summary which can be updated by another
-   * script. For that to work, each details element has an associated
-   * 'verticalTabCallback' (with jQuery.data() attached to the details),
-   * which is called every time the user performs an update to a form
-   * element inside the tab pane.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behaviors for vertical tabs.
-   */
-  Drupal.behaviors.verticalTabs = {
-    attach(context) {
-      const width = drupalSettings.widthBreakpoint || 640;
-      const mq = `(max-width: ${width}px)`;
-
-      if (window.matchMedia(mq).matches) {
-        return;
-      }
-
-      /**
-       * Binds a listener to handle fragment link clicks and URL hash changes.
-       */
-      $(once('vertical-tabs-fragments', 'body')).on(
-        'formFragmentLinkClickOrHashChange.verticalTabs',
-        handleFragmentLinkClickOrHashChange,
-      );
-
-      once('vertical-tabs', '[data-vertical-tabs-panes]', context).forEach(
-        (verticalTab) => {
-          const $this = $(verticalTab).addClass('vertical-tabs__panes');
-          const focusID = $this.find(':hidden.vertical-tabs__active-tab')[0]
-            .value;
-          let tabFocus;
-
-          // Check if there are some details that can be converted to
-          // vertical-tabs.
-          const $details = $this.find('> details');
-          if ($details.length === 0) {
-            return;
-          }
-
-          // Create the tab column.
-          const tabList = $('<ul class="vertical-tabs__menu"></ul>');
-          $this
-            .wrap('<div class="vertical-tabs clearfix"></div>')
-            .before(tabList);
-
-          // Transform each details into a tab.
-          $details.each(function () {
-            const $that = $(this);
-            const $summary = $that.find('> summary');
-            const verticalTab = new Drupal.verticalTab({
-              title: $summary.length ? $summary[0].textContent : '',
-              details: $that,
-            });
-            tabList.append(verticalTab.item);
-            $that
-              .removeClass('collapsed')
-              .removeAttr('open')
-              .addClass('vertical-tabs__pane')
-              .data('verticalTab', verticalTab);
-            if (this.id === focusID) {
-              tabFocus = $that;
-            }
-          });
-
-          $(tabList).find('> li').eq(0).addClass('first');
-          $(tabList).find('> li').eq(-1).addClass('last');
-
-          if (!tabFocus) {
-            // If the current URL has a fragment and one of the tabs contains an
-            // element that matches the URL fragment, activate that tab.
-            const $locationHash = $this.find(window.location.hash);
-            if (window.location.hash && $locationHash.length) {
-              tabFocus = $locationHash.closest('.vertical-tabs__pane');
-            } else {
-              tabFocus = $this.find('> .vertical-tabs__pane').eq(0);
-            }
-          }
-          if (tabFocus.length) {
-            tabFocus.data('verticalTab').focus();
-          }
-        },
-      );
-    },
-  };
-
-  /**
-   * The vertical tab object represents a single tab within a tab group.
-   *
-   * @constructor
-   *
-   * @param {object} settings
-   *   Settings object.
-   * @param {string} settings.title
-   *   The name of the tab.
-   * @param {jQuery} settings.details
-   *   The jQuery object of the details element that is the tab pane.
-   *
-   * @fires event:summaryUpdated
-   *
-   * @listens event:summaryUpdated
-   */
-  Drupal.verticalTab = function (settings) {
-    const self = this;
-    $.extend(this, settings, Drupal.theme('verticalTab', settings));
-
-    this.link.attr('href', `#${settings.details.attr('id')}`);
-
-    this.link.on('click', (e) => {
-      e.preventDefault();
-      self.focus();
-    });
-
-    // Keyboard events added:
-    // Pressing the Enter key will open the tab pane.
-    this.link.on('keydown', (event) => {
-      if (event.keyCode === 13) {
-        event.preventDefault();
-        self.focus();
-        // Set focus on the first input field of the visible details/tab pane.
-        $('.vertical-tabs__pane :input:visible:enabled').eq(0).trigger('focus');
-      }
-    });
-
-    this.details
-      .on('summaryUpdated', () => {
-        self.updateSummary();
-      })
-      .trigger('summaryUpdated');
-  };
-
-  Drupal.verticalTab.prototype = {
-    /**
-     * Displays the tab's content pane.
-     */
-    focus() {
-      this.details
-        .siblings('.vertical-tabs__pane')
-        .each(function () {
-          const tab = $(this).data('verticalTab');
-          tab.details.hide();
-          tab.details.removeAttr('open');
-          tab.item.removeClass('is-selected');
-        })
-        .end()
-        .show()
-        .siblings(':hidden.vertical-tabs__active-tab')[0].value =
-        this.details.attr('id');
-      this.details.attr('open', true);
-      this.item.addClass('is-selected');
-      // Mark the active tab for screen readers.
-      $('#active-vertical-tab').remove();
-      this.link.append(
-        `<span id="active-vertical-tab" class="visually-hidden">${Drupal.t(
-          '(active tab)',
-        )}</span>`,
-      );
-    },
-
-    /**
-     * Updates the tab's summary.
-     */
-    updateSummary() {
-      this.summary.html(this.details.drupalGetSummary());
-    },
-
-    /**
-     * Shows a vertical tab pane.
-     *
-     * @return {Drupal.verticalTab}
-     *   The verticalTab instance.
-     */
-    tabShow() {
-      // Display the tab.
-      this.item.show();
-      // Show the vertical tabs.
-      this.item.closest('.js-form-type-vertical-tabs').show();
-      // Update .first marker for items. We need recurse from parent to retain
-      // the actual DOM element order as jQuery implements sortOrder, but not
-      // as public method.
-      this.item
-        .parent()
-        .children('.vertical-tabs__menu-item')
-        .removeClass('first')
-        .filter(':visible')
-        .eq(0)
-        .addClass('first');
-      // Display the details element.
-      this.details.removeClass('vertical-tab--hidden').show();
-      // Focus this tab.
-      this.focus();
-      return this;
-    },
-
-    /**
-     * Hides a vertical tab pane.
-     *
-     * @return {Drupal.verticalTab}
-     *   The verticalTab instance.
-     */
-    tabHide() {
-      // Hide this tab.
-      this.item.hide();
-      // Update .first marker for items. We need recurse from parent to retain
-      // the actual DOM element order as jQuery implements sortOrder, but not
-      // as public method.
-      this.item
-        .parent()
-        .children('.vertical-tabs__menu-item')
-        .removeClass('first')
-        .filter(':visible')
-        .eq(0)
-        .addClass('first');
-      // Hide the details element.
-      this.details.addClass('vertical-tab--hidden').hide().removeAttr('open');
-      // Focus the first visible tab (if there is one).
-      const $firstTab = this.details
-        .siblings('.vertical-tabs__pane:not(.vertical-tab--hidden)')
-        .eq(0);
-      if ($firstTab.length) {
-        $firstTab.data('verticalTab').focus();
-      }
-      // Hide the vertical tabs (if no tabs remain).
-      else {
-        this.item.closest('.js-form-type-vertical-tabs').hide();
-      }
-      return this;
-    },
-  };
-
-  /**
-   * Theme function for a vertical tab.
-   *
-   * @param {object} settings
-   *   An object with the following keys:
-   * @param {string} settings.title
-   *   The name of the tab.
-   *
-   * @return {object}
-   *   This function has to return an object with at least these keys:
-   *   - item: The root tab jQuery element
-   *   - link: The anchor tag that acts as the clickable area of the tab
-   *       (jQuery version)
-   *   - summary: The jQuery element that contains the tab summary
-   */
-  Drupal.theme.verticalTab = function (settings) {
-    const tab = {};
-    tab.title = $('<strong class="vertical-tabs__menu-item-title"></strong>');
-    tab.title[0].textContent = settings.title;
-    tab.item = $(
-      '<li class="vertical-tabs__menu-item" tabindex="-1"></li>',
-    ).append(
-      (tab.link = $('<a href="#"></a>')
-        .append(tab.title)
-        .append(
-          (tab.summary = $(
-            '<span class="vertical-tabs__menu-item-summary"></span>',
-          )),
-        )),
-    );
-    return tab;
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/misc/vertical-tabs.js b/core/misc/vertical-tabs.js
index 369fbfac0e1c..85f200f5f809 100644
--- a/core/misc/vertical-tabs.js
+++ b/core/misc/vertical-tabs.js
@@ -1,17 +1,49 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Define vertical tabs functionality.
+ */
+
+/**
+ * Triggers when form values inside a vertical tab changes.
+ *
+ * This is used to update the summary in vertical tabs in order to know what
+ * are the important fields' values.
+ *
+ * @event summaryUpdated
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * Show the parent vertical tab pane of a targeted page fragment.
+   *
+   * In order to make sure a targeted element inside a vertical tab pane is
+   * visible on a hash change or fragment link click, show all parent panes.
+   *
+   * @param {jQuery.Event} e
+   *   The event triggered.
+   * @param {jQuery} $target
+   *   The targeted node as a jQuery object.
+   */
   const handleFragmentLinkClickOrHashChange = (e, $target) => {
     $target.parents('.vertical-tabs__pane').each((index, pane) => {
       $(pane).data('verticalTab').focus();
     });
   };
 
+  /**
+   * This script transforms a set of details into a stack of vertical tabs.
+   *
+   * Each tab may have a summary which can be updated by another
+   * script. For that to work, each details element has an associated
+   * 'verticalTabCallback' (with jQuery.data() attached to the details),
+   * which is called every time the user performs an update to a form
+   * element inside the tab pane.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behaviors for vertical tabs.
+   */
   Drupal.behaviors.verticalTabs = {
     attach(context) {
       const width = drupalSettings.widthBreakpoint || 640;
@@ -21,123 +53,248 @@
         return;
       }
 
-      $(once('vertical-tabs-fragments', 'body')).on('formFragmentLinkClickOrHashChange.verticalTabs', handleFragmentLinkClickOrHashChange);
-      once('vertical-tabs', '[data-vertical-tabs-panes]', context).forEach(verticalTab => {
-        const $this = $(verticalTab).addClass('vertical-tabs__panes');
-        const focusID = $this.find(':hidden.vertical-tabs__active-tab')[0].value;
-        let tabFocus;
-        const $details = $this.find('> details');
-
-        if ($details.length === 0) {
-          return;
-        }
-
-        const tabList = $('<ul class="vertical-tabs__menu"></ul>');
-        $this.wrap('<div class="vertical-tabs clearfix"></div>').before(tabList);
-        $details.each(function () {
-          const $that = $(this);
-          const $summary = $that.find('> summary');
-          const verticalTab = new Drupal.verticalTab({
-            title: $summary.length ? $summary[0].textContent : '',
-            details: $that
-          });
-          tabList.append(verticalTab.item);
-          $that.removeClass('collapsed').removeAttr('open').addClass('vertical-tabs__pane').data('verticalTab', verticalTab);
+      /**
+       * Binds a listener to handle fragment link clicks and URL hash changes.
+       */
+      $(once('vertical-tabs-fragments', 'body')).on(
+        'formFragmentLinkClickOrHashChange.verticalTabs',
+        handleFragmentLinkClickOrHashChange,
+      );
 
-          if (this.id === focusID) {
-            tabFocus = $that;
+      once('vertical-tabs', '[data-vertical-tabs-panes]', context).forEach(
+        (verticalTab) => {
+          const $this = $(verticalTab).addClass('vertical-tabs__panes');
+          const focusID = $this.find(':hidden.vertical-tabs__active-tab')[0]
+            .value;
+          let tabFocus;
+
+          // Check if there are some details that can be converted to
+          // vertical-tabs.
+          const $details = $this.find('> details');
+          if ($details.length === 0) {
+            return;
           }
-        });
-        $(tabList).find('> li').eq(0).addClass('first');
-        $(tabList).find('> li').eq(-1).addClass('last');
 
-        if (!tabFocus) {
-          const $locationHash = $this.find(window.location.hash);
+          // Create the tab column.
+          const tabList = $('<ul class="vertical-tabs__menu"></ul>');
+          $this
+            .wrap('<div class="vertical-tabs clearfix"></div>')
+            .before(tabList);
 
-          if (window.location.hash && $locationHash.length) {
-            tabFocus = $locationHash.closest('.vertical-tabs__pane');
-          } else {
-            tabFocus = $this.find('> .vertical-tabs__pane').eq(0);
-          }
-        }
+          // Transform each details into a tab.
+          $details.each(function () {
+            const $that = $(this);
+            const $summary = $that.find('> summary');
+            const verticalTab = new Drupal.verticalTab({
+              title: $summary.length ? $summary[0].textContent : '',
+              details: $that,
+            });
+            tabList.append(verticalTab.item);
+            $that
+              .removeClass('collapsed')
+              .removeAttr('open')
+              .addClass('vertical-tabs__pane')
+              .data('verticalTab', verticalTab);
+            if (this.id === focusID) {
+              tabFocus = $that;
+            }
+          });
 
-        if (tabFocus.length) {
-          tabFocus.data('verticalTab').focus();
-        }
-      });
-    }
+          $(tabList).find('> li').eq(0).addClass('first');
+          $(tabList).find('> li').eq(-1).addClass('last');
 
+          if (!tabFocus) {
+            // If the current URL has a fragment and one of the tabs contains an
+            // element that matches the URL fragment, activate that tab.
+            const $locationHash = $this.find(window.location.hash);
+            if (window.location.hash && $locationHash.length) {
+              tabFocus = $locationHash.closest('.vertical-tabs__pane');
+            } else {
+              tabFocus = $this.find('> .vertical-tabs__pane').eq(0);
+            }
+          }
+          if (tabFocus.length) {
+            tabFocus.data('verticalTab').focus();
+          }
+        },
+      );
+    },
   };
 
+  /**
+   * The vertical tab object represents a single tab within a tab group.
+   *
+   * @constructor
+   *
+   * @param {object} settings
+   *   Settings object.
+   * @param {string} settings.title
+   *   The name of the tab.
+   * @param {jQuery} settings.details
+   *   The jQuery object of the details element that is the tab pane.
+   *
+   * @fires event:summaryUpdated
+   *
+   * @listens event:summaryUpdated
+   */
   Drupal.verticalTab = function (settings) {
     const self = this;
     $.extend(this, settings, Drupal.theme('verticalTab', settings));
+
     this.link.attr('href', `#${settings.details.attr('id')}`);
-    this.link.on('click', e => {
+
+    this.link.on('click', (e) => {
       e.preventDefault();
       self.focus();
     });
-    this.link.on('keydown', event => {
+
+    // Keyboard events added:
+    // Pressing the Enter key will open the tab pane.
+    this.link.on('keydown', (event) => {
       if (event.keyCode === 13) {
         event.preventDefault();
         self.focus();
+        // Set focus on the first input field of the visible details/tab pane.
         $('.vertical-tabs__pane :input:visible:enabled').eq(0).trigger('focus');
       }
     });
-    this.details.on('summaryUpdated', () => {
-      self.updateSummary();
-    }).trigger('summaryUpdated');
+
+    this.details
+      .on('summaryUpdated', () => {
+        self.updateSummary();
+      })
+      .trigger('summaryUpdated');
   };
 
   Drupal.verticalTab.prototype = {
+    /**
+     * Displays the tab's content pane.
+     */
     focus() {
-      this.details.siblings('.vertical-tabs__pane').each(function () {
-        const tab = $(this).data('verticalTab');
-        tab.details.hide();
-        tab.details.removeAttr('open');
-        tab.item.removeClass('is-selected');
-      }).end().show().siblings(':hidden.vertical-tabs__active-tab')[0].value = this.details.attr('id');
+      this.details
+        .siblings('.vertical-tabs__pane')
+        .each(function () {
+          const tab = $(this).data('verticalTab');
+          tab.details.hide();
+          tab.details.removeAttr('open');
+          tab.item.removeClass('is-selected');
+        })
+        .end()
+        .show()
+        .siblings(':hidden.vertical-tabs__active-tab')[0].value =
+        this.details.attr('id');
       this.details.attr('open', true);
       this.item.addClass('is-selected');
+      // Mark the active tab for screen readers.
       $('#active-vertical-tab').remove();
-      this.link.append(`<span id="active-vertical-tab" class="visually-hidden">${Drupal.t('(active tab)')}</span>`);
+      this.link.append(
+        `<span id="active-vertical-tab" class="visually-hidden">${Drupal.t(
+          '(active tab)',
+        )}</span>`,
+      );
     },
 
+    /**
+     * Updates the tab's summary.
+     */
     updateSummary() {
       this.summary.html(this.details.drupalGetSummary());
     },
 
+    /**
+     * Shows a vertical tab pane.
+     *
+     * @return {Drupal.verticalTab}
+     *   The verticalTab instance.
+     */
     tabShow() {
+      // Display the tab.
       this.item.show();
+      // Show the vertical tabs.
       this.item.closest('.js-form-type-vertical-tabs').show();
-      this.item.parent().children('.vertical-tabs__menu-item').removeClass('first').filter(':visible').eq(0).addClass('first');
+      // Update .first marker for items. We need recurse from parent to retain
+      // the actual DOM element order as jQuery implements sortOrder, but not
+      // as public method.
+      this.item
+        .parent()
+        .children('.vertical-tabs__menu-item')
+        .removeClass('first')
+        .filter(':visible')
+        .eq(0)
+        .addClass('first');
+      // Display the details element.
       this.details.removeClass('vertical-tab--hidden').show();
+      // Focus this tab.
       this.focus();
       return this;
     },
 
+    /**
+     * Hides a vertical tab pane.
+     *
+     * @return {Drupal.verticalTab}
+     *   The verticalTab instance.
+     */
     tabHide() {
+      // Hide this tab.
       this.item.hide();
-      this.item.parent().children('.vertical-tabs__menu-item').removeClass('first').filter(':visible').eq(0).addClass('first');
+      // Update .first marker for items. We need recurse from parent to retain
+      // the actual DOM element order as jQuery implements sortOrder, but not
+      // as public method.
+      this.item
+        .parent()
+        .children('.vertical-tabs__menu-item')
+        .removeClass('first')
+        .filter(':visible')
+        .eq(0)
+        .addClass('first');
+      // Hide the details element.
       this.details.addClass('vertical-tab--hidden').hide().removeAttr('open');
-      const $firstTab = this.details.siblings('.vertical-tabs__pane:not(.vertical-tab--hidden)').eq(0);
-
+      // Focus the first visible tab (if there is one).
+      const $firstTab = this.details
+        .siblings('.vertical-tabs__pane:not(.vertical-tab--hidden)')
+        .eq(0);
       if ($firstTab.length) {
         $firstTab.data('verticalTab').focus();
-      } else {
+      }
+      // Hide the vertical tabs (if no tabs remain).
+      else {
         this.item.closest('.js-form-type-vertical-tabs').hide();
       }
-
       return this;
-    }
-
+    },
   };
 
+  /**
+   * Theme function for a vertical tab.
+   *
+   * @param {object} settings
+   *   An object with the following keys:
+   * @param {string} settings.title
+   *   The name of the tab.
+   *
+   * @return {object}
+   *   This function has to return an object with at least these keys:
+   *   - item: The root tab jQuery element
+   *   - link: The anchor tag that acts as the clickable area of the tab
+   *       (jQuery version)
+   *   - summary: The jQuery element that contains the tab summary
+   */
   Drupal.theme.verticalTab = function (settings) {
     const tab = {};
     tab.title = $('<strong class="vertical-tabs__menu-item-title"></strong>');
     tab.title[0].textContent = settings.title;
-    tab.item = $('<li class="vertical-tabs__menu-item" tabindex="-1"></li>').append(tab.link = $('<a href="#"></a>').append(tab.title).append(tab.summary = $('<span class="vertical-tabs__menu-item-summary"></span>')));
+    tab.item = $(
+      '<li class="vertical-tabs__menu-item" tabindex="-1"></li>',
+    ).append(
+      (tab.link = $('<a href="#"></a>')
+        .append(tab.title)
+        .append(
+          (tab.summary = $(
+            '<span class="vertical-tabs__menu-item-summary"></span>',
+          )),
+        )),
+    );
     return tab;
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/big_pipe/js/big_pipe.es6.js b/core/modules/big_pipe/js/big_pipe.es6.js
deleted file mode 100644
index 097a036472d8..000000000000
--- a/core/modules/big_pipe/js/big_pipe.es6.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * @file
- * Renders BigPipe placeholders using Drupal's Ajax system.
- */
-
-(function (Drupal, drupalSettings) {
-  /**
-   * Maps textContent of <script type="application/vnd.drupal-ajax"> to an AJAX response.
-   *
-   * @param {string} content
-   *   The text content of a <script type="application/vnd.drupal-ajax"> DOM node.
-   * @return {Array|boolean}
-   *   The parsed Ajax response containing an array of Ajax commands, or false in
-   *   case the DOM node hasn't fully arrived yet.
-   */
-  function mapTextContentToAjaxResponse(content) {
-    if (content === '') {
-      return false;
-    }
-
-    try {
-      return JSON.parse(content);
-    } catch (e) {
-      return false;
-    }
-  }
-
-  /**
-   * Executes Ajax commands in <script type="application/vnd.drupal-ajax"> tag.
-   *
-   * These Ajax commands replace placeholders with HTML and load missing CSS/JS.
-   *
-   * @param {HTMLScriptElement} placeholderReplacement
-   *   Script tag created by BigPipe.
-   */
-  function bigPipeProcessPlaceholderReplacement(placeholderReplacement) {
-    const placeholderId = placeholderReplacement.getAttribute(
-      'data-big-pipe-replacement-for-placeholder-with-id',
-    );
-    const content = placeholderReplacement.textContent.trim();
-    // Ignore any placeholders that are not in the known placeholder list. Used
-    // to avoid someone trying to XSS the site via the placeholdering mechanism.
-    if (
-      typeof drupalSettings.bigPipePlaceholderIds[placeholderId] !== 'undefined'
-    ) {
-      const response = mapTextContentToAjaxResponse(content);
-      // If we try to parse the content too early (when the JSON containing Ajax
-      // commands is still arriving), textContent will be empty or incomplete.
-      if (response === false) {
-        /**
-         * Mark as unprocessed so this will be retried later.
-         * @see bigPipeProcessDocument()
-         */
-        once.remove('big-pipe', placeholderReplacement);
-      } else {
-        // Create a Drupal.Ajax object without associating an element, a
-        // progress indicator or a URL.
-        const ajaxObject = Drupal.ajax({
-          url: '',
-          base: false,
-          element: false,
-          progress: false,
-        });
-        // Then, simulate an AJAX response having arrived, and let the Ajax
-        // system handle it.
-        ajaxObject.success(response, 'success');
-      }
-    }
-  }
-
-  // The frequency with which to check for newly arrived BigPipe placeholders.
-  // Hence 50 ms means we check 20 times per second. Setting this to 100 ms or
-  // more would cause the user to see content appear noticeably slower.
-  const interval = drupalSettings.bigPipeInterval || 50;
-
-  // The internal ID to contain the watcher service.
-  let timeoutID;
-
-  /**
-   * Processes a streamed HTML document receiving placeholder replacements.
-   *
-   * @param {HTMLDocument} context
-   *   The HTML document containing <script type="application/vnd.drupal-ajax">
-   *   tags generated by BigPipe.
-   *
-   * @return {bool}
-   *   Returns true when processing has been finished and a stop signal has been
-   *   found.
-   */
-  function bigPipeProcessDocument(context) {
-    // Make sure we have BigPipe-related scripts before processing further.
-    if (!context.querySelector('script[data-big-pipe-event="start"]')) {
-      return false;
-    }
-
-    // Attach Drupal behaviors early, if possible.
-    once('big-pipe-early-behaviors', 'body', context).forEach((el) => {
-      Drupal.attachBehaviors(el);
-    });
-
-    once(
-      'big-pipe',
-      'script[data-big-pipe-replacement-for-placeholder-with-id]',
-      context,
-    ).forEach(bigPipeProcessPlaceholderReplacement);
-
-    // If we see the stop signal, clear the timeout: all placeholder
-    // replacements are guaranteed to be received and processed.
-    if (context.querySelector('script[data-big-pipe-event="stop"]')) {
-      if (timeoutID) {
-        clearTimeout(timeoutID);
-      }
-      return true;
-    }
-
-    return false;
-  }
-
-  function bigPipeProcess() {
-    timeoutID = setTimeout(() => {
-      if (!bigPipeProcessDocument(document)) {
-        bigPipeProcess();
-      }
-    }, interval);
-  }
-
-  bigPipeProcess();
-
-  // If something goes wrong, make sure everything is cleaned up and has had a
-  // chance to be processed with everything loaded.
-  window.addEventListener('load', () => {
-    if (timeoutID) {
-      clearTimeout(timeoutID);
-    }
-    bigPipeProcessDocument(document);
-  });
-})(Drupal, drupalSettings);
diff --git a/core/modules/big_pipe/js/big_pipe.js b/core/modules/big_pipe/js/big_pipe.js
index e9e8497bf09f..097a036472d8 100644
--- a/core/modules/big_pipe/js/big_pipe.js
+++ b/core/modules/big_pipe/js/big_pipe.js
@@ -1,11 +1,18 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Renders BigPipe placeholders using Drupal's Ajax system.
+ */
 
 (function (Drupal, drupalSettings) {
+  /**
+   * Maps textContent of <script type="application/vnd.drupal-ajax"> to an AJAX response.
+   *
+   * @param {string} content
+   *   The text content of a <script type="application/vnd.drupal-ajax"> DOM node.
+   * @return {Array|boolean}
+   *   The parsed Ajax response containing an array of Ajax commands, or false in
+   *   case the DOM node hasn't fully arrived yet.
+   */
   function mapTextContentToAjaxResponse(content) {
     if (content === '') {
       return false;
@@ -18,45 +25,91 @@
     }
   }
 
+  /**
+   * Executes Ajax commands in <script type="application/vnd.drupal-ajax"> tag.
+   *
+   * These Ajax commands replace placeholders with HTML and load missing CSS/JS.
+   *
+   * @param {HTMLScriptElement} placeholderReplacement
+   *   Script tag created by BigPipe.
+   */
   function bigPipeProcessPlaceholderReplacement(placeholderReplacement) {
-    const placeholderId = placeholderReplacement.getAttribute('data-big-pipe-replacement-for-placeholder-with-id');
+    const placeholderId = placeholderReplacement.getAttribute(
+      'data-big-pipe-replacement-for-placeholder-with-id',
+    );
     const content = placeholderReplacement.textContent.trim();
-
-    if (typeof drupalSettings.bigPipePlaceholderIds[placeholderId] !== 'undefined') {
+    // Ignore any placeholders that are not in the known placeholder list. Used
+    // to avoid someone trying to XSS the site via the placeholdering mechanism.
+    if (
+      typeof drupalSettings.bigPipePlaceholderIds[placeholderId] !== 'undefined'
+    ) {
       const response = mapTextContentToAjaxResponse(content);
-
+      // If we try to parse the content too early (when the JSON containing Ajax
+      // commands is still arriving), textContent will be empty or incomplete.
       if (response === false) {
+        /**
+         * Mark as unprocessed so this will be retried later.
+         * @see bigPipeProcessDocument()
+         */
         once.remove('big-pipe', placeholderReplacement);
       } else {
+        // Create a Drupal.Ajax object without associating an element, a
+        // progress indicator or a URL.
         const ajaxObject = Drupal.ajax({
           url: '',
           base: false,
           element: false,
-          progress: false
+          progress: false,
         });
+        // Then, simulate an AJAX response having arrived, and let the Ajax
+        // system handle it.
         ajaxObject.success(response, 'success');
       }
     }
   }
 
+  // The frequency with which to check for newly arrived BigPipe placeholders.
+  // Hence 50 ms means we check 20 times per second. Setting this to 100 ms or
+  // more would cause the user to see content appear noticeably slower.
   const interval = drupalSettings.bigPipeInterval || 50;
+
+  // The internal ID to contain the watcher service.
   let timeoutID;
 
+  /**
+   * Processes a streamed HTML document receiving placeholder replacements.
+   *
+   * @param {HTMLDocument} context
+   *   The HTML document containing <script type="application/vnd.drupal-ajax">
+   *   tags generated by BigPipe.
+   *
+   * @return {bool}
+   *   Returns true when processing has been finished and a stop signal has been
+   *   found.
+   */
   function bigPipeProcessDocument(context) {
+    // Make sure we have BigPipe-related scripts before processing further.
     if (!context.querySelector('script[data-big-pipe-event="start"]')) {
       return false;
     }
 
-    once('big-pipe-early-behaviors', 'body', context).forEach(el => {
+    // Attach Drupal behaviors early, if possible.
+    once('big-pipe-early-behaviors', 'body', context).forEach((el) => {
       Drupal.attachBehaviors(el);
     });
-    once('big-pipe', 'script[data-big-pipe-replacement-for-placeholder-with-id]', context).forEach(bigPipeProcessPlaceholderReplacement);
 
+    once(
+      'big-pipe',
+      'script[data-big-pipe-replacement-for-placeholder-with-id]',
+      context,
+    ).forEach(bigPipeProcessPlaceholderReplacement);
+
+    // If we see the stop signal, clear the timeout: all placeholder
+    // replacements are guaranteed to be received and processed.
     if (context.querySelector('script[data-big-pipe-event="stop"]')) {
       if (timeoutID) {
         clearTimeout(timeoutID);
       }
-
       return true;
     }
 
@@ -72,11 +125,13 @@
   }
 
   bigPipeProcess();
+
+  // If something goes wrong, make sure everything is cleaned up and has had a
+  // chance to be processed with everything loaded.
   window.addEventListener('load', () => {
     if (timeoutID) {
       clearTimeout(timeoutID);
     }
-
     bigPipeProcessDocument(document);
   });
-})(Drupal, drupalSettings);
\ No newline at end of file
+})(Drupal, drupalSettings);
diff --git a/core/modules/block/js/block.admin.es6.js b/core/modules/block/js/block.admin.es6.js
deleted file mode 100644
index 055f2fccba56..000000000000
--- a/core/modules/block/js/block.admin.es6.js
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * @file
- * Block admin behaviors.
- */
-
-(function ($, Drupal, debounce, once) {
-  /**
-   * Filters the block list by a text input search string.
-   *
-   * The text input will have the selector `input.block-filter-text`.
-   *
-   * The target element to do searching in will be in the selector
-   * `input.block-filter-text[data-element]`
-   *
-   * The text source where the text should be found will have the selector
-   * `.block-filter-text-source`
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the behavior for the block filtering.
-   */
-  Drupal.behaviors.blockFilterByText = {
-    attach(context, settings) {
-      const $input = $(once('block-filter-text', 'input.block-filter-text'));
-      const $table = $($input.attr('data-element'));
-      let $filterRows;
-
-      /**
-       * Filters the block list.
-       *
-       * @param {jQuery.Event} e
-       *   The jQuery event for the keyup event that triggered the filter.
-       */
-      function filterBlockList(e) {
-        const query = e.target.value.toLowerCase();
-
-        /**
-         * Shows or hides the block entry based on the query.
-         *
-         * @param {number} index
-         *   The index in the loop, as provided by `jQuery.each`
-         * @param {HTMLElement} label
-         *   The label of the block.
-         */
-        function toggleBlockEntry(index, label) {
-          const $row = $(label).parent().parent();
-          const textMatch = label.textContent.toLowerCase().includes(query);
-          $row.toggle(textMatch);
-        }
-
-        // Filter if the length of the query is at least 2 characters.
-        if (query.length >= 2) {
-          $filterRows.each(toggleBlockEntry);
-          Drupal.announce(
-            Drupal.formatPlural(
-              $table.find('tr:visible').length - 1,
-              '1 block is available in the modified list.',
-              '@count blocks are available in the modified list.',
-            ),
-          );
-        } else {
-          $filterRows.each(function (index) {
-            $(this).parent().parent().show();
-          });
-        }
-      }
-
-      if ($table.length) {
-        $filterRows = $table.find('div.block-filter-text-source');
-        $input.on('keyup', debounce(filterBlockList, 200));
-      }
-    },
-  };
-
-  /**
-   * Highlights the block that was just placed into the block listing.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the behavior for the block placement highlighting.
-   */
-  Drupal.behaviors.blockHighlightPlacement = {
-    attach(context, settings) {
-      // Ensure that the block we are attempting to scroll to actually exists.
-      if (settings.blockPlacement && $('.js-block-placed').length) {
-        once(
-          'block-highlight',
-          '[data-drupal-selector="edit-blocks"]',
-          context,
-        ).forEach((container) => {
-          const $container = $(container);
-          // Just scrolling the document.body will not work in Firefox. The html
-          // element is needed as well.
-          $('html, body').animate(
-            {
-              scrollTop:
-                $('.js-block-placed').offset().top -
-                $container.offset().top +
-                $container.scrollTop(),
-            },
-            500,
-          );
-        });
-      }
-    },
-  };
-})(jQuery, Drupal, Drupal.debounce, once);
diff --git a/core/modules/block/js/block.admin.js b/core/modules/block/js/block.admin.js
index bfed45abdee0..055f2fccba56 100644
--- a/core/modules/block/js/block.admin.js
+++ b/core/modules/block/js/block.admin.js
@@ -1,29 +1,64 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Block admin behaviors.
+ */
 
 (function ($, Drupal, debounce, once) {
+  /**
+   * Filters the block list by a text input search string.
+   *
+   * The text input will have the selector `input.block-filter-text`.
+   *
+   * The target element to do searching in will be in the selector
+   * `input.block-filter-text[data-element]`
+   *
+   * The text source where the text should be found will have the selector
+   * `.block-filter-text-source`
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the behavior for the block filtering.
+   */
   Drupal.behaviors.blockFilterByText = {
     attach(context, settings) {
       const $input = $(once('block-filter-text', 'input.block-filter-text'));
       const $table = $($input.attr('data-element'));
       let $filterRows;
 
+      /**
+       * Filters the block list.
+       *
+       * @param {jQuery.Event} e
+       *   The jQuery event for the keyup event that triggered the filter.
+       */
       function filterBlockList(e) {
         const query = e.target.value.toLowerCase();
 
+        /**
+         * Shows or hides the block entry based on the query.
+         *
+         * @param {number} index
+         *   The index in the loop, as provided by `jQuery.each`
+         * @param {HTMLElement} label
+         *   The label of the block.
+         */
         function toggleBlockEntry(index, label) {
           const $row = $(label).parent().parent();
           const textMatch = label.textContent.toLowerCase().includes(query);
           $row.toggle(textMatch);
         }
 
+        // Filter if the length of the query is at least 2 characters.
         if (query.length >= 2) {
           $filterRows.each(toggleBlockEntry);
-          Drupal.announce(Drupal.formatPlural($table.find('tr:visible').length - 1, '1 block is available in the modified list.', '@count blocks are available in the modified list.'));
+          Drupal.announce(
+            Drupal.formatPlural(
+              $table.find('tr:visible').length - 1,
+              '1 block is available in the modified list.',
+              '@count blocks are available in the modified list.',
+            ),
+          );
         } else {
           $filterRows.each(function (index) {
             $(this).parent().parent().show();
@@ -35,20 +70,40 @@
         $filterRows = $table.find('div.block-filter-text-source');
         $input.on('keyup', debounce(filterBlockList, 200));
       }
-    }
-
+    },
   };
+
+  /**
+   * Highlights the block that was just placed into the block listing.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the behavior for the block placement highlighting.
+   */
   Drupal.behaviors.blockHighlightPlacement = {
     attach(context, settings) {
+      // Ensure that the block we are attempting to scroll to actually exists.
       if (settings.blockPlacement && $('.js-block-placed').length) {
-        once('block-highlight', '[data-drupal-selector="edit-blocks"]', context).forEach(container => {
+        once(
+          'block-highlight',
+          '[data-drupal-selector="edit-blocks"]',
+          context,
+        ).forEach((container) => {
           const $container = $(container);
-          $('html, body').animate({
-            scrollTop: $('.js-block-placed').offset().top - $container.offset().top + $container.scrollTop()
-          }, 500);
+          // Just scrolling the document.body will not work in Firefox. The html
+          // element is needed as well.
+          $('html, body').animate(
+            {
+              scrollTop:
+                $('.js-block-placed').offset().top -
+                $container.offset().top +
+                $container.scrollTop(),
+            },
+            500,
+          );
         });
       }
-    }
-
+    },
   };
-})(jQuery, Drupal, Drupal.debounce, once);
\ No newline at end of file
+})(jQuery, Drupal, Drupal.debounce, once);
diff --git a/core/modules/block/js/block.es6.js b/core/modules/block/js/block.es6.js
deleted file mode 100644
index a642ce363e6b..000000000000
--- a/core/modules/block/js/block.es6.js
+++ /dev/null
@@ -1,262 +0,0 @@
-/**
- * @file
- * Block behaviors.
- */
-
-(function ($, window, Drupal, once) {
-  /**
-   * Provide the summary information for the block settings vertical tabs.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the behavior for the block settings summaries.
-   */
-  Drupal.behaviors.blockSettingsSummary = {
-    attach() {
-      // The drupalSetSummary method required for this behavior is not available
-      // on the Blocks administration page, so we need to make sure this
-      // behavior is processed only if drupalSetSummary is defined.
-      if (typeof $.fn.drupalSetSummary === 'undefined') {
-        return;
-      }
-
-      /**
-       * Create a summary for checkboxes in the provided context.
-       *
-       * @param {HTMLDocument|HTMLElement} context
-       *   A context where one would find checkboxes to summarize.
-       *
-       * @return {string}
-       *   A string with the summary.
-       */
-      function checkboxesSummary(context) {
-        const vals = [];
-        const $checkboxes = $(context).find(
-          'input[type="checkbox"]:checked + label',
-        );
-        const il = $checkboxes.length;
-        for (let i = 0; i < il; i++) {
-          vals.push($($checkboxes[i]).html());
-        }
-        if (!vals.length) {
-          vals.push(Drupal.t('Not restricted'));
-        }
-        return vals.join(', ');
-      }
-
-      $(
-        '[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-entity-bundlenode"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"]',
-      ).drupalSetSummary(checkboxesSummary);
-
-      $(
-        '[data-drupal-selector="edit-visibility-request-path"]',
-      ).drupalSetSummary((context) => {
-        const $pages = $(context).find(
-          'textarea[name="visibility[request_path][pages]"]',
-        );
-        if (!$pages.length || !$pages[0].value) {
-          return Drupal.t('Not restricted');
-        }
-
-        return Drupal.t('Restricted to certain pages');
-      });
-    },
-  };
-
-  /**
-   * Move a block in the blocks table between regions via select list.
-   *
-   * This behavior is dependent on the tableDrag behavior, since it uses the
-   * objects initialized in that behavior to update the row.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the tableDrag behavior for blocks in block administration.
-   */
-  Drupal.behaviors.blockDrag = {
-    attach(context, settings) {
-      // tableDrag is required and we should be on the blocks admin page.
-      if (
-        typeof Drupal.tableDrag === 'undefined' ||
-        typeof Drupal.tableDrag.blocks === 'undefined'
-      ) {
-        return;
-      }
-
-      /**
-       * Function to check empty regions and toggle classes based on this.
-       *
-       * @param {jQuery} table
-       *   The jQuery object representing the table to inspect.
-       * @param {jQuery} rowObject
-       *   The jQuery object representing the table row.
-       */
-      function checkEmptyRegions(table, rowObject) {
-        table.find('tr.region-message').each(function () {
-          const $this = $(this);
-          // If the dragged row is in this region, but above the message row,
-          // swap it down one space.
-          if ($this.prev('tr').get(0) === rowObject.element) {
-            // Prevent a recursion problem when using the keyboard to move rows
-            // up.
-            if (
-              rowObject.method !== 'keyboard' ||
-              rowObject.direction === 'down'
-            ) {
-              rowObject.swap('after', this);
-            }
-          }
-          // This region has become empty.
-          if (
-            $this.next('tr').is(':not(.draggable)') ||
-            $this.next('tr').length === 0
-          ) {
-            $this.removeClass('region-populated').addClass('region-empty');
-          }
-          // This region has become populated.
-          else if ($this.is('.region-empty')) {
-            $this.removeClass('region-empty').addClass('region-populated');
-          }
-        });
-      }
-
-      /**
-       * Function to update the last placed row with the correct classes.
-       *
-       * @param {jQuery} table
-       *   The jQuery object representing the table to inspect.
-       * @param {jQuery} rowObject
-       *   The jQuery object representing the table row.
-       */
-      function updateLastPlaced(table, rowObject) {
-        // Remove the color-success class from new block if applicable.
-        table.find('.color-success').removeClass('color-success');
-
-        const $rowObject = $(rowObject);
-        if (!$rowObject.is('.drag-previous')) {
-          table.find('.drag-previous').removeClass('drag-previous');
-          $rowObject.addClass('drag-previous');
-        }
-      }
-
-      /**
-       * Update block weights in the given region.
-       *
-       * @param {jQuery} table
-       *   Table with draggable items.
-       * @param {string} region
-       *   Machine name of region containing blocks to update.
-       */
-      function updateBlockWeights(table, region) {
-        // Calculate minimum weight.
-        let weight = -Math.round(table.find('.draggable').length / 2);
-        // Update the block weights.
-        table
-          .find(`.region-${region}-message`)
-          .nextUntil('.region-title')
-          .find('select.block-weight')
-          .each(function () {
-            // Increment the weight before assigning it to prevent using the
-            // absolute minimum available weight. This way we always have an
-            // unused upper and lower bound, which makes manually setting the
-            // weights easier for users who prefer to do it that way.
-            this.value = ++weight;
-          });
-      }
-
-      const table = $('#blocks');
-      // Get the blocks tableDrag object.
-      const tableDrag = Drupal.tableDrag.blocks;
-      // Add a handler for when a row is swapped, update empty regions.
-      tableDrag.row.prototype.onSwap = function (swappedRow) {
-        checkEmptyRegions(table, this);
-        updateLastPlaced(table, this);
-      };
-
-      // Add a handler so when a row is dropped, update fields dropped into
-      // new regions.
-      tableDrag.onDrop = function () {
-        const dragObject = this;
-        const $rowElement = $(dragObject.rowObject.element);
-        // Use "region-message" row instead of "region" row because
-        // "region-{region_name}-message" is less prone to regexp match errors.
-        const regionRow = $rowElement.prevAll('tr.region-message').get(0);
-        const regionName = regionRow.className.replace(
-          /([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/,
-          '$2',
-        );
-        const regionField = $rowElement.find('select.block-region-select');
-        // Check whether the newly picked region is available for this block.
-        if (regionField.find(`option[value=${regionName}]`).length === 0) {
-          // If not, alert the user and keep the block in its old region
-          // setting.
-          window.alert(Drupal.t('The block cannot be placed in this region.'));
-          // Simulate that there was a selected element change, so the row is
-          // put back to from where the user tried to drag it.
-          regionField.trigger('change');
-        }
-
-        // Update region and weight fields if the region has been changed.
-        if (!regionField.is(`.block-region-${regionName}`)) {
-          const weightField = $rowElement.find('select.block-weight');
-          const oldRegionName = weightField[0].className.replace(
-            /([^ ]+[ ]+)*block-weight-([^ ]+)([ ]+[^ ]+)*/,
-            '$2',
-          );
-          regionField
-            .removeClass(`block-region-${oldRegionName}`)
-            .addClass(`block-region-${regionName}`);
-          weightField
-            .removeClass(`block-weight-${oldRegionName}`)
-            .addClass(`block-weight-${regionName}`);
-          regionField[0].value = regionName;
-        }
-
-        updateBlockWeights(table, regionName);
-      };
-
-      // Add the behavior to each region select list.
-      $(once('block-region-select', 'select.block-region-select', context)).on(
-        'change',
-        function (event) {
-          // Make our new row and select field.
-          const row = $(this).closest('tr');
-          const select = $(this);
-          // Find the correct region and insert the row as the last in the
-          // region.
-          tableDrag.rowObject = new tableDrag.row(row[0]);
-          const regionMessage = table.find(
-            `.region-${select[0].value}-message`,
-          );
-          const regionItems = regionMessage.nextUntil(
-            '.region-message, .region-title',
-          );
-          if (regionItems.length) {
-            regionItems.last().after(row);
-          }
-          // We found that regionMessage is the last row.
-          else {
-            regionMessage.after(row);
-          }
-          updateBlockWeights(table, select[0].value);
-          // Modify empty regions with added or removed fields.
-          checkEmptyRegions(table, tableDrag.rowObject);
-          // Update last placed block indication.
-          updateLastPlaced(table, row);
-          // Show unsaved changes warning.
-          if (!tableDrag.changed) {
-            $(Drupal.theme('tableDragChangedWarning'))
-              .insertBefore(tableDrag.table)
-              .hide()
-              .fadeIn('slow');
-            tableDrag.changed = true;
-          }
-          // Remove focus from selectbox.
-          select.trigger('blur');
-        },
-      );
-    },
-  };
-})(jQuery, window, Drupal, once);
diff --git a/core/modules/block/js/block.js b/core/modules/block/js/block.js
index 0b02179de945..a642ce363e6b 100644
--- a/core/modules/block/js/block.js
+++ b/core/modules/block/js/block.js
@@ -1,143 +1,262 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Block behaviors.
+ */
 
 (function ($, window, Drupal, once) {
+  /**
+   * Provide the summary information for the block settings vertical tabs.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the behavior for the block settings summaries.
+   */
   Drupal.behaviors.blockSettingsSummary = {
     attach() {
+      // The drupalSetSummary method required for this behavior is not available
+      // on the Blocks administration page, so we need to make sure this
+      // behavior is processed only if drupalSetSummary is defined.
       if (typeof $.fn.drupalSetSummary === 'undefined') {
         return;
       }
 
+      /**
+       * Create a summary for checkboxes in the provided context.
+       *
+       * @param {HTMLDocument|HTMLElement} context
+       *   A context where one would find checkboxes to summarize.
+       *
+       * @return {string}
+       *   A string with the summary.
+       */
       function checkboxesSummary(context) {
         const vals = [];
-        const $checkboxes = $(context).find('input[type="checkbox"]:checked + label');
+        const $checkboxes = $(context).find(
+          'input[type="checkbox"]:checked + label',
+        );
         const il = $checkboxes.length;
-
         for (let i = 0; i < il; i++) {
           vals.push($($checkboxes[i]).html());
         }
-
         if (!vals.length) {
           vals.push(Drupal.t('Not restricted'));
         }
-
         return vals.join(', ');
       }
 
-      $('[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-entity-bundlenode"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"]').drupalSetSummary(checkboxesSummary);
-      $('[data-drupal-selector="edit-visibility-request-path"]').drupalSetSummary(context => {
-        const $pages = $(context).find('textarea[name="visibility[request_path][pages]"]');
+      $(
+        '[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-entity-bundlenode"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"]',
+      ).drupalSetSummary(checkboxesSummary);
 
+      $(
+        '[data-drupal-selector="edit-visibility-request-path"]',
+      ).drupalSetSummary((context) => {
+        const $pages = $(context).find(
+          'textarea[name="visibility[request_path][pages]"]',
+        );
         if (!$pages.length || !$pages[0].value) {
           return Drupal.t('Not restricted');
         }
 
         return Drupal.t('Restricted to certain pages');
       });
-    }
-
+    },
   };
+
+  /**
+   * Move a block in the blocks table between regions via select list.
+   *
+   * This behavior is dependent on the tableDrag behavior, since it uses the
+   * objects initialized in that behavior to update the row.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the tableDrag behavior for blocks in block administration.
+   */
   Drupal.behaviors.blockDrag = {
     attach(context, settings) {
-      if (typeof Drupal.tableDrag === 'undefined' || typeof Drupal.tableDrag.blocks === 'undefined') {
+      // tableDrag is required and we should be on the blocks admin page.
+      if (
+        typeof Drupal.tableDrag === 'undefined' ||
+        typeof Drupal.tableDrag.blocks === 'undefined'
+      ) {
         return;
       }
 
+      /**
+       * Function to check empty regions and toggle classes based on this.
+       *
+       * @param {jQuery} table
+       *   The jQuery object representing the table to inspect.
+       * @param {jQuery} rowObject
+       *   The jQuery object representing the table row.
+       */
       function checkEmptyRegions(table, rowObject) {
         table.find('tr.region-message').each(function () {
           const $this = $(this);
-
+          // If the dragged row is in this region, but above the message row,
+          // swap it down one space.
           if ($this.prev('tr').get(0) === rowObject.element) {
-            if (rowObject.method !== 'keyboard' || rowObject.direction === 'down') {
+            // Prevent a recursion problem when using the keyboard to move rows
+            // up.
+            if (
+              rowObject.method !== 'keyboard' ||
+              rowObject.direction === 'down'
+            ) {
               rowObject.swap('after', this);
             }
           }
-
-          if ($this.next('tr').is(':not(.draggable)') || $this.next('tr').length === 0) {
+          // This region has become empty.
+          if (
+            $this.next('tr').is(':not(.draggable)') ||
+            $this.next('tr').length === 0
+          ) {
             $this.removeClass('region-populated').addClass('region-empty');
-          } else if ($this.is('.region-empty')) {
+          }
+          // This region has become populated.
+          else if ($this.is('.region-empty')) {
             $this.removeClass('region-empty').addClass('region-populated');
           }
         });
       }
 
+      /**
+       * Function to update the last placed row with the correct classes.
+       *
+       * @param {jQuery} table
+       *   The jQuery object representing the table to inspect.
+       * @param {jQuery} rowObject
+       *   The jQuery object representing the table row.
+       */
       function updateLastPlaced(table, rowObject) {
+        // Remove the color-success class from new block if applicable.
         table.find('.color-success').removeClass('color-success');
-        const $rowObject = $(rowObject);
 
+        const $rowObject = $(rowObject);
         if (!$rowObject.is('.drag-previous')) {
           table.find('.drag-previous').removeClass('drag-previous');
           $rowObject.addClass('drag-previous');
         }
       }
 
+      /**
+       * Update block weights in the given region.
+       *
+       * @param {jQuery} table
+       *   Table with draggable items.
+       * @param {string} region
+       *   Machine name of region containing blocks to update.
+       */
       function updateBlockWeights(table, region) {
+        // Calculate minimum weight.
         let weight = -Math.round(table.find('.draggable').length / 2);
-        table.find(`.region-${region}-message`).nextUntil('.region-title').find('select.block-weight').each(function () {
-          this.value = ++weight;
-        });
+        // Update the block weights.
+        table
+          .find(`.region-${region}-message`)
+          .nextUntil('.region-title')
+          .find('select.block-weight')
+          .each(function () {
+            // Increment the weight before assigning it to prevent using the
+            // absolute minimum available weight. This way we always have an
+            // unused upper and lower bound, which makes manually setting the
+            // weights easier for users who prefer to do it that way.
+            this.value = ++weight;
+          });
       }
 
       const table = $('#blocks');
+      // Get the blocks tableDrag object.
       const tableDrag = Drupal.tableDrag.blocks;
-
+      // Add a handler for when a row is swapped, update empty regions.
       tableDrag.row.prototype.onSwap = function (swappedRow) {
         checkEmptyRegions(table, this);
         updateLastPlaced(table, this);
       };
 
+      // Add a handler so when a row is dropped, update fields dropped into
+      // new regions.
       tableDrag.onDrop = function () {
         const dragObject = this;
         const $rowElement = $(dragObject.rowObject.element);
+        // Use "region-message" row instead of "region" row because
+        // "region-{region_name}-message" is less prone to regexp match errors.
         const regionRow = $rowElement.prevAll('tr.region-message').get(0);
-        const regionName = regionRow.className.replace(/([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
+        const regionName = regionRow.className.replace(
+          /([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/,
+          '$2',
+        );
         const regionField = $rowElement.find('select.block-region-select');
-
+        // Check whether the newly picked region is available for this block.
         if (regionField.find(`option[value=${regionName}]`).length === 0) {
+          // If not, alert the user and keep the block in its old region
+          // setting.
           window.alert(Drupal.t('The block cannot be placed in this region.'));
+          // Simulate that there was a selected element change, so the row is
+          // put back to from where the user tried to drag it.
           regionField.trigger('change');
         }
 
+        // Update region and weight fields if the region has been changed.
         if (!regionField.is(`.block-region-${regionName}`)) {
           const weightField = $rowElement.find('select.block-weight');
-          const oldRegionName = weightField[0].className.replace(/([^ ]+[ ]+)*block-weight-([^ ]+)([ ]+[^ ]+)*/, '$2');
-          regionField.removeClass(`block-region-${oldRegionName}`).addClass(`block-region-${regionName}`);
-          weightField.removeClass(`block-weight-${oldRegionName}`).addClass(`block-weight-${regionName}`);
+          const oldRegionName = weightField[0].className.replace(
+            /([^ ]+[ ]+)*block-weight-([^ ]+)([ ]+[^ ]+)*/,
+            '$2',
+          );
+          regionField
+            .removeClass(`block-region-${oldRegionName}`)
+            .addClass(`block-region-${regionName}`);
+          weightField
+            .removeClass(`block-weight-${oldRegionName}`)
+            .addClass(`block-weight-${regionName}`);
           regionField[0].value = regionName;
         }
 
         updateBlockWeights(table, regionName);
       };
 
-      $(once('block-region-select', 'select.block-region-select', context)).on('change', function (event) {
-        const row = $(this).closest('tr');
-        const select = $(this);
-        tableDrag.rowObject = new tableDrag.row(row[0]);
-        const regionMessage = table.find(`.region-${select[0].value}-message`);
-        const regionItems = regionMessage.nextUntil('.region-message, .region-title');
-
-        if (regionItems.length) {
-          regionItems.last().after(row);
-        } else {
-          regionMessage.after(row);
-        }
-
-        updateBlockWeights(table, select[0].value);
-        checkEmptyRegions(table, tableDrag.rowObject);
-        updateLastPlaced(table, row);
-
-        if (!tableDrag.changed) {
-          $(Drupal.theme('tableDragChangedWarning')).insertBefore(tableDrag.table).hide().fadeIn('slow');
-          tableDrag.changed = true;
-        }
-
-        select.trigger('blur');
-      });
-    }
-
+      // Add the behavior to each region select list.
+      $(once('block-region-select', 'select.block-region-select', context)).on(
+        'change',
+        function (event) {
+          // Make our new row and select field.
+          const row = $(this).closest('tr');
+          const select = $(this);
+          // Find the correct region and insert the row as the last in the
+          // region.
+          tableDrag.rowObject = new tableDrag.row(row[0]);
+          const regionMessage = table.find(
+            `.region-${select[0].value}-message`,
+          );
+          const regionItems = regionMessage.nextUntil(
+            '.region-message, .region-title',
+          );
+          if (regionItems.length) {
+            regionItems.last().after(row);
+          }
+          // We found that regionMessage is the last row.
+          else {
+            regionMessage.after(row);
+          }
+          updateBlockWeights(table, select[0].value);
+          // Modify empty regions with added or removed fields.
+          checkEmptyRegions(table, tableDrag.rowObject);
+          // Update last placed block indication.
+          updateLastPlaced(table, row);
+          // Show unsaved changes warning.
+          if (!tableDrag.changed) {
+            $(Drupal.theme('tableDragChangedWarning'))
+              .insertBefore(tableDrag.table)
+              .hide()
+              .fadeIn('slow');
+            tableDrag.changed = true;
+          }
+          // Remove focus from selectbox.
+          select.trigger('blur');
+        },
+      );
+    },
   };
-})(jQuery, window, Drupal, once);
\ No newline at end of file
+})(jQuery, window, Drupal, once);
diff --git a/core/modules/book/book.es6.js b/core/modules/book/book.es6.js
deleted file mode 100644
index b9f44d564e61..000000000000
--- a/core/modules/book/book.es6.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * @file
- * JavaScript behaviors for the Book module.
- */
-
-(function ($, Drupal) {
-  /**
-   * Adds summaries to the book outline form.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches summary behavior to book outline forms.
-   */
-  Drupal.behaviors.bookDetailsSummaries = {
-    attach(context) {
-      $(context)
-        .find('.book-outline-form')
-        .drupalSetSummary((context) => {
-          const $select = $(context).find('.book-title-select');
-          const val = $select[0].value;
-
-          if (val === '0') {
-            return Drupal.t('Not in book');
-          }
-          if (val === 'new') {
-            return Drupal.t('New book');
-          }
-          return Drupal.checkPlain($select.find(':selected')[0].textContent);
-        });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/book/book.js b/core/modules/book/book.js
index efc457056d5a..b9f44d564e61 100644
--- a/core/modules/book/book.js
+++ b/core/modules/book/book.js
@@ -1,28 +1,33 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * JavaScript behaviors for the Book module.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Adds summaries to the book outline form.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches summary behavior to book outline forms.
+   */
   Drupal.behaviors.bookDetailsSummaries = {
     attach(context) {
-      $(context).find('.book-outline-form').drupalSetSummary(context => {
-        const $select = $(context).find('.book-title-select');
-        const val = $select[0].value;
-
-        if (val === '0') {
-          return Drupal.t('Not in book');
-        }
-
-        if (val === 'new') {
-          return Drupal.t('New book');
-        }
-
-        return Drupal.checkPlain($select.find(':selected')[0].textContent);
-      });
-    }
+      $(context)
+        .find('.book-outline-form')
+        .drupalSetSummary((context) => {
+          const $select = $(context).find('.book-title-select');
+          const val = $select[0].value;
 
+          if (val === '0') {
+            return Drupal.t('Not in book');
+          }
+          if (val === 'new') {
+            return Drupal.t('New book');
+          }
+          return Drupal.checkPlain($select.find(':selected')[0].textContent);
+        });
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/ckeditor5/js/ckeditor5.admin.es6.js b/core/modules/ckeditor5/js/ckeditor5.admin.es6.js
deleted file mode 100644
index c996d2f506f1..000000000000
--- a/core/modules/ckeditor5/js/ckeditor5.admin.es6.js
+++ /dev/null
@@ -1,1069 +0,0 @@
-/**
- * @file
- * Provides the admin UI for CKEditor 5.
- */
-
-((Drupal, drupalSettings, $, JSON, once, Sortable, { tabbable }) => {
-  const toolbarHelp = [
-    {
-      message: Drupal.t(
-        "The toolbar buttons that don't fit the user's browser window width will be grouped in a dropdown. If multiple toolbar rows are preferred, those can be configured by adding an explicit wrapping breakpoint wherever you want to start a new row.",
-        null,
-        {
-          context:
-            'CKEditor 5 toolbar help text, default, no explicit wrapping breakpoint',
-        },
-      ),
-      button: 'wrapping',
-      condition: false,
-    },
-    {
-      message: Drupal.t(
-        'You have configured a multi-row toolbar by using an explicit wrapping breakpoint. This may not work well in narrow browser windows. To use automatic grouping, remove any of these divider buttons.',
-        null,
-        {
-          context:
-            'CKEditor 5 toolbar help text, with explicit wrapping breakpoint',
-        },
-      ),
-      button: 'wrapping',
-      condition: true,
-    },
-  ];
-
-  /**
-   * Allows attaching listeners to a value.
-   *
-   * @type {Observable}
-   */
-  const Observable = class {
-    /**
-     * Creates new Observable with a value.
-     *
-     * @param {*} value
-     *   The value to be observed.
-     */
-    constructor(value) {
-      this._listeners = [];
-      this._value = value;
-    }
-
-    /**
-     * Notifies subscribers about new values.
-     */
-    notify() {
-      this._listeners.forEach((listener) => listener(this._value));
-    }
-
-    /**
-     * Subscribes a listener callback to changes.
-     *
-     * @param {Function} listener
-     *   The function to be called when a new value is set.
-     */
-    subscribe(listener) {
-      this._listeners.push(listener);
-    }
-
-    /**
-     * The value of the observable.
-     *
-     * @return {*}
-     *   The current value.
-     */
-    get value() {
-      return this._value;
-    }
-
-    /**
-     * Sets the value of the observable and notifies subscribers.
-     *
-     * @param {*} val
-     *   The new value of the observable.
-     */
-    set value(val) {
-      if (val !== this._value) {
-        this._value = val;
-        this.notify();
-      }
-    }
-  };
-
-  /**
-   * Gets selected buttons.
-   *
-   * @param {Array} selected
-   *   The selected buttons retrieved from state.
-   * @param {Array} dividers
-   *   The available dividers.
-   * @param {Array} available
-   *   The available buttons.
-   * @return {Array}
-   *   An array containing selected buttons.
-   */
-  const getSelectedButtons = (selected, dividers, available) => {
-    return selected.map((id) => ({
-      ...[...dividers, ...available].find((button) => button.id === id),
-    }));
-  };
-
-  /**
-   * Updates selected buttons to the textarea.
-   *
-   * @param {Array} selection
-   *   The current selection.
-   * @param {Element} textarea
-   *   The textarea element.
-   */
-  const updateSelectedButtons = (selection, textarea) => {
-    const newValue = JSON.stringify(selection);
-
-    const priorValue = textarea.innerHTML;
-    textarea.value = newValue;
-    textarea.innerHTML = newValue;
-
-    // The textarea is programmatically updated, so no native JavaScript
-    // event is triggered. Event listeners need to be aware of this config
-    // update, so a custom event is dispatched immediately after the
-    // config update.
-    textarea.dispatchEvent(
-      new CustomEvent('change', {
-        detail: {
-          priorValue,
-        },
-      }),
-    );
-  };
-
-  /**
-   * Function to add button to selected buttons.
-   *
-   * @param {Observable} selection
-   *   The currently selected buttons.
-   * @param {Element} element
-   *   The element which is being added.
-   * @param {function} announceChange
-   *   Function to call to announce the change.
-   */
-  const addToSelectedButtons = (selection, element, announceChange) => {
-    const list = [...selection.value];
-    list.push(element.dataset.id);
-    selection.value = list;
-
-    if (announceChange) {
-      setTimeout(() => {
-        announceChange(element.dataset.label);
-      });
-    }
-  };
-
-  /**
-   * Function to remove button from selected buttons.
-   *
-   * @param {Observable} selection
-   *   The currently selected buttons.
-   * @param {Element} element
-   *   The element which is being removed.
-   * @param {function} announceChange
-   *   Function to call to announce the change.
-   */
-  const removeFromSelectedButtons = (selection, element, announceChange) => {
-    const list = [...selection.value];
-    const index = Array.from(element.parentElement.children).findIndex(
-      (child) => {
-        return child === element;
-      },
-    );
-    list.splice(index, 1);
-    selection.value = list;
-
-    if (announceChange) {
-      setTimeout(() => {
-        announceChange(element.dataset.label);
-      });
-    }
-  };
-
-  /**
-   * Moves element within active buttons.
-   *
-   * @param {Observable} selection
-   *   The currently selected buttons.
-   * @param {Element} element
-   *   The element being moved.
-   * @param {Number} dir
-   *   The direction which the element is being moved.
-   */
-  const moveWithinSelectedButtons = (selection, element, dir) => {
-    const list = [...selection.value];
-    const index = Array.from(element.parentElement.children).findIndex(
-      (child) => {
-        return child === element;
-      },
-    );
-    // If moving up, check it is not the first, else check it is not the last.
-    const condition = dir < 0 ? index > 0 : index < list.length - 1;
-    if (condition) {
-      list.splice(index + dir, 0, list.splice(index, 1)[0]);
-      selection.value = list;
-    }
-  };
-
-  /**
-   * Copies element to active buttons.
-   *
-   * @param {Observable} selection
-   *   The currently selected buttons.
-   * @param {Element} element
-   *   The element to be copied.
-   * @param {Function} announceChange
-   *   A function to call to announce the change.
-   */
-  const copyToActiveButtons = (selection, element, announceChange) => {
-    const list = [...selection.value];
-    list.push(element.dataset.id);
-    selection.value = list;
-
-    setTimeout(() => {
-      if (announceChange) {
-        announceChange(element.dataset.label);
-      }
-    });
-  };
-
-  /**
-   * Renders the CKEditor 5 button admin UI.
-   *
-   * @param {Element} root
-   *   The element where the admin UI should be rendered.
-   * @param {Observable} selectedButtons
-   *   An Observable object containing selected buttons.
-   * @param {Array} availableButtons
-   *   An array containing available buttons.
-   * @param {Array} dividerButtons
-   *   An array containing available divider buttons.
-   */
-  const render = (root, selectedButtons, availableButtons, dividerButtons) => {
-    const toolbarHelpText = toolbarHelp
-      .filter(
-        (helpItem) =>
-          selectedButtons.value.includes(helpItem.button) ===
-          helpItem.condition,
-      )
-      .map((helpItem) => helpItem.message);
-
-    // Get the existing toolbar help message.
-    const existingToolbarHelpText = document.querySelector(
-      '[data-drupal-selector="ckeditor5-admin-help-message"]',
-    );
-
-    // If the existing toolbar help message does not match the message that is
-    // about to be rendered, it is new information that should be conveyed to
-    // assistive tech via announce().
-    if (
-      existingToolbarHelpText &&
-      toolbarHelpText.join('').trim() !==
-        existingToolbarHelpText.textContent.trim()
-    ) {
-      Drupal.announce(toolbarHelpText.join(' '));
-    }
-
-    root.innerHTML = Drupal.theme.ckeditor5Admin({
-      availableButtons: Drupal.theme.ckeditor5AvailableButtons({
-        buttons: availableButtons.filter(
-          (button) => !selectedButtons.value.includes(button.id),
-        ),
-      }),
-      dividerButtons: Drupal.theme.ckeditor5DividerButtons({
-        buttons: dividerButtons,
-      }),
-      activeToolbar: Drupal.theme.ckeditor5SelectedButtons({
-        buttons: getSelectedButtons(
-          selectedButtons.value,
-          dividerButtons,
-          availableButtons,
-        ),
-      }),
-      helpMessage: toolbarHelpText,
-    });
-
-    // Create sortable groups for available buttons, current toolbar items,
-    // and dividers.
-    new Sortable(
-      root.querySelector(
-        '[data-button-list="ckeditor5-toolbar-active-buttons"]',
-      ),
-      {
-        group: { name: 'toolbar', put: ['divider', 'available'] },
-        sort: true,
-        store: {
-          set: (sortable) => {
-            selectedButtons.value = sortable.toArray();
-          },
-        },
-      },
-    );
-    const toolbarAvailableButtons = new Sortable(
-      root.querySelector(
-        '[data-button-list="ckeditor5-toolbar-available-buttons"]',
-      ),
-      {
-        group: { name: 'available', put: ['toolbar'] },
-        sort: false,
-        onAdd: (event) => {
-          // If the moved item is a divider, it should not be added to
-          // the available buttons list.
-          if (
-            dividerButtons.find(
-              (dividerButton) => dividerButton.id === event.item.dataset.id,
-            )
-          ) {
-            const { newIndex } = event;
-            setTimeout(() => {
-              // Remove the divider button from the available buttons
-              // list. Draggable reassesses the lists during each drag
-              // event, so the DOM removal should not be disruptive.
-              document
-                .querySelectorAll('.ckeditor5-toolbar-available__buttons li')
-                [newIndex].remove();
-            });
-          }
-        },
-      },
-    );
-    new Sortable(
-      root.querySelector(
-        '[data-button-list="ckeditor5-toolbar-divider-buttons"]',
-      ),
-      {
-        group: { name: 'divider', put: false, pull: 'clone', sort: 'false' },
-      },
-    );
-
-    root
-      .querySelectorAll('[data-drupal-selector="ckeditor5-toolbar-button"]')
-      .forEach((element) => {
-        const expandButton = (event) => {
-          event.currentTarget
-            .querySelectorAll('.ckeditor5-toolbar-button')
-            .forEach((buttonElement) => {
-              buttonElement.setAttribute('data-expanded', true);
-            });
-        };
-        const retractButton = (event) => {
-          event.currentTarget
-            .querySelectorAll('.ckeditor5-toolbar-button')
-            .forEach((buttonElement) => {
-              buttonElement.setAttribute('data-expanded', false);
-            });
-        };
-        element.addEventListener('mouseenter', expandButton);
-        element.addEventListener('focus', expandButton);
-        element.addEventListener('mouseleave', retractButton);
-        element.addEventListener('blur', retractButton);
-
-        element.addEventListener('keyup', (event) => {
-          // Keys supported by the admin UI. Depending on the element that is
-          // triggering the event, the event could trigger changes in the state.
-          // Changes to the state trigger re-rendering of the admin UI, which
-          // means that for consistent navigation, each action modifying state
-          // needs to set focus back on the button that is being moved. The state
-          // change also triggers an AJAX request which re-renders parts of the
-          // form, and moves the focus to the triggering form element, meaning
-          // that focus needs to be set back on the button again.
-          const supportedKeys = [
-            'ArrowLeft',
-            'ArrowRight',
-            'ArrowUp',
-            'ArrowDown',
-          ];
-          const dir = document.documentElement.dir;
-          if (supportedKeys.includes(event.key)) {
-            if (event.currentTarget.dataset.divider.toLowerCase() === 'true') {
-              switch (event.key) {
-                case 'ArrowDown': {
-                  const announceChange = (name) => {
-                    Drupal.announce(
-                      Drupal.t(
-                        'Button @name has been copied to the active toolbar.',
-                        { '@name': name },
-                      ),
-                    );
-                  };
-                  copyToActiveButtons(
-                    selectedButtons,
-                    event.currentTarget,
-                    announceChange,
-                  );
-                  // Focus the last button since new button is always added to the
-                  // end of the list.
-                  root
-                    .querySelector(
-                      '[data-button-list="ckeditor5-toolbar-active-buttons"] li:last-child',
-                    )
-                    .focus();
-                  break;
-                }
-              }
-            } else if (
-              selectedButtons.value.includes(event.currentTarget.dataset.id)
-            ) {
-              const index = Array.from(
-                element.parentElement.children,
-              ).findIndex((child) => {
-                return child === element;
-              });
-              switch (event.key) {
-                case 'ArrowLeft': {
-                  const leftOffset = dir === 'ltr' ? -1 : 1;
-                  moveWithinSelectedButtons(
-                    selectedButtons,
-                    event.currentTarget,
-                    leftOffset,
-                  );
-                  // Move focus to left or right from the current index depending
-                  // on current language direction. Use index instead of the
-                  // data-id because dividers don't have a unique ID.
-                  root
-                    .querySelectorAll(
-                      '[data-button-list="ckeditor5-toolbar-active-buttons"] li',
-                    )
-                    [index + leftOffset].focus();
-                  break;
-                }
-                case 'ArrowRight': {
-                  const rightOffset = dir === 'ltr' ? 1 : -1;
-                  moveWithinSelectedButtons(
-                    selectedButtons,
-                    event.currentTarget,
-                    rightOffset,
-                  );
-                  // Move focus to right or left from the current index depending
-                  // on current language direction. Use index instead of the
-                  // data-id because dividers don't have a unique ID.
-                  root
-                    .querySelectorAll(
-                      '[data-button-list="ckeditor5-toolbar-active-buttons"] li',
-                    )
-                    [index + rightOffset].focus();
-                  break;
-                }
-                case 'ArrowUp': {
-                  const announceChange = (name) => {
-                    Drupal.announce(
-                      Drupal.t(
-                        'Button @name has been removed from the active toolbar.',
-                        { '@name': name },
-                      ),
-                    );
-                  };
-                  removeFromSelectedButtons(
-                    selectedButtons,
-                    event.currentTarget,
-                    announceChange,
-                  );
-                  // Focus only if the button wasn't a divider because dividers
-                  // are simply removed from the active buttons instead of moving
-                  // to another list.
-                  if (
-                    !dividerButtons.find(
-                      (dividerButton) =>
-                        event.currentTarget.dataset.id === dividerButton.id,
-                    )
-                  ) {
-                    // Focus button based on the data-id attribute from the
-                    // available buttons list.
-                    root
-                      .querySelector(
-                        `[data-button-list="ckeditor5-toolbar-available-buttons"] [data-id="${event.currentTarget.dataset.id}"]`,
-                      )
-                      .focus();
-                  }
-                  break;
-                }
-              }
-            } else if (
-              toolbarAvailableButtons
-                .toArray()
-                .includes(event.currentTarget.dataset.id)
-            ) {
-              switch (event.key) {
-                case 'ArrowDown': {
-                  const announceChange = (name) => {
-                    Drupal.announce(
-                      Drupal.t(
-                        'Button @name has been moved to the active toolbar.',
-                        { '@name': name },
-                      ),
-                    );
-                  };
-                  addToSelectedButtons(
-                    selectedButtons,
-                    event.currentTarget,
-                    announceChange,
-                  );
-                  // Focus the last button since new button is always added to the
-                  // end of the list.
-                  root
-                    .querySelector(
-                      '[data-button-list="ckeditor5-toolbar-active-buttons"] li:last-child',
-                    )
-                    .focus();
-                  break;
-                }
-              }
-            }
-          }
-        });
-      });
-  };
-
-  /**
-   * Attach CKEditor 5 admin UI.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches admin app to edit the CKEditor 5 toolbar.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detaches admin app from the CKEditor 5 configuration form on 'unload'.
-   */
-  Drupal.behaviors.ckeditor5Admin = {
-    attach(context) {
-      once('ckeditor5-admin-toolbar', '#ckeditor5-toolbar-app').forEach(
-        (container) => {
-          const selectedTextarea = context.querySelector(
-            '#ckeditor5-toolbar-buttons-selected',
-          );
-          const available = Object.entries(
-            JSON.parse(
-              context.querySelector('#ckeditor5-toolbar-buttons-available')
-                .innerHTML,
-            ),
-          ).map(([name, attrs]) => ({ name, id: name, ...attrs }));
-          const dividers = [
-            {
-              id: 'divider',
-              name: '|',
-              label: Drupal.t('Divider'),
-            },
-            {
-              id: 'wrapping',
-              name: '-',
-              label: Drupal.t('Wrapping'),
-            },
-          ];
-
-          // Selected is used for managing the state. Sortable is handling updates
-          // to the state when the system is operated by mouse. There are
-          // functions making direct modifications to the state when system is
-          // operated by keyboard.
-          const selected = new Observable(
-            JSON.parse(selectedTextarea.innerHTML).map((name) => {
-              return [...dividers, ...available].find((button) => {
-                return button.name === name;
-              }).id;
-            }),
-          );
-
-          const mapSelection = (selection) => {
-            return selection.map((id) => {
-              return [...dividers, ...available].find((button) => {
-                return button.id === id;
-              }).name;
-            });
-          };
-          // Whenever the state is changed, update the textarea with the changes.
-          // This will also trigger re-render of the admin UI to reinitialize the
-          // Sortable state.
-          selected.subscribe((selection) => {
-            updateSelectedButtons(mapSelection(selection), selectedTextarea);
-            render(container, selected, available, dividers);
-          });
-
-          [
-            context.querySelector('#ckeditor5-toolbar-buttons-available'),
-            context.querySelector('[class*="editor-settings-toolbar-items"]'),
-          ]
-            .filter((el) => el)
-            .forEach((el) => {
-              el.classList.add('visually-hidden');
-            });
-
-          render(container, selected, available, dividers);
-        },
-      );
-      // Safari's focus outlines take into account absolute positioned elements.
-      // When a toolbar option is blurred, the portion of the focus outline
-      // surrounding the absolutely positioned tooltip does not go away. To
-      // prevent keyboard navigation users from seeing outline artifacts for
-      // every option they've tabbed through, we provide a keydown listener
-      // that can catch blur-causing events before the blur happens. If the
-      // tooltip is hidden before the blur event, the outline will disappear
-      // correctly.
-      once('safari-focus-fix', '.ckeditor5-toolbar-item').forEach((item) => {
-        item.addEventListener('keydown', (e) => {
-          const keyCodeDirections = {
-            9: 'tab',
-            37: 'left',
-            38: 'up',
-            39: 'right',
-            40: 'down',
-          };
-          if (
-            ['tab', 'left', 'up', 'right', 'down'].includes(
-              keyCodeDirections[e.keyCode],
-            )
-          ) {
-            let hideTip = false;
-            const isActive = e.target.closest(
-              '[data-button-list="ckeditor5-toolbar-active__buttons"]',
-            );
-            if (isActive) {
-              if (
-                ['tab', 'left', 'up', 'right'].includes(
-                  keyCodeDirections[e.keyCode],
-                )
-              ) {
-                hideTip = true;
-              }
-            } else if (['tab', 'down'].includes(keyCodeDirections[e.keyCode])) {
-              hideTip = true;
-            }
-            if (hideTip) {
-              e.target
-                .querySelector('[data-expanded]')
-                .setAttribute('data-expanded', 'false');
-            }
-          }
-        });
-      });
-
-      /**
-       * Updates the UI state info in the form's 'data-drupal-ui-state' attribute.
-       *
-       * @param {object} states
-       *   An object with one or more items with the structure { ui-property: stored-value }
-       */
-      const updateUiStateStorage = (states) => {
-        const form = document.querySelector(
-          '#filter-format-edit-form, #filter-format-add-form',
-        );
-
-        // Get the current stored UI state as an object.
-        const currentStates = form.hasAttribute('data-drupal-ui-state')
-          ? JSON.parse(form.getAttribute('data-drupal-ui-state'))
-          : {};
-
-        // Store the updated UI state object as an object literal in the parent
-        // form's 'data-drupal-ui-state' attribute.
-        form.setAttribute(
-          'data-drupal-ui-state',
-          JSON.stringify({ ...currentStates, ...states }),
-        );
-      };
-
-      /**
-       * Gets a stored UI state property.
-       *
-       * @param {string} property
-       *   The UI state property to retrieve the value of.
-       *
-       * @return {string|null}
-       *   When present, the stored value of the property.
-       */
-      const getUiStateStorage = (property) => {
-        const form = document.querySelector(
-          '#filter-format-edit-form, #filter-format-add-form',
-        );
-
-        if (form === null) {
-          return;
-        }
-
-        // Parse the object literal stored in the form's 'data-drupal-ui-state'
-        // attribute and return the value of the object property that matches
-        // the 'property' argument.
-        return form.hasAttribute('data-drupal-ui-state')
-          ? JSON.parse(form.getAttribute('data-drupal-ui-state'))[property]
-          : null;
-      };
-
-      // Add an attribute to the parent form for storing UI states, so this
-      // information can be retrieved after AJAX rebuilds.
-      once(
-        'ui-state-storage',
-        '#filter-format-edit-form, #filter-format-add-form',
-      ).forEach((form) => {
-        form.setAttribute('data-drupal-ui-state', JSON.stringify({}));
-      });
-
-      /**
-       * Maintains the active vertical tab after AJAX rebuild.
-       *
-       * @param {Element} verticalTabs
-       *   The vertical tabs element.
-       */
-      const maintainActiveVerticalTab = (verticalTabs) => {
-        const id = verticalTabs.id;
-
-        // If the UI state storage has an active tab, click that tab.
-        const activeTab = getUiStateStorage(`${id}-active-tab`);
-        if (activeTab) {
-          setTimeout(() => {
-            const activeTabLink = document.querySelector(activeTab);
-            activeTabLink.click();
-
-            // Only change focus on the plugin-settings-wrapper element.
-            if (id !== 'plugin-settings-wrapper') {
-              return;
-            }
-            // If the current focused element is not the body, then the user
-            // navigated away from the vertical tab area and is somewhere else
-            // within the form. Do not change the current focus.
-            if (document.activeElement !== document.body) {
-              return;
-            }
-            // If the active element is the body then we can assume that the
-            // focus was on an element that was replaced by an ajax command.
-            // If that is the case restore the focus to the active tab that
-            // was just rebuilt.
-            const targetTabPane = document.querySelector(
-              activeTabLink.getAttribute('href'),
-            );
-            if (targetTabPane) {
-              const tabbableElements = tabbable(targetTabPane);
-              if (tabbableElements.length) {
-                tabbableElements[0].focus();
-              }
-            }
-          });
-        }
-
-        // Add click listener that adds any tab click into UI storage.
-        verticalTabs.querySelectorAll('.vertical-tabs__menu').forEach((tab) => {
-          tab.addEventListener('click', (e) => {
-            const state = {};
-            const href = e.target
-              .closest('[href]')
-              .getAttribute('href')
-              .split('--')[0];
-            state[`${id}-active-tab`] = `#${id} [href^='${href}']`;
-            updateUiStateStorage(state);
-          });
-        });
-      };
-
-      once(
-        'maintainActiveVerticalTab',
-        '#plugin-settings-wrapper, #filter-settings-wrapper',
-      ).forEach(maintainActiveVerticalTab);
-
-      // Add listeners to maintain focus after AJAX rebuilds.
-      const selectedButtons = document.querySelector(
-        '#ckeditor5-toolbar-buttons-selected',
-      );
-
-      once('textarea-listener', selectedButtons).forEach((textarea) => {
-        textarea.addEventListener('change', (e) => {
-          const buttonName = document.activeElement.getAttribute('data-id');
-          if (!buttonName) {
-            // If there is no 'data-id' attribute, then the config
-            // is happening via mouse.
-            return;
-          }
-          let focusSelector = '';
-
-          // Divider elements are treated differently as there can be multiple
-          // elements with the same button name.
-          if (['divider', 'wrapping'].includes(buttonName)) {
-            const oldConfig = JSON.parse(e.detail.priorValue);
-            const newConfig = JSON.parse(e.target.innerHTML);
-
-            // If the divider is being removed from active buttons, it does not
-            // 'move' anywhere. Move focus to the prior active button
-            if (oldConfig.length > newConfig.length) {
-              for (let item = 0; item < newConfig.length; item++) {
-                if (newConfig[item] !== oldConfig[item]) {
-                  focusSelector = `[data-button-list="ckeditor5-toolbar-active-buttons"] li:nth-child(${Math.min(
-                    item - 1,
-                    0,
-                  )})`;
-                  break;
-                }
-              }
-            } else if (oldConfig.length < newConfig.length) {
-              // If the divider is being added, it will be the last active item.
-              focusSelector =
-                '[data-button-list="ckeditor5-toolbar-active-buttons"] li:last-child';
-            } else {
-              // When moving a dividers position within the active buttons.
-              document
-                .querySelectorAll(
-                  `[data-button-list="ckeditor5-toolbar-active-buttons"] [data-id='${buttonName}']`,
-                )
-                .forEach((divider, index) => {
-                  if (divider === document.activeElement) {
-                    focusSelector = `${buttonName}|${index}`;
-                  }
-                });
-            }
-          } else {
-            focusSelector = `[data-id='${buttonName}']`;
-          }
-
-          // Store the focus selector in an attribute on the form itself, which
-          // will not be overwritten after the AJAX rebuild. This makes it
-          // the value available to the textarea focus listener that is
-          // triggered after the AJAX rebuild.
-          updateUiStateStorage({ focusSelector });
-        });
-
-        textarea.addEventListener('focus', () => {
-          // The selector that should receive focus is stored in the parent
-          // form element. Move focus to that selector.
-          const focusSelector = getUiStateStorage('focusSelector');
-
-          if (focusSelector) {
-            // If focusSelector includes '|', it is a separator that is being
-            // moved within the active button list. Different logic us used to
-            // determine focus since there can be multiple separators of the
-            // same type within the active buttons list.
-            if (focusSelector.includes('|')) {
-              const [buttonName, count] = focusSelector.split('|');
-              document
-                .querySelectorAll(
-                  `[data-button-list="ckeditor5-toolbar-active-buttons"] [data-id='${buttonName}']`,
-                )
-                .forEach((item, index) => {
-                  if (index === parseInt(count, 10)) {
-                    item.focus();
-                  }
-                });
-            } else {
-              const toFocus = document.querySelector(focusSelector);
-              if (toFocus) {
-                toFocus.focus();
-              }
-            }
-          }
-        });
-      });
-    },
-  };
-
-  /**
-   * Theme function for CKEditor 5 selected buttons.
-   *
-   * @param {Object} options
-   *   An object containing options.
-   * @param {Array} options.buttons
-   *   An array of selected buttons.
-   * @return {string}
-   *   The selected buttons markup.
-   *
-   * @private
-   */
-  Drupal.theme.ckeditor5SelectedButtons = ({ buttons }) => {
-    return `
-      <ul class="ckeditor5-toolbar-tray ckeditor5-toolbar-active__buttons" data-button-list="ckeditor5-toolbar-active-buttons" role="listbox" aria-orientation="horizontal" aria-labelledby="ckeditor5-toolbar-active-buttons-label">
-        ${buttons
-          .map((button) =>
-            Drupal.theme.ckeditor5Button({ button, listType: 'active' }),
-          )
-          .join('')}
-      </ul>
-    `;
-  };
-
-  /**
-   * Theme function for CKEditor 5 divider buttons.
-   *
-   * @param {Object} options
-   *   An object containing options.
-   * @param {Array} options.buttons
-   *   An array of divider buttons.
-   * @return {string}
-   *   The CKEditor 5 divider buttons markup.
-   *
-   * @private
-   */
-  Drupal.theme.ckeditor5DividerButtons = ({ buttons }) => {
-    return `
-      <ul class="ckeditor5-toolbar-tray ckeditor5-toolbar-divider__buttons" data-button-list="ckeditor5-toolbar-divider-buttons" role="listbox" aria-orientation="horizontal" aria-labelledby="ckeditor5-toolbar-divider-buttons-label">
-        ${buttons
-          .map((button) =>
-            Drupal.theme.ckeditor5Button({ button, listType: 'divider' }),
-          )
-          .join('')}
-      </ul>
-    `;
-  };
-
-  /**
-   * Theme function for CKEditor 5 available buttons.
-   *
-   * @param {Object} options
-   *   An object containing options.
-   * @param {Array} options.buttons
-   *   An array of available buttons.
-   * @return {string}
-   *   The CKEditor 5 available buttons markup.
-   *
-   * @private
-   */
-  Drupal.theme.ckeditor5AvailableButtons = ({ buttons }) => {
-    return `
-      <ul class="ckeditor5-toolbar-tray ckeditor5-toolbar-available__buttons" data-button-list="ckeditor5-toolbar-available-buttons" role="listbox" aria-orientation="horizontal" aria-labelledby="ckeditor5-toolbar-available-buttons-label">
-        ${buttons
-          .map((button) =>
-            Drupal.theme.ckeditor5Button({ button, listType: 'available' }),
-          )
-          .join('')}
-      </ul>
-    `;
-  };
-
-  /**
-   * Theme function for CKEditor 5 buttons.
-   *
-   * @param {Object} options
-   *  An object containing options.
-   * @param {Object} options.button
-   *   An object containing button options.
-   * @param {String} options.button.label
-   *   Button label.
-   * @param {String} options.button.id
-   *   Button id.
-   * @param {String} options.listType
-   *   The type of the list.
-   * @return {string}
-   *   The CKEditor 5 buttons markup.
-   *
-   * @private
-   */
-  Drupal.theme.ckeditor5Button = ({ button: { label, id }, listType }) => {
-    const buttonInstructions = {
-      divider: Drupal.t(
-        'Press the down arrow key to use this divider in the active button list',
-      ),
-      available: Drupal.t('Press the down arrow key to activate'),
-      active: Drupal.t(
-        'Press the up arrow key to deactivate. Use the right and left arrow keys to move position',
-      ),
-    };
-    const visuallyHiddenLabel = Drupal.t(`@listType button @label`, {
-      '@listType': listType !== 'divider' ? listType : 'available',
-      '@label': label,
-    });
-    return `
-      <li class="ckeditor5-toolbar-item ckeditor5-toolbar-item-${id}" role="option" tabindex="0" data-drupal-selector="ckeditor5-toolbar-button" data-id="${id}" data-label="${label}" data-divider="${
-      listType === 'divider'
-    }">
-        <span class="ckeditor5-toolbar-button ckeditor5-toolbar-button-${id}">
-          <span class="visually-hidden">${visuallyHiddenLabel}. ${
-      buttonInstructions[listType]
-    }</span>
-        </span>
-        <span class="ckeditor5-toolbar-tooltip" aria-hidden="true">${label} </span>
-      </li>
-    `;
-  };
-
-  /**
-   * Theme function for CKEditor 5 admin UI.
-   *
-   * @param {Object} options
-   *   An object containing options.
-   * @param {String} options.availableButtons
-   *   Markup for available buttons.
-   * @param {String} options.dividerButtons
-   *   Markup for divider buttons.
-   * @param {String} options.activeToolbar
-   *   Markup for active toolbar.
-   * @param {Array} options.helpMessage
-   *   An array of help messages.
-   * @return {string}
-   *   The CKEditor 5 admin UI markup.
-   *
-   * @private
-   */
-  Drupal.theme.ckeditor5Admin = ({
-    availableButtons,
-    dividerButtons,
-    activeToolbar,
-    helpMessage,
-  }) => {
-    return `
-    <div data-drupal-selector="ckeditor5-admin-help-message">
-      <p>${helpMessage.join('</p><p>')}</p>
-    </div>
-    <div class="ckeditor5-toolbar-disabled">
-      <div class="ckeditor5-toolbar-available">
-        <label id="ckeditor5-toolbar-available-buttons-label">${Drupal.t(
-          'Available buttons',
-        )}</label>
-        ${availableButtons}
-      </div>
-      <div class="ckeditor5-toolbar-divider">
-        <label id="ckeditor5-toolbar-divider-buttons-label">${Drupal.t(
-          'Button divider',
-        )}</label>
-        ${dividerButtons}
-      </div>
-    </div>
-    <div class="ckeditor5-toolbar-active">
-      <label id="ckeditor5-toolbar-active-buttons-label">${Drupal.t(
-        'Active toolbar',
-      )}</label>
-      ${activeToolbar}
-    </div>
-    `;
-  };
-
-  // Make a copy of the default filterStatus attach behaviors so it can be
-  // called within this module's override of it.
-  const originalFilterStatusAttach = Drupal.behaviors.filterStatus.attach;
-
-  // Overrides the default filterStatus to provided functionality needs
-  // specific to CKEditor 5.
-  Drupal.behaviors.filterStatus.attach = (context, settings) => {
-    const filterStatusCheckboxes = document.querySelectorAll(
-      '#filters-status-wrapper input.form-checkbox',
-    );
-
-    // CKEditor 5 has uses cases that require updating the filter settings via
-    // AJAX. When this happens, the checkboxes that enable filters must be
-    // reprocessed by the filterStatus behavior. For this to occur:
-    // 1. 'filter-status' must be removed from the element's once registry so
-    //    the process can run again and take into account any filter settings
-    //    elements that have been added or removed from the DOM.
-    //    @see core/assets/vendor/once/once.js
-    once.remove('filter-status', filterStatusCheckboxes);
-
-    // 2. Any listeners to the 'click.filterUpdate' event should be removed so
-    //    they do not conflict with event listeners that are added as part of
-    //    the AJAX refresh.
-    $(filterStatusCheckboxes).off('click.filterUpdate');
-
-    // Call the original behavior.
-    originalFilterStatusAttach(context, settings);
-  };
-
-  // Activates otherwise-inactive tabs that have form elements with validation
-  // errors.
-  // @todo Remove when https://www.drupal.org/project/drupal/issues/2911932 lands.
-  Drupal.behaviors.tabErrorsVisible = {
-    attach(context) {
-      context.querySelectorAll('details .form-item .error').forEach((item) => {
-        const details = item.closest('details');
-        if (details.style.display === 'none') {
-          const tabSelect = document.querySelector(`[href='#${details.id}']`);
-          if (tabSelect) {
-            tabSelect.click();
-          }
-        }
-      });
-    },
-  };
-})(Drupal, drupalSettings, jQuery, JSON, once, Sortable, tabbable);
diff --git a/core/modules/ckeditor5/js/ckeditor5.admin.js b/core/modules/ckeditor5/js/ckeditor5.admin.js
index 55a2ab5490b4..c996d2f506f1 100644
--- a/core/modules/ckeditor5/js/ckeditor5.admin.js
+++ b/core/modules/ckeditor5/js/ckeditor5.admin.js
@@ -1,71 +1,150 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-((Drupal, drupalSettings, $, JSON, once, Sortable, _ref) => {
-  let {
-    tabbable
-  } = _ref;
-  const toolbarHelp = [{
-    message: Drupal.t("The toolbar buttons that don't fit the user's browser window width will be grouped in a dropdown. If multiple toolbar rows are preferred, those can be configured by adding an explicit wrapping breakpoint wherever you want to start a new row.", null, {
-      context: 'CKEditor 5 toolbar help text, default, no explicit wrapping breakpoint'
-    }),
-    button: 'wrapping',
-    condition: false
-  }, {
-    message: Drupal.t('You have configured a multi-row toolbar by using an explicit wrapping breakpoint. This may not work well in narrow browser windows. To use automatic grouping, remove any of these divider buttons.', null, {
-      context: 'CKEditor 5 toolbar help text, with explicit wrapping breakpoint'
-    }),
-    button: 'wrapping',
-    condition: true
-  }];
+ * @file
+ * Provides the admin UI for CKEditor 5.
+ */
+
+((Drupal, drupalSettings, $, JSON, once, Sortable, { tabbable }) => {
+  const toolbarHelp = [
+    {
+      message: Drupal.t(
+        "The toolbar buttons that don't fit the user's browser window width will be grouped in a dropdown. If multiple toolbar rows are preferred, those can be configured by adding an explicit wrapping breakpoint wherever you want to start a new row.",
+        null,
+        {
+          context:
+            'CKEditor 5 toolbar help text, default, no explicit wrapping breakpoint',
+        },
+      ),
+      button: 'wrapping',
+      condition: false,
+    },
+    {
+      message: Drupal.t(
+        'You have configured a multi-row toolbar by using an explicit wrapping breakpoint. This may not work well in narrow browser windows. To use automatic grouping, remove any of these divider buttons.',
+        null,
+        {
+          context:
+            'CKEditor 5 toolbar help text, with explicit wrapping breakpoint',
+        },
+      ),
+      button: 'wrapping',
+      condition: true,
+    },
+  ];
+
+  /**
+   * Allows attaching listeners to a value.
+   *
+   * @type {Observable}
+   */
   const Observable = class {
+    /**
+     * Creates new Observable with a value.
+     *
+     * @param {*} value
+     *   The value to be observed.
+     */
     constructor(value) {
       this._listeners = [];
       this._value = value;
     }
 
+    /**
+     * Notifies subscribers about new values.
+     */
     notify() {
-      this._listeners.forEach(listener => listener(this._value));
+      this._listeners.forEach((listener) => listener(this._value));
     }
 
+    /**
+     * Subscribes a listener callback to changes.
+     *
+     * @param {Function} listener
+     *   The function to be called when a new value is set.
+     */
     subscribe(listener) {
       this._listeners.push(listener);
     }
 
+    /**
+     * The value of the observable.
+     *
+     * @return {*}
+     *   The current value.
+     */
     get value() {
       return this._value;
     }
 
+    /**
+     * Sets the value of the observable and notifies subscribers.
+     *
+     * @param {*} val
+     *   The new value of the observable.
+     */
     set value(val) {
       if (val !== this._value) {
         this._value = val;
         this.notify();
       }
     }
-
   };
 
+  /**
+   * Gets selected buttons.
+   *
+   * @param {Array} selected
+   *   The selected buttons retrieved from state.
+   * @param {Array} dividers
+   *   The available dividers.
+   * @param {Array} available
+   *   The available buttons.
+   * @return {Array}
+   *   An array containing selected buttons.
+   */
   const getSelectedButtons = (selected, dividers, available) => {
-    return selected.map(id => ({ ...[...dividers, ...available].find(button => button.id === id)
+    return selected.map((id) => ({
+      ...[...dividers, ...available].find((button) => button.id === id),
     }));
   };
 
+  /**
+   * Updates selected buttons to the textarea.
+   *
+   * @param {Array} selection
+   *   The current selection.
+   * @param {Element} textarea
+   *   The textarea element.
+   */
   const updateSelectedButtons = (selection, textarea) => {
     const newValue = JSON.stringify(selection);
+
     const priorValue = textarea.innerHTML;
     textarea.value = newValue;
     textarea.innerHTML = newValue;
-    textarea.dispatchEvent(new CustomEvent('change', {
-      detail: {
-        priorValue
-      }
-    }));
+
+    // The textarea is programmatically updated, so no native JavaScript
+    // event is triggered. Event listeners need to be aware of this config
+    // update, so a custom event is dispatched immediately after the
+    // config update.
+    textarea.dispatchEvent(
+      new CustomEvent('change', {
+        detail: {
+          priorValue,
+        },
+      }),
+    );
   };
 
+  /**
+   * Function to add button to selected buttons.
+   *
+   * @param {Observable} selection
+   *   The currently selected buttons.
+   * @param {Element} element
+   *   The element which is being added.
+   * @param {function} announceChange
+   *   Function to call to announce the change.
+   */
   const addToSelectedButtons = (selection, element, announceChange) => {
     const list = [...selection.value];
     list.push(element.dataset.id);
@@ -78,11 +157,23 @@
     }
   };
 
+  /**
+   * Function to remove button from selected buttons.
+   *
+   * @param {Observable} selection
+   *   The currently selected buttons.
+   * @param {Element} element
+   *   The element which is being removed.
+   * @param {function} announceChange
+   *   Function to call to announce the change.
+   */
   const removeFromSelectedButtons = (selection, element, announceChange) => {
     const list = [...selection.value];
-    const index = Array.from(element.parentElement.children).findIndex(child => {
-      return child === element;
-    });
+    const index = Array.from(element.parentElement.children).findIndex(
+      (child) => {
+        return child === element;
+      },
+    );
     list.splice(index, 1);
     selection.value = list;
 
@@ -93,23 +184,46 @@
     }
   };
 
+  /**
+   * Moves element within active buttons.
+   *
+   * @param {Observable} selection
+   *   The currently selected buttons.
+   * @param {Element} element
+   *   The element being moved.
+   * @param {Number} dir
+   *   The direction which the element is being moved.
+   */
   const moveWithinSelectedButtons = (selection, element, dir) => {
     const list = [...selection.value];
-    const index = Array.from(element.parentElement.children).findIndex(child => {
-      return child === element;
-    });
+    const index = Array.from(element.parentElement.children).findIndex(
+      (child) => {
+        return child === element;
+      },
+    );
+    // If moving up, check it is not the first, else check it is not the last.
     const condition = dir < 0 ? index > 0 : index < list.length - 1;
-
     if (condition) {
       list.splice(index + dir, 0, list.splice(index, 1)[0]);
       selection.value = list;
     }
   };
 
+  /**
+   * Copies element to active buttons.
+   *
+   * @param {Observable} selection
+   *   The currently selected buttons.
+   * @param {Element} element
+   *   The element to be copied.
+   * @param {Function} announceChange
+   *   A function to call to announce the change.
+   */
   const copyToActiveButtons = (selection, element, announceChange) => {
     const list = [...selection.value];
     list.push(element.dataset.id);
     selection.value = list;
+
     setTimeout(() => {
       if (announceChange) {
         announceChange(element.dataset.label);
@@ -117,277 +231,508 @@
     });
   };
 
+  /**
+   * Renders the CKEditor 5 button admin UI.
+   *
+   * @param {Element} root
+   *   The element where the admin UI should be rendered.
+   * @param {Observable} selectedButtons
+   *   An Observable object containing selected buttons.
+   * @param {Array} availableButtons
+   *   An array containing available buttons.
+   * @param {Array} dividerButtons
+   *   An array containing available divider buttons.
+   */
   const render = (root, selectedButtons, availableButtons, dividerButtons) => {
-    const toolbarHelpText = toolbarHelp.filter(helpItem => selectedButtons.value.includes(helpItem.button) === helpItem.condition).map(helpItem => helpItem.message);
-    const existingToolbarHelpText = document.querySelector('[data-drupal-selector="ckeditor5-admin-help-message"]');
-
-    if (existingToolbarHelpText && toolbarHelpText.join('').trim() !== existingToolbarHelpText.textContent.trim()) {
+    const toolbarHelpText = toolbarHelp
+      .filter(
+        (helpItem) =>
+          selectedButtons.value.includes(helpItem.button) ===
+          helpItem.condition,
+      )
+      .map((helpItem) => helpItem.message);
+
+    // Get the existing toolbar help message.
+    const existingToolbarHelpText = document.querySelector(
+      '[data-drupal-selector="ckeditor5-admin-help-message"]',
+    );
+
+    // If the existing toolbar help message does not match the message that is
+    // about to be rendered, it is new information that should be conveyed to
+    // assistive tech via announce().
+    if (
+      existingToolbarHelpText &&
+      toolbarHelpText.join('').trim() !==
+        existingToolbarHelpText.textContent.trim()
+    ) {
       Drupal.announce(toolbarHelpText.join(' '));
     }
 
     root.innerHTML = Drupal.theme.ckeditor5Admin({
       availableButtons: Drupal.theme.ckeditor5AvailableButtons({
-        buttons: availableButtons.filter(button => !selectedButtons.value.includes(button.id))
+        buttons: availableButtons.filter(
+          (button) => !selectedButtons.value.includes(button.id),
+        ),
       }),
       dividerButtons: Drupal.theme.ckeditor5DividerButtons({
-        buttons: dividerButtons
+        buttons: dividerButtons,
       }),
       activeToolbar: Drupal.theme.ckeditor5SelectedButtons({
-        buttons: getSelectedButtons(selectedButtons.value, dividerButtons, availableButtons)
+        buttons: getSelectedButtons(
+          selectedButtons.value,
+          dividerButtons,
+          availableButtons,
+        ),
       }),
-      helpMessage: toolbarHelpText
+      helpMessage: toolbarHelpText,
     });
-    new Sortable(root.querySelector('[data-button-list="ckeditor5-toolbar-active-buttons"]'), {
-      group: {
-        name: 'toolbar',
-        put: ['divider', 'available']
+
+    // Create sortable groups for available buttons, current toolbar items,
+    // and dividers.
+    new Sortable(
+      root.querySelector(
+        '[data-button-list="ckeditor5-toolbar-active-buttons"]',
+      ),
+      {
+        group: { name: 'toolbar', put: ['divider', 'available'] },
+        sort: true,
+        store: {
+          set: (sortable) => {
+            selectedButtons.value = sortable.toArray();
+          },
+        },
       },
-      sort: true,
-      store: {
-        set: sortable => {
-          selectedButtons.value = sortable.toArray();
-        }
-      }
-    });
-    const toolbarAvailableButtons = new Sortable(root.querySelector('[data-button-list="ckeditor5-toolbar-available-buttons"]'), {
-      group: {
-        name: 'available',
-        put: ['toolbar']
+    );
+    const toolbarAvailableButtons = new Sortable(
+      root.querySelector(
+        '[data-button-list="ckeditor5-toolbar-available-buttons"]',
+      ),
+      {
+        group: { name: 'available', put: ['toolbar'] },
+        sort: false,
+        onAdd: (event) => {
+          // If the moved item is a divider, it should not be added to
+          // the available buttons list.
+          if (
+            dividerButtons.find(
+              (dividerButton) => dividerButton.id === event.item.dataset.id,
+            )
+          ) {
+            const { newIndex } = event;
+            setTimeout(() => {
+              // Remove the divider button from the available buttons
+              // list. Draggable reassesses the lists during each drag
+              // event, so the DOM removal should not be disruptive.
+              document
+                .querySelectorAll('.ckeditor5-toolbar-available__buttons li')
+                [newIndex].remove();
+            });
+          }
+        },
       },
-      sort: false,
-      onAdd: event => {
-        if (dividerButtons.find(dividerButton => dividerButton.id === event.item.dataset.id)) {
-          const {
-            newIndex
-          } = event;
-          setTimeout(() => {
-            document.querySelectorAll('.ckeditor5-toolbar-available__buttons li')[newIndex].remove();
-          });
-        }
-      }
-    });
-    new Sortable(root.querySelector('[data-button-list="ckeditor5-toolbar-divider-buttons"]'), {
-      group: {
-        name: 'divider',
-        put: false,
-        pull: 'clone',
-        sort: 'false'
-      }
-    });
-    root.querySelectorAll('[data-drupal-selector="ckeditor5-toolbar-button"]').forEach(element => {
-      const expandButton = event => {
-        event.currentTarget.querySelectorAll('.ckeditor5-toolbar-button').forEach(buttonElement => {
-          buttonElement.setAttribute('data-expanded', true);
-        });
-      };
-
-      const retractButton = event => {
-        event.currentTarget.querySelectorAll('.ckeditor5-toolbar-button').forEach(buttonElement => {
-          buttonElement.setAttribute('data-expanded', false);
-        });
-      };
-
-      element.addEventListener('mouseenter', expandButton);
-      element.addEventListener('focus', expandButton);
-      element.addEventListener('mouseleave', retractButton);
-      element.addEventListener('blur', retractButton);
-      element.addEventListener('keyup', event => {
-        const supportedKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
-        const dir = document.documentElement.dir;
-
-        if (supportedKeys.includes(event.key)) {
-          if (event.currentTarget.dataset.divider.toLowerCase() === 'true') {
-            switch (event.key) {
-              case 'ArrowDown':
-                {
-                  const announceChange = name => {
-                    Drupal.announce(Drupal.t('Button @name has been copied to the active toolbar.', {
-                      '@name': name
-                    }));
+    );
+    new Sortable(
+      root.querySelector(
+        '[data-button-list="ckeditor5-toolbar-divider-buttons"]',
+      ),
+      {
+        group: { name: 'divider', put: false, pull: 'clone', sort: 'false' },
+      },
+    );
+
+    root
+      .querySelectorAll('[data-drupal-selector="ckeditor5-toolbar-button"]')
+      .forEach((element) => {
+        const expandButton = (event) => {
+          event.currentTarget
+            .querySelectorAll('.ckeditor5-toolbar-button')
+            .forEach((buttonElement) => {
+              buttonElement.setAttribute('data-expanded', true);
+            });
+        };
+        const retractButton = (event) => {
+          event.currentTarget
+            .querySelectorAll('.ckeditor5-toolbar-button')
+            .forEach((buttonElement) => {
+              buttonElement.setAttribute('data-expanded', false);
+            });
+        };
+        element.addEventListener('mouseenter', expandButton);
+        element.addEventListener('focus', expandButton);
+        element.addEventListener('mouseleave', retractButton);
+        element.addEventListener('blur', retractButton);
+
+        element.addEventListener('keyup', (event) => {
+          // Keys supported by the admin UI. Depending on the element that is
+          // triggering the event, the event could trigger changes in the state.
+          // Changes to the state trigger re-rendering of the admin UI, which
+          // means that for consistent navigation, each action modifying state
+          // needs to set focus back on the button that is being moved. The state
+          // change also triggers an AJAX request which re-renders parts of the
+          // form, and moves the focus to the triggering form element, meaning
+          // that focus needs to be set back on the button again.
+          const supportedKeys = [
+            'ArrowLeft',
+            'ArrowRight',
+            'ArrowUp',
+            'ArrowDown',
+          ];
+          const dir = document.documentElement.dir;
+          if (supportedKeys.includes(event.key)) {
+            if (event.currentTarget.dataset.divider.toLowerCase() === 'true') {
+              switch (event.key) {
+                case 'ArrowDown': {
+                  const announceChange = (name) => {
+                    Drupal.announce(
+                      Drupal.t(
+                        'Button @name has been copied to the active toolbar.',
+                        { '@name': name },
+                      ),
+                    );
                   };
-
-                  copyToActiveButtons(selectedButtons, event.currentTarget, announceChange);
-                  root.querySelector('[data-button-list="ckeditor5-toolbar-active-buttons"] li:last-child').focus();
+                  copyToActiveButtons(
+                    selectedButtons,
+                    event.currentTarget,
+                    announceChange,
+                  );
+                  // Focus the last button since new button is always added to the
+                  // end of the list.
+                  root
+                    .querySelector(
+                      '[data-button-list="ckeditor5-toolbar-active-buttons"] li:last-child',
+                    )
+                    .focus();
                   break;
                 }
-            }
-          } else if (selectedButtons.value.includes(event.currentTarget.dataset.id)) {
-            const index = Array.from(element.parentElement.children).findIndex(child => {
-              return child === element;
-            });
-
-            switch (event.key) {
-              case 'ArrowLeft':
-                {
+              }
+            } else if (
+              selectedButtons.value.includes(event.currentTarget.dataset.id)
+            ) {
+              const index = Array.from(
+                element.parentElement.children,
+              ).findIndex((child) => {
+                return child === element;
+              });
+              switch (event.key) {
+                case 'ArrowLeft': {
                   const leftOffset = dir === 'ltr' ? -1 : 1;
-                  moveWithinSelectedButtons(selectedButtons, event.currentTarget, leftOffset);
-                  root.querySelectorAll('[data-button-list="ckeditor5-toolbar-active-buttons"] li')[index + leftOffset].focus();
+                  moveWithinSelectedButtons(
+                    selectedButtons,
+                    event.currentTarget,
+                    leftOffset,
+                  );
+                  // Move focus to left or right from the current index depending
+                  // on current language direction. Use index instead of the
+                  // data-id because dividers don't have a unique ID.
+                  root
+                    .querySelectorAll(
+                      '[data-button-list="ckeditor5-toolbar-active-buttons"] li',
+                    )
+                    [index + leftOffset].focus();
                   break;
                 }
-
-              case 'ArrowRight':
-                {
+                case 'ArrowRight': {
                   const rightOffset = dir === 'ltr' ? 1 : -1;
-                  moveWithinSelectedButtons(selectedButtons, event.currentTarget, rightOffset);
-                  root.querySelectorAll('[data-button-list="ckeditor5-toolbar-active-buttons"] li')[index + rightOffset].focus();
+                  moveWithinSelectedButtons(
+                    selectedButtons,
+                    event.currentTarget,
+                    rightOffset,
+                  );
+                  // Move focus to right or left from the current index depending
+                  // on current language direction. Use index instead of the
+                  // data-id because dividers don't have a unique ID.
+                  root
+                    .querySelectorAll(
+                      '[data-button-list="ckeditor5-toolbar-active-buttons"] li',
+                    )
+                    [index + rightOffset].focus();
                   break;
                 }
-
-              case 'ArrowUp':
-                {
-                  const announceChange = name => {
-                    Drupal.announce(Drupal.t('Button @name has been removed from the active toolbar.', {
-                      '@name': name
-                    }));
+                case 'ArrowUp': {
+                  const announceChange = (name) => {
+                    Drupal.announce(
+                      Drupal.t(
+                        'Button @name has been removed from the active toolbar.',
+                        { '@name': name },
+                      ),
+                    );
                   };
-
-                  removeFromSelectedButtons(selectedButtons, event.currentTarget, announceChange);
-
-                  if (!dividerButtons.find(dividerButton => event.currentTarget.dataset.id === dividerButton.id)) {
-                    root.querySelector(`[data-button-list="ckeditor5-toolbar-available-buttons"] [data-id="${event.currentTarget.dataset.id}"]`).focus();
+                  removeFromSelectedButtons(
+                    selectedButtons,
+                    event.currentTarget,
+                    announceChange,
+                  );
+                  // Focus only if the button wasn't a divider because dividers
+                  // are simply removed from the active buttons instead of moving
+                  // to another list.
+                  if (
+                    !dividerButtons.find(
+                      (dividerButton) =>
+                        event.currentTarget.dataset.id === dividerButton.id,
+                    )
+                  ) {
+                    // Focus button based on the data-id attribute from the
+                    // available buttons list.
+                    root
+                      .querySelector(
+                        `[data-button-list="ckeditor5-toolbar-available-buttons"] [data-id="${event.currentTarget.dataset.id}"]`,
+                      )
+                      .focus();
                   }
-
                   break;
                 }
-            }
-          } else if (toolbarAvailableButtons.toArray().includes(event.currentTarget.dataset.id)) {
-            switch (event.key) {
-              case 'ArrowDown':
-                {
-                  const announceChange = name => {
-                    Drupal.announce(Drupal.t('Button @name has been moved to the active toolbar.', {
-                      '@name': name
-                    }));
+              }
+            } else if (
+              toolbarAvailableButtons
+                .toArray()
+                .includes(event.currentTarget.dataset.id)
+            ) {
+              switch (event.key) {
+                case 'ArrowDown': {
+                  const announceChange = (name) => {
+                    Drupal.announce(
+                      Drupal.t(
+                        'Button @name has been moved to the active toolbar.',
+                        { '@name': name },
+                      ),
+                    );
                   };
-
-                  addToSelectedButtons(selectedButtons, event.currentTarget, announceChange);
-                  root.querySelector('[data-button-list="ckeditor5-toolbar-active-buttons"] li:last-child').focus();
+                  addToSelectedButtons(
+                    selectedButtons,
+                    event.currentTarget,
+                    announceChange,
+                  );
+                  // Focus the last button since new button is always added to the
+                  // end of the list.
+                  root
+                    .querySelector(
+                      '[data-button-list="ckeditor5-toolbar-active-buttons"] li:last-child',
+                    )
+                    .focus();
                   break;
                 }
+              }
             }
           }
-        }
+        });
       });
-    });
   };
 
+  /**
+   * Attach CKEditor 5 admin UI.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches admin app to edit the CKEditor 5 toolbar.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches admin app from the CKEditor 5 configuration form on 'unload'.
+   */
   Drupal.behaviors.ckeditor5Admin = {
     attach(context) {
-      once('ckeditor5-admin-toolbar', '#ckeditor5-toolbar-app').forEach(container => {
-        const selectedTextarea = context.querySelector('#ckeditor5-toolbar-buttons-selected');
-        const available = Object.entries(JSON.parse(context.querySelector('#ckeditor5-toolbar-buttons-available').innerHTML)).map(_ref2 => {
-          let [name, attrs] = _ref2;
-          return {
-            name,
-            id: name,
-            ...attrs
+      once('ckeditor5-admin-toolbar', '#ckeditor5-toolbar-app').forEach(
+        (container) => {
+          const selectedTextarea = context.querySelector(
+            '#ckeditor5-toolbar-buttons-selected',
+          );
+          const available = Object.entries(
+            JSON.parse(
+              context.querySelector('#ckeditor5-toolbar-buttons-available')
+                .innerHTML,
+            ),
+          ).map(([name, attrs]) => ({ name, id: name, ...attrs }));
+          const dividers = [
+            {
+              id: 'divider',
+              name: '|',
+              label: Drupal.t('Divider'),
+            },
+            {
+              id: 'wrapping',
+              name: '-',
+              label: Drupal.t('Wrapping'),
+            },
+          ];
+
+          // Selected is used for managing the state. Sortable is handling updates
+          // to the state when the system is operated by mouse. There are
+          // functions making direct modifications to the state when system is
+          // operated by keyboard.
+          const selected = new Observable(
+            JSON.parse(selectedTextarea.innerHTML).map((name) => {
+              return [...dividers, ...available].find((button) => {
+                return button.name === name;
+              }).id;
+            }),
+          );
+
+          const mapSelection = (selection) => {
+            return selection.map((id) => {
+              return [...dividers, ...available].find((button) => {
+                return button.id === id;
+              }).name;
+            });
           };
-        });
-        const dividers = [{
-          id: 'divider',
-          name: '|',
-          label: Drupal.t('Divider')
-        }, {
-          id: 'wrapping',
-          name: '-',
-          label: Drupal.t('Wrapping')
-        }];
-        const selected = new Observable(JSON.parse(selectedTextarea.innerHTML).map(name => {
-          return [...dividers, ...available].find(button => {
-            return button.name === name;
-          }).id;
-        }));
-
-        const mapSelection = selection => {
-          return selection.map(id => {
-            return [...dividers, ...available].find(button => {
-              return button.id === id;
-            }).name;
+          // Whenever the state is changed, update the textarea with the changes.
+          // This will also trigger re-render of the admin UI to reinitialize the
+          // Sortable state.
+          selected.subscribe((selection) => {
+            updateSelectedButtons(mapSelection(selection), selectedTextarea);
+            render(container, selected, available, dividers);
           });
-        };
 
-        selected.subscribe(selection => {
-          updateSelectedButtons(mapSelection(selection), selectedTextarea);
+          [
+            context.querySelector('#ckeditor5-toolbar-buttons-available'),
+            context.querySelector('[class*="editor-settings-toolbar-items"]'),
+          ]
+            .filter((el) => el)
+            .forEach((el) => {
+              el.classList.add('visually-hidden');
+            });
+
           render(container, selected, available, dividers);
-        });
-        [context.querySelector('#ckeditor5-toolbar-buttons-available'), context.querySelector('[class*="editor-settings-toolbar-items"]')].filter(el => el).forEach(el => {
-          el.classList.add('visually-hidden');
-        });
-        render(container, selected, available, dividers);
-      });
-      once('safari-focus-fix', '.ckeditor5-toolbar-item').forEach(item => {
-        item.addEventListener('keydown', e => {
+        },
+      );
+      // Safari's focus outlines take into account absolute positioned elements.
+      // When a toolbar option is blurred, the portion of the focus outline
+      // surrounding the absolutely positioned tooltip does not go away. To
+      // prevent keyboard navigation users from seeing outline artifacts for
+      // every option they've tabbed through, we provide a keydown listener
+      // that can catch blur-causing events before the blur happens. If the
+      // tooltip is hidden before the blur event, the outline will disappear
+      // correctly.
+      once('safari-focus-fix', '.ckeditor5-toolbar-item').forEach((item) => {
+        item.addEventListener('keydown', (e) => {
           const keyCodeDirections = {
             9: 'tab',
             37: 'left',
             38: 'up',
             39: 'right',
-            40: 'down'
+            40: 'down',
           };
-
-          if (['tab', 'left', 'up', 'right', 'down'].includes(keyCodeDirections[e.keyCode])) {
+          if (
+            ['tab', 'left', 'up', 'right', 'down'].includes(
+              keyCodeDirections[e.keyCode],
+            )
+          ) {
             let hideTip = false;
-            const isActive = e.target.closest('[data-button-list="ckeditor5-toolbar-active__buttons"]');
-
+            const isActive = e.target.closest(
+              '[data-button-list="ckeditor5-toolbar-active__buttons"]',
+            );
             if (isActive) {
-              if (['tab', 'left', 'up', 'right'].includes(keyCodeDirections[e.keyCode])) {
+              if (
+                ['tab', 'left', 'up', 'right'].includes(
+                  keyCodeDirections[e.keyCode],
+                )
+              ) {
                 hideTip = true;
               }
             } else if (['tab', 'down'].includes(keyCodeDirections[e.keyCode])) {
               hideTip = true;
             }
-
             if (hideTip) {
-              e.target.querySelector('[data-expanded]').setAttribute('data-expanded', 'false');
+              e.target
+                .querySelector('[data-expanded]')
+                .setAttribute('data-expanded', 'false');
             }
           }
         });
       });
 
-      const updateUiStateStorage = states => {
-        const form = document.querySelector('#filter-format-edit-form, #filter-format-add-form');
-        const currentStates = form.hasAttribute('data-drupal-ui-state') ? JSON.parse(form.getAttribute('data-drupal-ui-state')) : {};
-        form.setAttribute('data-drupal-ui-state', JSON.stringify({ ...currentStates,
-          ...states
-        }));
+      /**
+       * Updates the UI state info in the form's 'data-drupal-ui-state' attribute.
+       *
+       * @param {object} states
+       *   An object with one or more items with the structure { ui-property: stored-value }
+       */
+      const updateUiStateStorage = (states) => {
+        const form = document.querySelector(
+          '#filter-format-edit-form, #filter-format-add-form',
+        );
+
+        // Get the current stored UI state as an object.
+        const currentStates = form.hasAttribute('data-drupal-ui-state')
+          ? JSON.parse(form.getAttribute('data-drupal-ui-state'))
+          : {};
+
+        // Store the updated UI state object as an object literal in the parent
+        // form's 'data-drupal-ui-state' attribute.
+        form.setAttribute(
+          'data-drupal-ui-state',
+          JSON.stringify({ ...currentStates, ...states }),
+        );
       };
 
-      const getUiStateStorage = property => {
-        const form = document.querySelector('#filter-format-edit-form, #filter-format-add-form');
+      /**
+       * Gets a stored UI state property.
+       *
+       * @param {string} property
+       *   The UI state property to retrieve the value of.
+       *
+       * @return {string|null}
+       *   When present, the stored value of the property.
+       */
+      const getUiStateStorage = (property) => {
+        const form = document.querySelector(
+          '#filter-format-edit-form, #filter-format-add-form',
+        );
 
         if (form === null) {
           return;
         }
 
-        return form.hasAttribute('data-drupal-ui-state') ? JSON.parse(form.getAttribute('data-drupal-ui-state'))[property] : null;
+        // Parse the object literal stored in the form's 'data-drupal-ui-state'
+        // attribute and return the value of the object property that matches
+        // the 'property' argument.
+        return form.hasAttribute('data-drupal-ui-state')
+          ? JSON.parse(form.getAttribute('data-drupal-ui-state'))[property]
+          : null;
       };
 
-      once('ui-state-storage', '#filter-format-edit-form, #filter-format-add-form').forEach(form => {
+      // Add an attribute to the parent form for storing UI states, so this
+      // information can be retrieved after AJAX rebuilds.
+      once(
+        'ui-state-storage',
+        '#filter-format-edit-form, #filter-format-add-form',
+      ).forEach((form) => {
         form.setAttribute('data-drupal-ui-state', JSON.stringify({}));
       });
 
-      const maintainActiveVerticalTab = verticalTabs => {
+      /**
+       * Maintains the active vertical tab after AJAX rebuild.
+       *
+       * @param {Element} verticalTabs
+       *   The vertical tabs element.
+       */
+      const maintainActiveVerticalTab = (verticalTabs) => {
         const id = verticalTabs.id;
-        const activeTab = getUiStateStorage(`${id}-active-tab`);
 
+        // If the UI state storage has an active tab, click that tab.
+        const activeTab = getUiStateStorage(`${id}-active-tab`);
         if (activeTab) {
           setTimeout(() => {
             const activeTabLink = document.querySelector(activeTab);
             activeTabLink.click();
 
+            // Only change focus on the plugin-settings-wrapper element.
             if (id !== 'plugin-settings-wrapper') {
               return;
             }
-
+            // If the current focused element is not the body, then the user
+            // navigated away from the vertical tab area and is somewhere else
+            // within the form. Do not change the current focus.
             if (document.activeElement !== document.body) {
               return;
             }
-
-            const targetTabPane = document.querySelector(activeTabLink.getAttribute('href'));
-
+            // If the active element is the body then we can assume that the
+            // focus was on an element that was replaced by an ajax command.
+            // If that is the case restore the focus to the active tab that
+            // was just rebuilt.
+            const targetTabPane = document.querySelector(
+              activeTabLink.getAttribute('href'),
+            );
             if (targetTabPane) {
               const tabbableElements = tabbable(targetTabPane);
-
               if (tabbableElements.length) {
                 tabbableElements[0].focus();
               }
@@ -395,70 +740,108 @@
           });
         }
 
-        verticalTabs.querySelectorAll('.vertical-tabs__menu').forEach(tab => {
-          tab.addEventListener('click', e => {
+        // Add click listener that adds any tab click into UI storage.
+        verticalTabs.querySelectorAll('.vertical-tabs__menu').forEach((tab) => {
+          tab.addEventListener('click', (e) => {
             const state = {};
-            const href = e.target.closest('[href]').getAttribute('href').split('--')[0];
+            const href = e.target
+              .closest('[href]')
+              .getAttribute('href')
+              .split('--')[0];
             state[`${id}-active-tab`] = `#${id} [href^='${href}']`;
             updateUiStateStorage(state);
           });
         });
       };
 
-      once('maintainActiveVerticalTab', '#plugin-settings-wrapper, #filter-settings-wrapper').forEach(maintainActiveVerticalTab);
-      const selectedButtons = document.querySelector('#ckeditor5-toolbar-buttons-selected');
-      once('textarea-listener', selectedButtons).forEach(textarea => {
-        textarea.addEventListener('change', e => {
-          const buttonName = document.activeElement.getAttribute('data-id');
+      once(
+        'maintainActiveVerticalTab',
+        '#plugin-settings-wrapper, #filter-settings-wrapper',
+      ).forEach(maintainActiveVerticalTab);
+
+      // Add listeners to maintain focus after AJAX rebuilds.
+      const selectedButtons = document.querySelector(
+        '#ckeditor5-toolbar-buttons-selected',
+      );
 
+      once('textarea-listener', selectedButtons).forEach((textarea) => {
+        textarea.addEventListener('change', (e) => {
+          const buttonName = document.activeElement.getAttribute('data-id');
           if (!buttonName) {
+            // If there is no 'data-id' attribute, then the config
+            // is happening via mouse.
             return;
           }
-
           let focusSelector = '';
 
+          // Divider elements are treated differently as there can be multiple
+          // elements with the same button name.
           if (['divider', 'wrapping'].includes(buttonName)) {
             const oldConfig = JSON.parse(e.detail.priorValue);
             const newConfig = JSON.parse(e.target.innerHTML);
 
+            // If the divider is being removed from active buttons, it does not
+            // 'move' anywhere. Move focus to the prior active button
             if (oldConfig.length > newConfig.length) {
               for (let item = 0; item < newConfig.length; item++) {
                 if (newConfig[item] !== oldConfig[item]) {
-                  focusSelector = `[data-button-list="ckeditor5-toolbar-active-buttons"] li:nth-child(${Math.min(item - 1, 0)})`;
+                  focusSelector = `[data-button-list="ckeditor5-toolbar-active-buttons"] li:nth-child(${Math.min(
+                    item - 1,
+                    0,
+                  )})`;
                   break;
                 }
               }
             } else if (oldConfig.length < newConfig.length) {
-              focusSelector = '[data-button-list="ckeditor5-toolbar-active-buttons"] li:last-child';
+              // If the divider is being added, it will be the last active item.
+              focusSelector =
+                '[data-button-list="ckeditor5-toolbar-active-buttons"] li:last-child';
             } else {
-              document.querySelectorAll(`[data-button-list="ckeditor5-toolbar-active-buttons"] [data-id='${buttonName}']`).forEach((divider, index) => {
-                if (divider === document.activeElement) {
-                  focusSelector = `${buttonName}|${index}`;
-                }
-              });
+              // When moving a dividers position within the active buttons.
+              document
+                .querySelectorAll(
+                  `[data-button-list="ckeditor5-toolbar-active-buttons"] [data-id='${buttonName}']`,
+                )
+                .forEach((divider, index) => {
+                  if (divider === document.activeElement) {
+                    focusSelector = `${buttonName}|${index}`;
+                  }
+                });
             }
           } else {
             focusSelector = `[data-id='${buttonName}']`;
           }
 
-          updateUiStateStorage({
-            focusSelector
-          });
+          // Store the focus selector in an attribute on the form itself, which
+          // will not be overwritten after the AJAX rebuild. This makes it
+          // the value available to the textarea focus listener that is
+          // triggered after the AJAX rebuild.
+          updateUiStateStorage({ focusSelector });
         });
+
         textarea.addEventListener('focus', () => {
+          // The selector that should receive focus is stored in the parent
+          // form element. Move focus to that selector.
           const focusSelector = getUiStateStorage('focusSelector');
 
           if (focusSelector) {
+            // If focusSelector includes '|', it is a separator that is being
+            // moved within the active button list. Different logic us used to
+            // determine focus since there can be multiple separators of the
+            // same type within the active buttons list.
             if (focusSelector.includes('|')) {
               const [buttonName, count] = focusSelector.split('|');
-              document.querySelectorAll(`[data-button-list="ckeditor5-toolbar-active-buttons"] [data-id='${buttonName}']`).forEach((item, index) => {
-                if (index === parseInt(count, 10)) {
-                  item.focus();
-                }
-              });
+              document
+                .querySelectorAll(
+                  `[data-button-list="ckeditor5-toolbar-active-buttons"] [data-id='${buttonName}']`,
+                )
+                .forEach((item, index) => {
+                  if (index === parseInt(count, 10)) {
+                    item.focus();
+                  }
+                });
             } else {
               const toFocus = document.querySelector(focusSelector);
-
               if (toFocus) {
                 toFocus.focus();
               }
@@ -466,130 +849,221 @@
           }
         });
       });
-    }
-
+    },
   };
 
-  Drupal.theme.ckeditor5SelectedButtons = _ref3 => {
-    let {
-      buttons
-    } = _ref3;
+  /**
+   * Theme function for CKEditor 5 selected buttons.
+   *
+   * @param {Object} options
+   *   An object containing options.
+   * @param {Array} options.buttons
+   *   An array of selected buttons.
+   * @return {string}
+   *   The selected buttons markup.
+   *
+   * @private
+   */
+  Drupal.theme.ckeditor5SelectedButtons = ({ buttons }) => {
     return `
       <ul class="ckeditor5-toolbar-tray ckeditor5-toolbar-active__buttons" data-button-list="ckeditor5-toolbar-active-buttons" role="listbox" aria-orientation="horizontal" aria-labelledby="ckeditor5-toolbar-active-buttons-label">
-        ${buttons.map(button => Drupal.theme.ckeditor5Button({
-      button,
-      listType: 'active'
-    })).join('')}
+        ${buttons
+          .map((button) =>
+            Drupal.theme.ckeditor5Button({ button, listType: 'active' }),
+          )
+          .join('')}
       </ul>
     `;
   };
 
-  Drupal.theme.ckeditor5DividerButtons = _ref4 => {
-    let {
-      buttons
-    } = _ref4;
+  /**
+   * Theme function for CKEditor 5 divider buttons.
+   *
+   * @param {Object} options
+   *   An object containing options.
+   * @param {Array} options.buttons
+   *   An array of divider buttons.
+   * @return {string}
+   *   The CKEditor 5 divider buttons markup.
+   *
+   * @private
+   */
+  Drupal.theme.ckeditor5DividerButtons = ({ buttons }) => {
     return `
       <ul class="ckeditor5-toolbar-tray ckeditor5-toolbar-divider__buttons" data-button-list="ckeditor5-toolbar-divider-buttons" role="listbox" aria-orientation="horizontal" aria-labelledby="ckeditor5-toolbar-divider-buttons-label">
-        ${buttons.map(button => Drupal.theme.ckeditor5Button({
-      button,
-      listType: 'divider'
-    })).join('')}
+        ${buttons
+          .map((button) =>
+            Drupal.theme.ckeditor5Button({ button, listType: 'divider' }),
+          )
+          .join('')}
       </ul>
     `;
   };
 
-  Drupal.theme.ckeditor5AvailableButtons = _ref5 => {
-    let {
-      buttons
-    } = _ref5;
+  /**
+   * Theme function for CKEditor 5 available buttons.
+   *
+   * @param {Object} options
+   *   An object containing options.
+   * @param {Array} options.buttons
+   *   An array of available buttons.
+   * @return {string}
+   *   The CKEditor 5 available buttons markup.
+   *
+   * @private
+   */
+  Drupal.theme.ckeditor5AvailableButtons = ({ buttons }) => {
     return `
       <ul class="ckeditor5-toolbar-tray ckeditor5-toolbar-available__buttons" data-button-list="ckeditor5-toolbar-available-buttons" role="listbox" aria-orientation="horizontal" aria-labelledby="ckeditor5-toolbar-available-buttons-label">
-        ${buttons.map(button => Drupal.theme.ckeditor5Button({
-      button,
-      listType: 'available'
-    })).join('')}
+        ${buttons
+          .map((button) =>
+            Drupal.theme.ckeditor5Button({ button, listType: 'available' }),
+          )
+          .join('')}
       </ul>
     `;
   };
 
-  Drupal.theme.ckeditor5Button = _ref6 => {
-    let {
-      button: {
-        label,
-        id
-      },
-      listType
-    } = _ref6;
+  /**
+   * Theme function for CKEditor 5 buttons.
+   *
+   * @param {Object} options
+   *  An object containing options.
+   * @param {Object} options.button
+   *   An object containing button options.
+   * @param {String} options.button.label
+   *   Button label.
+   * @param {String} options.button.id
+   *   Button id.
+   * @param {String} options.listType
+   *   The type of the list.
+   * @return {string}
+   *   The CKEditor 5 buttons markup.
+   *
+   * @private
+   */
+  Drupal.theme.ckeditor5Button = ({ button: { label, id }, listType }) => {
     const buttonInstructions = {
-      divider: Drupal.t('Press the down arrow key to use this divider in the active button list'),
+      divider: Drupal.t(
+        'Press the down arrow key to use this divider in the active button list',
+      ),
       available: Drupal.t('Press the down arrow key to activate'),
-      active: Drupal.t('Press the up arrow key to deactivate. Use the right and left arrow keys to move position')
+      active: Drupal.t(
+        'Press the up arrow key to deactivate. Use the right and left arrow keys to move position',
+      ),
     };
     const visuallyHiddenLabel = Drupal.t(`@listType button @label`, {
       '@listType': listType !== 'divider' ? listType : 'available',
-      '@label': label
+      '@label': label,
     });
     return `
-      <li class="ckeditor5-toolbar-item ckeditor5-toolbar-item-${id}" role="option" tabindex="0" data-drupal-selector="ckeditor5-toolbar-button" data-id="${id}" data-label="${label}" data-divider="${listType === 'divider'}">
+      <li class="ckeditor5-toolbar-item ckeditor5-toolbar-item-${id}" role="option" tabindex="0" data-drupal-selector="ckeditor5-toolbar-button" data-id="${id}" data-label="${label}" data-divider="${
+      listType === 'divider'
+    }">
         <span class="ckeditor5-toolbar-button ckeditor5-toolbar-button-${id}">
-          <span class="visually-hidden">${visuallyHiddenLabel}. ${buttonInstructions[listType]}</span>
+          <span class="visually-hidden">${visuallyHiddenLabel}. ${
+      buttonInstructions[listType]
+    }</span>
         </span>
         <span class="ckeditor5-toolbar-tooltip" aria-hidden="true">${label} </span>
       </li>
     `;
   };
 
-  Drupal.theme.ckeditor5Admin = _ref7 => {
-    let {
-      availableButtons,
-      dividerButtons,
-      activeToolbar,
-      helpMessage
-    } = _ref7;
+  /**
+   * Theme function for CKEditor 5 admin UI.
+   *
+   * @param {Object} options
+   *   An object containing options.
+   * @param {String} options.availableButtons
+   *   Markup for available buttons.
+   * @param {String} options.dividerButtons
+   *   Markup for divider buttons.
+   * @param {String} options.activeToolbar
+   *   Markup for active toolbar.
+   * @param {Array} options.helpMessage
+   *   An array of help messages.
+   * @return {string}
+   *   The CKEditor 5 admin UI markup.
+   *
+   * @private
+   */
+  Drupal.theme.ckeditor5Admin = ({
+    availableButtons,
+    dividerButtons,
+    activeToolbar,
+    helpMessage,
+  }) => {
     return `
     <div data-drupal-selector="ckeditor5-admin-help-message">
       <p>${helpMessage.join('</p><p>')}</p>
     </div>
     <div class="ckeditor5-toolbar-disabled">
       <div class="ckeditor5-toolbar-available">
-        <label id="ckeditor5-toolbar-available-buttons-label">${Drupal.t('Available buttons')}</label>
+        <label id="ckeditor5-toolbar-available-buttons-label">${Drupal.t(
+          'Available buttons',
+        )}</label>
         ${availableButtons}
       </div>
       <div class="ckeditor5-toolbar-divider">
-        <label id="ckeditor5-toolbar-divider-buttons-label">${Drupal.t('Button divider')}</label>
+        <label id="ckeditor5-toolbar-divider-buttons-label">${Drupal.t(
+          'Button divider',
+        )}</label>
         ${dividerButtons}
       </div>
     </div>
     <div class="ckeditor5-toolbar-active">
-      <label id="ckeditor5-toolbar-active-buttons-label">${Drupal.t('Active toolbar')}</label>
+      <label id="ckeditor5-toolbar-active-buttons-label">${Drupal.t(
+        'Active toolbar',
+      )}</label>
       ${activeToolbar}
     </div>
     `;
   };
 
+  // Make a copy of the default filterStatus attach behaviors so it can be
+  // called within this module's override of it.
   const originalFilterStatusAttach = Drupal.behaviors.filterStatus.attach;
 
+  // Overrides the default filterStatus to provided functionality needs
+  // specific to CKEditor 5.
   Drupal.behaviors.filterStatus.attach = (context, settings) => {
-    const filterStatusCheckboxes = document.querySelectorAll('#filters-status-wrapper input.form-checkbox');
+    const filterStatusCheckboxes = document.querySelectorAll(
+      '#filters-status-wrapper input.form-checkbox',
+    );
+
+    // CKEditor 5 has uses cases that require updating the filter settings via
+    // AJAX. When this happens, the checkboxes that enable filters must be
+    // reprocessed by the filterStatus behavior. For this to occur:
+    // 1. 'filter-status' must be removed from the element's once registry so
+    //    the process can run again and take into account any filter settings
+    //    elements that have been added or removed from the DOM.
+    //    @see core/assets/vendor/once/once.js
     once.remove('filter-status', filterStatusCheckboxes);
+
+    // 2. Any listeners to the 'click.filterUpdate' event should be removed so
+    //    they do not conflict with event listeners that are added as part of
+    //    the AJAX refresh.
     $(filterStatusCheckboxes).off('click.filterUpdate');
+
+    // Call the original behavior.
     originalFilterStatusAttach(context, settings);
   };
 
+  // Activates otherwise-inactive tabs that have form elements with validation
+  // errors.
+  // @todo Remove when https://www.drupal.org/project/drupal/issues/2911932 lands.
   Drupal.behaviors.tabErrorsVisible = {
     attach(context) {
-      context.querySelectorAll('details .form-item .error').forEach(item => {
+      context.querySelectorAll('details .form-item .error').forEach((item) => {
         const details = item.closest('details');
-
         if (details.style.display === 'none') {
           const tabSelect = document.querySelector(`[href='#${details.id}']`);
-
           if (tabSelect) {
             tabSelect.click();
           }
         }
       });
-    }
-
+    },
   };
-})(Drupal, drupalSettings, jQuery, JSON, once, Sortable, tabbable);
\ No newline at end of file
+})(Drupal, drupalSettings, jQuery, JSON, once, Sortable, tabbable);
diff --git a/core/modules/ckeditor5/js/ckeditor5.dialog.fix.es6.js b/core/modules/ckeditor5/js/ckeditor5.dialog.fix.es6.js
deleted file mode 100644
index 1f4ed1d7feb5..000000000000
--- a/core/modules/ckeditor5/js/ckeditor5.dialog.fix.es6.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * @file
- * This file overrides the way jQuery UI focus trap works.
- *
- * When a focus event is fired while a CKEditor 5 instance is focused, do not
- * trap the focus and let CKEditor 5 manage that focus.
- */
-
-(($) => {
-  $.widget('ui.dialog', $.ui.dialog, {
-    // Override core override of jQuery UI's `_allowInteraction()` so that
-    // CKEditor 5 in modals can work as expected.
-    // @see https://api.jqueryui.com/dialog/#method-_allowInteraction
-    _allowInteraction(event) {
-      return event.target.classList.contains('ck') || this._super(event);
-    },
-  });
-})(jQuery);
diff --git a/core/modules/ckeditor5/js/ckeditor5.dialog.fix.js b/core/modules/ckeditor5/js/ckeditor5.dialog.fix.js
index e0b9531cab53..1f4ed1d7feb5 100644
--- a/core/modules/ckeditor5/js/ckeditor5.dialog.fix.js
+++ b/core/modules/ckeditor5/js/ckeditor5.dialog.fix.js
@@ -1,15 +1,18 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * This file overrides the way jQuery UI focus trap works.
+ *
+ * When a focus event is fired while a CKEditor 5 instance is focused, do not
+ * trap the focus and let CKEditor 5 manage that focus.
+ */
 
-($ => {
+(($) => {
   $.widget('ui.dialog', $.ui.dialog, {
+    // Override core override of jQuery UI's `_allowInteraction()` so that
+    // CKEditor 5 in modals can work as expected.
+    // @see https://api.jqueryui.com/dialog/#method-_allowInteraction
     _allowInteraction(event) {
       return event.target.classList.contains('ck') || this._super(event);
-    }
-
+    },
   });
-})(jQuery);
\ No newline at end of file
+})(jQuery);
diff --git a/core/modules/ckeditor5/js/ckeditor5.es6.js b/core/modules/ckeditor5/js/ckeditor5.es6.js
deleted file mode 100644
index f276df9f76f1..000000000000
--- a/core/modules/ckeditor5/js/ckeditor5.es6.js
+++ /dev/null
@@ -1,637 +0,0 @@
-/**
- * @file
- * CKEditor 5 implementation of {@link Drupal.editors} API.
- */
-
-((Drupal, debounce, CKEditor5, $, once) => {
-  // CKEditor 5 is incompatible with IE11. When IE11 is detected, the CKEditor 5
-  // variable is null. In those instances, exit early since CKEditor 5 is not
-  // loaded.
-  if (!CKEditor5) {
-    return;
-  }
-
-  /**
-   * The CKEditor 5 instances.
-   *
-   * @type {Map}
-   */
-  Drupal.CKEditor5Instances = new Map();
-
-  /**
-   * The callback functions.
-   *
-   * @type {Map}
-   */
-  const callbacks = new Map();
-
-  /**
-   * List of element ids with the required attribute.
-   *
-   * @type {Set}
-   */
-  const required = new Set();
-
-  /**
-   * Get the value of the (deep) property on name from scope.
-   *
-   * @param {object} scope
-   *  Object used to search for the function.
-   * @param {string} name
-   *  The path to access in the scope object.
-   *
-   * @return {null|function}
-   *  The corresponding function from the scope object.
-   */
-  function findFunc(scope, name) {
-    if (!scope) {
-      return null;
-    }
-    const parts = name.includes('.') ? name.split('.') : name;
-
-    if (parts.length > 1) {
-      return findFunc(scope[parts.shift()], parts);
-    }
-    return typeof scope[parts[0]] === 'function' ? scope[parts[0]] : null;
-  }
-
-  /**
-   * Transform a config key in a callback function or execute the function
-   * to dynamically build the configuration entry.
-   *
-   * @param {object} config
-   *  The plugin configuration object.
-   *
-   * @return {null|function|*}
-   *  Resulting configuration value.
-   */
-  function buildFunc(config) {
-    const { func } = config;
-    // Assuming a global object.
-    const fn = findFunc(window, func.name);
-    if (typeof fn === 'function') {
-      const result = func.invoke ? fn(...func.args) : fn;
-      return result;
-    }
-    return null;
-  }
-
-  /**
-   * Converts a string representing regexp to a RegExp object.
-   *
-   * @param {Object} config
-   *   An object containing configuration.
-   * @param {string} config.pattern
-   *   The regexp pattern that is used to create the RegExp object.
-   *
-   * @return {RegExp}
-   *   Regexp object built from the string regexp.
-   */
-  function buildRegexp(config) {
-    const { pattern } = config.regexp;
-
-    const main = pattern.match(/\/(.+)\/.*/)[1];
-    const options = pattern.match(/\/.+\/(.*)/)[1];
-
-    return new RegExp(main, options);
-  }
-
-  /**
-   * Casts configuration items to correct types.
-   *
-   * @param {Object} config
-   *   The config object.
-   * @return {Object}
-   *   The config object with items transformed to correct type.
-   */
-  function processConfig(config) {
-    /**
-     * Processes an array in config recursively.
-     *
-     * @param {Array} config
-     *   An array that should be processed recursively.
-     * @return {Array}
-     *   An array that has been processed recursively.
-     */
-    function processArray(config) {
-      return config.map((item) => {
-        if (typeof item === 'object') {
-          return processConfig(item);
-        }
-
-        return item;
-      });
-    }
-
-    return Object.entries(config).reduce((processed, [key, value]) => {
-      if (typeof value === 'object') {
-        // Check for null values.
-        if (!value) {
-          return processed;
-        }
-        if (value.hasOwnProperty('func')) {
-          processed[key] = buildFunc(value);
-        } else if (value.hasOwnProperty('regexp')) {
-          processed[key] = buildRegexp(value);
-        } else if (Array.isArray(value)) {
-          processed[key] = processArray(value);
-        } else {
-          processed[key] = processConfig(value);
-        }
-      } else {
-        processed[key] = value;
-      }
-
-      return processed;
-    }, {});
-  }
-
-  /**
-   * Set an id to a data-attribute for registering this element instance.
-   *
-   * @param {Element} element
-   *   An element that should receive unique ID.
-   *
-   * @return {string}
-   *   The id to use for this element.
-   */
-  const setElementId = (element) => {
-    const id = Math.random().toString().slice(2, 9);
-    element.setAttribute('data-ckeditor5-id', id);
-
-    return id;
-  };
-
-  /**
-   * Return a unique selector for the element.
-   *
-   * @param {HTMLElement} element
-   *   An element which unique ID should be retrieved.
-   *
-   * @return {string}
-   *   The id to use for this element.
-   */
-  const getElementId = (element) => element.getAttribute('data-ckeditor5-id');
-
-  /**
-   * Select CKEditor 5 plugin classes to include.
-   *
-   * Found in the CKEditor 5 global JavaScript object as {package.Class}.
-   *
-   * @param {Array} plugins
-   *  List of package and Class name of plugins
-   *
-   * @return {Array}
-   *   List of JavaScript Classes to add in the extraPlugins property of config.
-   */
-  function selectPlugins(plugins) {
-    return plugins.map((pluginDefinition) => {
-      const [build, name] = pluginDefinition.split('.');
-      if (CKEditor5[build] && CKEditor5[build][name]) {
-        return CKEditor5[build][name];
-      }
-
-      // eslint-disable-next-line no-console
-      console.warn(`Failed to load ${build} - ${name}`);
-      return null;
-    });
-  }
-
-  /**
-   * Process a group of CSS rules.
-   *
-   * @param {CSSGroupingRule} rulesGroup
-   *  A complete stylesheet or a group of nested rules like @media.
-   */
-  function processRules(rulesGroup) {
-    try {
-      // eslint-disable-next-line no-use-before-define
-      [...rulesGroup.cssRules].forEach(ckeditor5SelectorProcessing);
-    } catch (e) {
-      // eslint-disable-next-line no-console
-      console.warn(
-        `Stylesheet ${rulesGroup.href} not included in CKEditor reset due to the browser's CORS policy.`,
-      );
-    }
-  }
-
-  /**
-   * Processes CSS rules dynamically to account for CKEditor 5 in off canvas.
-   *
-   * This is achieved by doing the following steps:
-   * - Adding a donut scope to off canvas rules, so they don't apply within the
-   *   editor element.
-   * - Editor specific rules (i.e. those with .ck* selectors) are duplicated and
-   *   prefixed with the off canvas selector to ensure they have higher
-   *   specificity over the off canvas reset.
-   *
-   * The donut scope prevents off canvas rules from applying to the CKEditor 5
-   * editor element. Transforms a:
-   *  - #drupal-off-canvas strong
-   * rule into:
-   *  - #drupal-off-canvas strong:not([data-drupal-ck-style-fence] *)
-   *
-   * This means that the rule applies to all <strong> elements inside
-   * #drupal-off-canvas, except for <strong> elements who have a with a parent
-   * with the "data-drupal-ck-style-fence" attribute.
-   *
-   * For example:
-   * <div id="drupal-off-canvas">
-   *   <p>
-   *     <strong>Off canvas reset</strong>
-   *   </p>
-   *   <p data-drupal-ck-style-fence>
-   *     <!--
-   *       this strong elements matches the `[data-drupal-ck-style-fence] *`
-   *       selector and is excluded from the off canvas reset rule.
-   *     -->
-   *     <strong>Off canvas reset NOT applied.</strong>
-   *   </p>
-   * </div>
-   *
-   * The donut scope does not prevent CSS inheritance. There is CSS that resets
-   * following properties to prevent inheritance: background, border,
-   * box-sizing, margin, padding, position, text-decoration, transition,
-   * vertical-align and word-wrap.
-   *
-   * All .ck* CSS rules are duplicated and prefixed with the off canvas selector
-   * To ensure they have higher specificity and are not reset too aggressively.
-   *
-   * @param {CSSRule} rule
-   *  A single CSS rule to be analysed and changed if necessary.
-   */
-  function ckeditor5SelectorProcessing(rule) {
-    // Handle nested rules in @media, @support, etc.
-    if (rule.cssRules) {
-      processRules(rule);
-    }
-    if (!rule.selectorText) {
-      return;
-    }
-    const offCanvasId = '#drupal-off-canvas';
-    const CKEditorClass = '.ck';
-    const styleFence = '[data-drupal-ck-style-fence]';
-    if (
-      rule.selectorText.includes(offCanvasId) ||
-      rule.selectorText.includes(CKEditorClass)
-    ) {
-      rule.selectorText = rule.selectorText
-        .split(/,/g)
-        .map((selector) => {
-          // Only change rules that include #drupal-off-canvas in the selector.
-          if (selector.includes(offCanvasId)) {
-            return `${selector.trim()}:not(${styleFence} *)`;
-          }
-          // Duplicate CKEditor 5 styles with higher specificity for proper
-          // display in off canvas elements.
-          if (selector.includes(CKEditorClass)) {
-            // Return both rules to avoid replacing the existing rules.
-            return [
-              selector.trim(),
-              selector
-                .trim()
-                .replace(
-                  CKEditorClass,
-                  `${offCanvasId} ${styleFence} ${CKEditorClass}`,
-                ),
-            ];
-          }
-          return selector;
-        })
-        .flat()
-        .join(', ');
-    }
-  }
-
-  /**
-   * Adds CSS to ensure proper styling of CKEditor 5 inside off-canvas dialogs.
-   *
-   * @param {HTMLElement} element
-   *   The element the editor is attached to.
-   */
-  function offCanvasCss(element) {
-    const fenceName = 'data-drupal-ck-style-fence';
-    const editor = Drupal.CKEditor5Instances.get(
-      element.getAttribute('data-ckeditor5-id'),
-    );
-    editor.ui.view.element.setAttribute(fenceName, '');
-    // Only proceed if the styles haven't been added yet.
-    if (once('ckeditor5-off-canvas-reset', 'body').length) {
-      // For all rules on the page, add the donut scope for
-      // rules containing the #drupal-off-canvas selector.
-      [...document.styleSheets].forEach(processRules);
-
-      const prefix = `#drupal-off-canvas-wrapper [${fenceName}]`;
-      // Additional styles that need to be explicity added in addition to the
-      // prefixed versions of existing css in `existingCss`.
-      const addedCss = [
-        `${prefix} .ck.ck-content {display:block;min-height:5rem;}`,
-        `${prefix} .ck.ck-content * {display:initial;background:initial;color:initial;padding:initial;}`,
-        `${prefix} .ck.ck-content li {display:list-item}`,
-        `${prefix} .ck.ck-content ol li {list-style-type: decimal}`,
-        `${prefix} .ck[contenteditable], ${prefix} .ck[contenteditable] * {-webkit-user-modify: read-write;-moz-user-modify: read-write;}`,
-      ];
-
-      const prefixedCss = [...addedCss].join('\n');
-
-      // Create a new style tag with the prefixed styles added above.
-      const offCanvasCssStyle = document.createElement('style');
-      offCanvasCssStyle.textContent = prefixedCss;
-      offCanvasCssStyle.setAttribute('id', 'ckeditor5-off-canvas-reset');
-      document.body.appendChild(offCanvasCssStyle);
-    }
-  }
-
-  /**
-   * Integration of CKEditor 5 with the Drupal editor API.
-   *
-   * @namespace
-   *
-   * @see Drupal.editorAttach
-   */
-  Drupal.editors.ckeditor5 = {
-    /**
-     * Editor attach callback.
-     *
-     * @param {HTMLElement} element
-     *   The element to attach the editor to.
-     * @param {string} format
-     *   The text format for the editor.
-     */
-    attach(element, format) {
-      const { editorClassic } = CKEditor5;
-      const { toolbar, plugins, config, language } = format.editorSettings;
-      const extraPlugins = selectPlugins(plugins);
-      const pluginConfig = processConfig(config);
-      const editorConfig = {
-        extraPlugins,
-        toolbar,
-        ...pluginConfig,
-        // Language settings have a conflict between the editor localization
-        // settings and the "language" plugin.
-        language: { ...pluginConfig.language, ...language },
-      };
-      // Set the id immediately so that it is available when onChange is called.
-      const id = setElementId(element);
-      const { ClassicEditor } = editorClassic;
-
-      ClassicEditor.create(element, editorConfig)
-        .then((editor) => {
-          // Save a reference to the initialized instance.
-          Drupal.CKEditor5Instances.set(id, editor);
-
-          // CKEditor 4 had a feature to remove the required attribute
-          // see: https://www.drupal.org/project/drupal/issues/1954968
-          if (element.hasAttribute('required')) {
-            required.add(id);
-            element.removeAttribute('required');
-          }
-
-          // Integrate CKEditor 5 viewport offset with Drupal displace.
-          // @see \Drupal\Tests\ckeditor5\FunctionalJavascript\CKEditor5ToolbarTest
-          // @see https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorui-EditorUI.html#member-viewportOffset
-          $(document).on(
-            `drupalViewportOffsetChange.ckeditor5.${id}`,
-            (event, offsets) => {
-              editor.ui.viewportOffset = offsets;
-            },
-          );
-
-          editor.model.document.on('change:data', () => {
-            const callback = callbacks.get(id);
-            if (callback) {
-              if (editor.plugins.has('SourceEditing')) {
-                // If the change:data is being called while in source editing
-                // mode, it means that the form is being submitted. To avoid
-                // race conditions, in this case the callback gets called
-                // without decorating the callback with debounce.
-                // @see https://www.drupal.org/i/3229174
-                // @see Drupal.editorDetach
-                if (editor.plugins.get('SourceEditing').isSourceEditingMode) {
-                  callback();
-                  return;
-                }
-              }
-
-              // Marks the field as changed.
-              // @see Drupal.editorAttach
-              debounce(callback, 400)();
-            }
-          });
-
-          const isOffCanvas = element.closest('#drupal-off-canvas');
-
-          if (isOffCanvas) {
-            offCanvasCss(element);
-          }
-        })
-        .catch((error) => {
-          // eslint-disable-next-line no-console
-          console.error(error);
-        });
-    },
-
-    /**
-     * Editor detach callback.
-     *
-     * @param {HTMLElement} element
-     *   The element to detach the editor from.
-     * @param {string} format
-     *   The text format used for the editor.
-     * @param {string} trigger
-     *   The event trigger for the detach.
-     */
-    detach(element, format, trigger) {
-      const id = getElementId(element);
-      const editor = Drupal.CKEditor5Instances.get(id);
-      if (!editor) {
-        return;
-      }
-
-      $(document).off(`drupalViewportOffsetChange.ckeditor5.${id}`);
-
-      if (trigger === 'serialize') {
-        editor.updateSourceElement();
-      } else {
-        element.removeAttribute('contentEditable');
-        // Return the promise to allow external code to queue code to
-        // execute after the destroy is complete.
-        return editor
-          .destroy()
-          .then(() => {
-            // Clean up stored references.
-            Drupal.CKEditor5Instances.delete(id);
-            callbacks.delete(id);
-            if (required.has(id)) {
-              element.setAttribute('required', 'required');
-              required.delete(id);
-            }
-          })
-          .catch((error) => {
-            // eslint-disable-next-line no-console
-            console.error(error);
-          });
-      }
-    },
-
-    /**
-     * Registers a callback which CKEditor 5 will call on change:data event.
-     *
-     * @param {HTMLElement} element
-     *   The element where the change occurred.
-     * @param {function} callback
-     *   Callback called with the value of the editor.
-     */
-    onChange(element, callback) {
-      callbacks.set(getElementId(element), callback);
-    },
-
-    /**
-     * Attaches an inline editor to a DOM element.
-     *
-     * @param {HTMLElement} element
-     *   The element to attach the editor to.
-     * @param {object} format
-     *   The text format used in the editor.
-     * @param {string} [mainToolbarId]
-     *   The id attribute for the main editor toolbar, if any.
-     */
-    attachInlineEditor(element, format, mainToolbarId) {
-      const { editorDecoupled } = CKEditor5;
-      const {
-        toolbar,
-        plugins,
-        config: pluginConfig,
-        language,
-      } = format.editorSettings;
-      const extraPlugins = selectPlugins(plugins);
-      const config = {
-        extraPlugins,
-        toolbar,
-        language,
-        ...processConfig(pluginConfig),
-      };
-      const id = setElementId(element);
-      const { DecoupledEditor } = editorDecoupled;
-
-      DecoupledEditor.create(element, config)
-        .then((editor) => {
-          Drupal.CKEditor5Instances.set(id, editor);
-          const toolbar = document.getElementById(mainToolbarId);
-          toolbar.appendChild(editor.ui.view.toolbar.element);
-          editor.model.document.on('change:data', () => {
-            const callback = callbacks.get(id);
-            if (callback) {
-              // Allow modules to update EditorModel by providing the current data.
-              debounce(callback, 400)(editor.getData());
-            }
-          });
-        })
-        .catch((error) => {
-          // eslint-disable-next-line no-console
-          console.error(error);
-        });
-    },
-  };
-
-  /**
-   * Public API for Drupal CKEditor 5 integration.
-   *
-   * @namespace
-   */
-  Drupal.ckeditor5 = {
-    /**
-     * Variable storing the current dialog's save callback.
-     *
-     * @type {?function}
-     */
-    saveCallback: null,
-
-    /**
-     * Open a dialog for a Drupal-based plugin.
-     *
-     * This dynamically loads jQuery UI (if necessary) using the Drupal AJAX
-     * framework, then opens a dialog at the specified Drupal path.
-     *
-     * @param {string} url
-     *   The URL that contains the contents of the dialog.
-     * @param {function} saveCallback
-     *   A function to be called upon saving the dialog.
-     * @param {object} dialogSettings
-     *   An object containing settings to be passed to the jQuery UI.
-     */
-    openDialog(url, saveCallback, dialogSettings) {
-      // Add a consistent dialog class.
-      const classes = dialogSettings.dialogClass
-        ? dialogSettings.dialogClass.split(' ')
-        : [];
-      classes.push('ui-dialog--narrow');
-      dialogSettings.dialogClass = classes.join(' ');
-      dialogSettings.autoResize =
-        window.matchMedia('(min-width: 600px)').matches;
-      dialogSettings.width = 'auto';
-
-      const ckeditorAjaxDialog = Drupal.ajax({
-        dialog: dialogSettings,
-        dialogType: 'modal',
-        selector: '.ckeditor5-dialog-loading-link',
-        url,
-        progress: { type: 'fullscreen' },
-        submit: {
-          editor_object: {},
-        },
-      });
-      ckeditorAjaxDialog.execute();
-
-      // Store the save callback to be executed when this dialog is closed.
-      Drupal.ckeditor5.saveCallback = saveCallback;
-    },
-  };
-
-  // Redirect on hash change when the original hash has an associated CKEditor 5.
-  function redirectTextareaFragmentToCKEditor5Instance() {
-    const hash = window.location.hash.substr(1);
-    const element = document.getElementById(hash);
-    if (element) {
-      const editorID = getElementId(element);
-      const editor = Drupal.CKEditor5Instances.get(editorID);
-      if (editor) {
-        // Give the CKEditor 5 instance an ID.
-        editor.sourceElement.nextElementSibling.setAttribute(
-          'id',
-          `cke_${hash}`,
-        );
-        window.location.replace(`#cke_${hash}`);
-      }
-    }
-  }
-
-  $(window).on(
-    'hashchange.ckeditor',
-    redirectTextareaFragmentToCKEditor5Instance,
-  );
-
-  // Respond to new dialogs that are opened by CKEditor, closing the AJAX loader.
-  $(window).on('dialog:beforecreate', () => {
-    $('.ckeditor5-dialog-loading').animate(
-      { top: '-40px' },
-      function removeDialogLoading() {
-        $(this).remove();
-      },
-    );
-  });
-
-  // Respond to dialogs that are saved, sending data back to CKEditor.
-  $(window).on('editor:dialogsave', (e, values) => {
-    if (Drupal.ckeditor5.saveCallback) {
-      Drupal.ckeditor5.saveCallback(values);
-    }
-  });
-
-  // Respond to dialogs that are closed, removing the current save handler.
-  $(window).on('dialog:afterclose', () => {
-    if (Drupal.ckeditor5.saveCallback) {
-      Drupal.ckeditor5.saveCallback = null;
-    }
-  });
-})(Drupal, Drupal.debounce, CKEditor5, jQuery, once);
diff --git a/core/modules/ckeditor5/js/ckeditor5.filter.admin.es6.js b/core/modules/ckeditor5/js/ckeditor5.filter.admin.es6.js
deleted file mode 100644
index 6775bbf7631f..000000000000
--- a/core/modules/ckeditor5/js/ckeditor5.filter.admin.es6.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * @file
- * Provides Text Editor UI improvements specific to CKEditor 5.
- */
-((Drupal, once) => {
-  Drupal.behaviors.allowedTagsListener = {
-    attach: function attach(context) {
-      once(
-        'ajax-conflict-prevention',
-        '[data-drupal-selector="filter-format-edit-form"], [data-drupal-selector="filter-format-add-form"]',
-        context,
-      ).forEach((form) => {
-        // When the form is submitted, remove the disabled attribute from all
-        // AJAX enabled form elements. The disabled state is added as part of
-        // AJAX processing, but will prevent the value from being added to
-        // $form_state.
-        form.addEventListener('submit', () => {
-          once
-            .filter(
-              'drupal-ajax',
-              '[data-drupal-selector="filter-format-edit-form"] [disabled], [data-drupal-selector="filter-format-add-form"] [disabled]',
-            )
-            // eslint-disable-next-line max-nested-callbacks
-            .forEach((disabledElement) => {
-              disabledElement.removeAttribute('disabled');
-            });
-        });
-      });
-    },
-  };
-
-  // Copy the function that is about to be overridden so it can be invoked
-  // inside the override.
-  const originalAjaxEventResponse = Drupal.Ajax.prototype.eventResponse;
-
-  /**
-   * Overrides Ajax.eventResponse with CKEditor 5 specific customizations.
-   *
-   * This is the handler for events that will ultimately trigger an AJAX
-   * response. It is overridden here to provide additional logic to prevent
-   * specific CKEditor 5-related events from triggering that AJAX response
-   * unless certain criteria are met.
-   */
-  Drupal.Ajax.prototype.eventResponse = function ckeditor5AjaxEventResponse(
-    ...args
-  ) {
-    // There are AJAX callbacks that should only be triggered if the editor
-    // <select> is set to 'ckeditor5'. They should be active when the text
-    // format is using CKEditor 5 and when a user is attempting to switch to
-    // CKEditor 5 but is prevented from doing so by validation. Triggering these
-    // AJAX callback when trying to switch to CKEditor 5 but blocked by
-    // validation benefits the user as they get real time feedback as they
-    // configure the text format to be CKEditor 5 compatible. This spares them
-    // from having to submit the form multiple times in order to determine if
-    // their settings are compatible.
-    // This validation stage is also why the AJAX callbacks can't be
-    // conditionally added server side, as validation errors interrupt the form
-    // rebuild before the AJAX callbacks could be added via form_alter.
-    if (this.ckeditor5_only) {
-      // The ckeditor5_only property is added to form elements that should only
-      // trigger AJAX callbacks when the editor <select> value is 'ckeditor5'.
-      // These callbacks provide real-time validation that should be present for
-      // both text formats using CKEditor 5 and text formats in the process of
-      // switching to CKEditor 5, but prevented from doing so by validation.
-      if (
-        this.$form[0].querySelector('#edit-editor-editor').value !== 'ckeditor5'
-      ) {
-        return;
-      }
-    }
-
-    originalAjaxEventResponse.apply(this, args);
-  };
-})(Drupal, once);
diff --git a/core/modules/ckeditor5/js/ckeditor5.filter.admin.js b/core/modules/ckeditor5/js/ckeditor5.filter.admin.js
index 9feaff4a8cfc..6775bbf7631f 100644
--- a/core/modules/ckeditor5/js/ckeditor5.filter.admin.js
+++ b/core/modules/ckeditor5/js/ckeditor5.filter.admin.js
@@ -1,35 +1,74 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * @file
+ * Provides Text Editor UI improvements specific to CKEditor 5.
+ */
 ((Drupal, once) => {
   Drupal.behaviors.allowedTagsListener = {
     attach: function attach(context) {
-      once('ajax-conflict-prevention', '[data-drupal-selector="filter-format-edit-form"], [data-drupal-selector="filter-format-add-form"]', context).forEach(form => {
+      once(
+        'ajax-conflict-prevention',
+        '[data-drupal-selector="filter-format-edit-form"], [data-drupal-selector="filter-format-add-form"]',
+        context,
+      ).forEach((form) => {
+        // When the form is submitted, remove the disabled attribute from all
+        // AJAX enabled form elements. The disabled state is added as part of
+        // AJAX processing, but will prevent the value from being added to
+        // $form_state.
         form.addEventListener('submit', () => {
-          once.filter('drupal-ajax', '[data-drupal-selector="filter-format-edit-form"] [disabled], [data-drupal-selector="filter-format-add-form"] [disabled]').forEach(disabledElement => {
-            disabledElement.removeAttribute('disabled');
-          });
+          once
+            .filter(
+              'drupal-ajax',
+              '[data-drupal-selector="filter-format-edit-form"] [disabled], [data-drupal-selector="filter-format-add-form"] [disabled]',
+            )
+            // eslint-disable-next-line max-nested-callbacks
+            .forEach((disabledElement) => {
+              disabledElement.removeAttribute('disabled');
+            });
         });
       });
-    }
+    },
   };
+
+  // Copy the function that is about to be overridden so it can be invoked
+  // inside the override.
   const originalAjaxEventResponse = Drupal.Ajax.prototype.eventResponse;
 
-  Drupal.Ajax.prototype.eventResponse = function ckeditor5AjaxEventResponse() {
+  /**
+   * Overrides Ajax.eventResponse with CKEditor 5 specific customizations.
+   *
+   * This is the handler for events that will ultimately trigger an AJAX
+   * response. It is overridden here to provide additional logic to prevent
+   * specific CKEditor 5-related events from triggering that AJAX response
+   * unless certain criteria are met.
+   */
+  Drupal.Ajax.prototype.eventResponse = function ckeditor5AjaxEventResponse(
+    ...args
+  ) {
+    // There are AJAX callbacks that should only be triggered if the editor
+    // <select> is set to 'ckeditor5'. They should be active when the text
+    // format is using CKEditor 5 and when a user is attempting to switch to
+    // CKEditor 5 but is prevented from doing so by validation. Triggering these
+    // AJAX callback when trying to switch to CKEditor 5 but blocked by
+    // validation benefits the user as they get real time feedback as they
+    // configure the text format to be CKEditor 5 compatible. This spares them
+    // from having to submit the form multiple times in order to determine if
+    // their settings are compatible.
+    // This validation stage is also why the AJAX callbacks can't be
+    // conditionally added server side, as validation errors interrupt the form
+    // rebuild before the AJAX callbacks could be added via form_alter.
     if (this.ckeditor5_only) {
-      if (this.$form[0].querySelector('#edit-editor-editor').value !== 'ckeditor5') {
+      // The ckeditor5_only property is added to form elements that should only
+      // trigger AJAX callbacks when the editor <select> value is 'ckeditor5'.
+      // These callbacks provide real-time validation that should be present for
+      // both text formats using CKEditor 5 and text formats in the process of
+      // switching to CKEditor 5, but prevented from doing so by validation.
+      if (
+        this.$form[0].querySelector('#edit-editor-editor').value !== 'ckeditor5'
+      ) {
         return;
       }
     }
 
-    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
-      args[_key] = arguments[_key];
-    }
-
     originalAjaxEventResponse.apply(this, args);
   };
-})(Drupal, once);
\ No newline at end of file
+})(Drupal, once);
diff --git a/core/modules/ckeditor5/js/ckeditor5.js b/core/modules/ckeditor5/js/ckeditor5.js
index aa25b3f40b8a..f276df9f76f1 100644
--- a/core/modules/ckeditor5/js/ckeditor5.js
+++ b/core/modules/ckeditor5/js/ckeditor5.js
@@ -1,59 +1,120 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * CKEditor 5 implementation of {@link Drupal.editors} API.
+ */
 
 ((Drupal, debounce, CKEditor5, $, once) => {
+  // CKEditor 5 is incompatible with IE11. When IE11 is detected, the CKEditor 5
+  // variable is null. In those instances, exit early since CKEditor 5 is not
+  // loaded.
   if (!CKEditor5) {
     return;
   }
 
+  /**
+   * The CKEditor 5 instances.
+   *
+   * @type {Map}
+   */
   Drupal.CKEditor5Instances = new Map();
+
+  /**
+   * The callback functions.
+   *
+   * @type {Map}
+   */
   const callbacks = new Map();
+
+  /**
+   * List of element ids with the required attribute.
+   *
+   * @type {Set}
+   */
   const required = new Set();
 
+  /**
+   * Get the value of the (deep) property on name from scope.
+   *
+   * @param {object} scope
+   *  Object used to search for the function.
+   * @param {string} name
+   *  The path to access in the scope object.
+   *
+   * @return {null|function}
+   *  The corresponding function from the scope object.
+   */
   function findFunc(scope, name) {
     if (!scope) {
       return null;
     }
-
     const parts = name.includes('.') ? name.split('.') : name;
 
     if (parts.length > 1) {
       return findFunc(scope[parts.shift()], parts);
     }
-
     return typeof scope[parts[0]] === 'function' ? scope[parts[0]] : null;
   }
 
+  /**
+   * Transform a config key in a callback function or execute the function
+   * to dynamically build the configuration entry.
+   *
+   * @param {object} config
+   *  The plugin configuration object.
+   *
+   * @return {null|function|*}
+   *  Resulting configuration value.
+   */
   function buildFunc(config) {
-    const {
-      func
-    } = config;
+    const { func } = config;
+    // Assuming a global object.
     const fn = findFunc(window, func.name);
-
     if (typeof fn === 'function') {
       const result = func.invoke ? fn(...func.args) : fn;
       return result;
     }
-
     return null;
   }
 
+  /**
+   * Converts a string representing regexp to a RegExp object.
+   *
+   * @param {Object} config
+   *   An object containing configuration.
+   * @param {string} config.pattern
+   *   The regexp pattern that is used to create the RegExp object.
+   *
+   * @return {RegExp}
+   *   Regexp object built from the string regexp.
+   */
   function buildRegexp(config) {
-    const {
-      pattern
-    } = config.regexp;
+    const { pattern } = config.regexp;
+
     const main = pattern.match(/\/(.+)\/.*/)[1];
     const options = pattern.match(/\/.+\/(.*)/)[1];
+
     return new RegExp(main, options);
   }
 
+  /**
+   * Casts configuration items to correct types.
+   *
+   * @param {Object} config
+   *   The config object.
+   * @return {Object}
+   *   The config object with items transformed to correct type.
+   */
   function processConfig(config) {
+    /**
+     * Processes an array in config recursively.
+     *
+     * @param {Array} config
+     *   An array that should be processed recursively.
+     * @return {Array}
+     *   An array that has been processed recursively.
+     */
     function processArray(config) {
-      return config.map(item => {
+      return config.map((item) => {
         if (typeof item === 'object') {
           return processConfig(item);
         }
@@ -62,14 +123,12 @@
       });
     }
 
-    return Object.entries(config).reduce((processed, _ref) => {
-      let [key, value] = _ref;
-
+    return Object.entries(config).reduce((processed, [key, value]) => {
       if (typeof value === 'object') {
+        // Check for null values.
         if (!value) {
           return processed;
         }
-
         if (value.hasOwnProperty('func')) {
           processed[key] = buildFunc(value);
         } else if (value.hasOwnProperty('regexp')) {
@@ -87,73 +146,195 @@
     }, {});
   }
 
-  const setElementId = element => {
+  /**
+   * Set an id to a data-attribute for registering this element instance.
+   *
+   * @param {Element} element
+   *   An element that should receive unique ID.
+   *
+   * @return {string}
+   *   The id to use for this element.
+   */
+  const setElementId = (element) => {
     const id = Math.random().toString().slice(2, 9);
     element.setAttribute('data-ckeditor5-id', id);
+
     return id;
   };
 
-  const getElementId = element => element.getAttribute('data-ckeditor5-id');
-
+  /**
+   * Return a unique selector for the element.
+   *
+   * @param {HTMLElement} element
+   *   An element which unique ID should be retrieved.
+   *
+   * @return {string}
+   *   The id to use for this element.
+   */
+  const getElementId = (element) => element.getAttribute('data-ckeditor5-id');
+
+  /**
+   * Select CKEditor 5 plugin classes to include.
+   *
+   * Found in the CKEditor 5 global JavaScript object as {package.Class}.
+   *
+   * @param {Array} plugins
+   *  List of package and Class name of plugins
+   *
+   * @return {Array}
+   *   List of JavaScript Classes to add in the extraPlugins property of config.
+   */
   function selectPlugins(plugins) {
-    return plugins.map(pluginDefinition => {
+    return plugins.map((pluginDefinition) => {
       const [build, name] = pluginDefinition.split('.');
-
       if (CKEditor5[build] && CKEditor5[build][name]) {
         return CKEditor5[build][name];
       }
 
+      // eslint-disable-next-line no-console
       console.warn(`Failed to load ${build} - ${name}`);
       return null;
     });
   }
 
+  /**
+   * Process a group of CSS rules.
+   *
+   * @param {CSSGroupingRule} rulesGroup
+   *  A complete stylesheet or a group of nested rules like @media.
+   */
   function processRules(rulesGroup) {
     try {
+      // eslint-disable-next-line no-use-before-define
       [...rulesGroup.cssRules].forEach(ckeditor5SelectorProcessing);
     } catch (e) {
-      console.warn(`Stylesheet ${rulesGroup.href} not included in CKEditor reset due to the browser's CORS policy.`);
+      // eslint-disable-next-line no-console
+      console.warn(
+        `Stylesheet ${rulesGroup.href} not included in CKEditor reset due to the browser's CORS policy.`,
+      );
     }
   }
 
+  /**
+   * Processes CSS rules dynamically to account for CKEditor 5 in off canvas.
+   *
+   * This is achieved by doing the following steps:
+   * - Adding a donut scope to off canvas rules, so they don't apply within the
+   *   editor element.
+   * - Editor specific rules (i.e. those with .ck* selectors) are duplicated and
+   *   prefixed with the off canvas selector to ensure they have higher
+   *   specificity over the off canvas reset.
+   *
+   * The donut scope prevents off canvas rules from applying to the CKEditor 5
+   * editor element. Transforms a:
+   *  - #drupal-off-canvas strong
+   * rule into:
+   *  - #drupal-off-canvas strong:not([data-drupal-ck-style-fence] *)
+   *
+   * This means that the rule applies to all <strong> elements inside
+   * #drupal-off-canvas, except for <strong> elements who have a with a parent
+   * with the "data-drupal-ck-style-fence" attribute.
+   *
+   * For example:
+   * <div id="drupal-off-canvas">
+   *   <p>
+   *     <strong>Off canvas reset</strong>
+   *   </p>
+   *   <p data-drupal-ck-style-fence>
+   *     <!--
+   *       this strong elements matches the `[data-drupal-ck-style-fence] *`
+   *       selector and is excluded from the off canvas reset rule.
+   *     -->
+   *     <strong>Off canvas reset NOT applied.</strong>
+   *   </p>
+   * </div>
+   *
+   * The donut scope does not prevent CSS inheritance. There is CSS that resets
+   * following properties to prevent inheritance: background, border,
+   * box-sizing, margin, padding, position, text-decoration, transition,
+   * vertical-align and word-wrap.
+   *
+   * All .ck* CSS rules are duplicated and prefixed with the off canvas selector
+   * To ensure they have higher specificity and are not reset too aggressively.
+   *
+   * @param {CSSRule} rule
+   *  A single CSS rule to be analysed and changed if necessary.
+   */
   function ckeditor5SelectorProcessing(rule) {
+    // Handle nested rules in @media, @support, etc.
     if (rule.cssRules) {
       processRules(rule);
     }
-
     if (!rule.selectorText) {
       return;
     }
-
     const offCanvasId = '#drupal-off-canvas';
     const CKEditorClass = '.ck';
     const styleFence = '[data-drupal-ck-style-fence]';
-
-    if (rule.selectorText.includes(offCanvasId) || rule.selectorText.includes(CKEditorClass)) {
-      rule.selectorText = rule.selectorText.split(/,/g).map(selector => {
-        if (selector.includes(offCanvasId)) {
-          return `${selector.trim()}:not(${styleFence} *)`;
-        }
-
-        if (selector.includes(CKEditorClass)) {
-          return [selector.trim(), selector.trim().replace(CKEditorClass, `${offCanvasId} ${styleFence} ${CKEditorClass}`)];
-        }
-
-        return selector;
-      }).flat().join(', ');
+    if (
+      rule.selectorText.includes(offCanvasId) ||
+      rule.selectorText.includes(CKEditorClass)
+    ) {
+      rule.selectorText = rule.selectorText
+        .split(/,/g)
+        .map((selector) => {
+          // Only change rules that include #drupal-off-canvas in the selector.
+          if (selector.includes(offCanvasId)) {
+            return `${selector.trim()}:not(${styleFence} *)`;
+          }
+          // Duplicate CKEditor 5 styles with higher specificity for proper
+          // display in off canvas elements.
+          if (selector.includes(CKEditorClass)) {
+            // Return both rules to avoid replacing the existing rules.
+            return [
+              selector.trim(),
+              selector
+                .trim()
+                .replace(
+                  CKEditorClass,
+                  `${offCanvasId} ${styleFence} ${CKEditorClass}`,
+                ),
+            ];
+          }
+          return selector;
+        })
+        .flat()
+        .join(', ');
     }
   }
 
+  /**
+   * Adds CSS to ensure proper styling of CKEditor 5 inside off-canvas dialogs.
+   *
+   * @param {HTMLElement} element
+   *   The element the editor is attached to.
+   */
   function offCanvasCss(element) {
     const fenceName = 'data-drupal-ck-style-fence';
-    const editor = Drupal.CKEditor5Instances.get(element.getAttribute('data-ckeditor5-id'));
+    const editor = Drupal.CKEditor5Instances.get(
+      element.getAttribute('data-ckeditor5-id'),
+    );
     editor.ui.view.element.setAttribute(fenceName, '');
-
+    // Only proceed if the styles haven't been added yet.
     if (once('ckeditor5-off-canvas-reset', 'body').length) {
+      // For all rules on the page, add the donut scope for
+      // rules containing the #drupal-off-canvas selector.
       [...document.styleSheets].forEach(processRules);
+
       const prefix = `#drupal-off-canvas-wrapper [${fenceName}]`;
-      const addedCss = [`${prefix} .ck.ck-content {display:block;min-height:5rem;}`, `${prefix} .ck.ck-content * {display:initial;background:initial;color:initial;padding:initial;}`, `${prefix} .ck.ck-content li {display:list-item}`, `${prefix} .ck.ck-content ol li {list-style-type: decimal}`, `${prefix} .ck[contenteditable], ${prefix} .ck[contenteditable] * {-webkit-user-modify: read-write;-moz-user-modify: read-write;}`];
+      // Additional styles that need to be explicity added in addition to the
+      // prefixed versions of existing css in `existingCss`.
+      const addedCss = [
+        `${prefix} .ck.ck-content {display:block;min-height:5rem;}`,
+        `${prefix} .ck.ck-content * {display:initial;background:initial;color:initial;padding:initial;}`,
+        `${prefix} .ck.ck-content li {display:list-item}`,
+        `${prefix} .ck.ck-content ol li {list-style-type: decimal}`,
+        `${prefix} .ck[contenteditable], ${prefix} .ck[contenteditable] * {-webkit-user-modify: read-write;-moz-user-modify: read-write;}`,
+      ];
+
       const prefixedCss = [...addedCss].join('\n');
+
+      // Create a new style tag with the prefixed styles added above.
       const offCanvasCssStyle = document.createElement('style');
       offCanvasCssStyle.textContent = prefixedCss;
       offCanvasCssStyle.setAttribute('id', 'ckeditor5-off-canvas-reset');
@@ -161,70 +342,108 @@
     }
   }
 
+  /**
+   * Integration of CKEditor 5 with the Drupal editor API.
+   *
+   * @namespace
+   *
+   * @see Drupal.editorAttach
+   */
   Drupal.editors.ckeditor5 = {
+    /**
+     * Editor attach callback.
+     *
+     * @param {HTMLElement} element
+     *   The element to attach the editor to.
+     * @param {string} format
+     *   The text format for the editor.
+     */
     attach(element, format) {
-      const {
-        editorClassic
-      } = CKEditor5;
-      const {
-        toolbar,
-        plugins,
-        config,
-        language
-      } = format.editorSettings;
+      const { editorClassic } = CKEditor5;
+      const { toolbar, plugins, config, language } = format.editorSettings;
       const extraPlugins = selectPlugins(plugins);
       const pluginConfig = processConfig(config);
       const editorConfig = {
         extraPlugins,
         toolbar,
         ...pluginConfig,
-        language: { ...pluginConfig.language,
-          ...language
-        }
+        // Language settings have a conflict between the editor localization
+        // settings and the "language" plugin.
+        language: { ...pluginConfig.language, ...language },
       };
+      // Set the id immediately so that it is available when onChange is called.
       const id = setElementId(element);
-      const {
-        ClassicEditor
-      } = editorClassic;
-      ClassicEditor.create(element, editorConfig).then(editor => {
-        Drupal.CKEditor5Instances.set(id, editor);
-
-        if (element.hasAttribute('required')) {
-          required.add(id);
-          element.removeAttribute('required');
-        }
+      const { ClassicEditor } = editorClassic;
+
+      ClassicEditor.create(element, editorConfig)
+        .then((editor) => {
+          // Save a reference to the initialized instance.
+          Drupal.CKEditor5Instances.set(id, editor);
+
+          // CKEditor 4 had a feature to remove the required attribute
+          // see: https://www.drupal.org/project/drupal/issues/1954968
+          if (element.hasAttribute('required')) {
+            required.add(id);
+            element.removeAttribute('required');
+          }
 
-        $(document).on(`drupalViewportOffsetChange.ckeditor5.${id}`, (event, offsets) => {
-          editor.ui.viewportOffset = offsets;
-        });
-        editor.model.document.on('change:data', () => {
-          const callback = callbacks.get(id);
-
-          if (callback) {
-            if (editor.plugins.has('SourceEditing')) {
-              if (editor.plugins.get('SourceEditing').isSourceEditingMode) {
-                callback();
-                return;
+          // Integrate CKEditor 5 viewport offset with Drupal displace.
+          // @see \Drupal\Tests\ckeditor5\FunctionalJavascript\CKEditor5ToolbarTest
+          // @see https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorui-EditorUI.html#member-viewportOffset
+          $(document).on(
+            `drupalViewportOffsetChange.ckeditor5.${id}`,
+            (event, offsets) => {
+              editor.ui.viewportOffset = offsets;
+            },
+          );
+
+          editor.model.document.on('change:data', () => {
+            const callback = callbacks.get(id);
+            if (callback) {
+              if (editor.plugins.has('SourceEditing')) {
+                // If the change:data is being called while in source editing
+                // mode, it means that the form is being submitted. To avoid
+                // race conditions, in this case the callback gets called
+                // without decorating the callback with debounce.
+                // @see https://www.drupal.org/i/3229174
+                // @see Drupal.editorDetach
+                if (editor.plugins.get('SourceEditing').isSourceEditingMode) {
+                  callback();
+                  return;
+                }
               }
+
+              // Marks the field as changed.
+              // @see Drupal.editorAttach
+              debounce(callback, 400)();
             }
+          });
 
-            debounce(callback, 400)();
+          const isOffCanvas = element.closest('#drupal-off-canvas');
+
+          if (isOffCanvas) {
+            offCanvasCss(element);
           }
+        })
+        .catch((error) => {
+          // eslint-disable-next-line no-console
+          console.error(error);
         });
-        const isOffCanvas = element.closest('#drupal-off-canvas');
-
-        if (isOffCanvas) {
-          offCanvasCss(element);
-        }
-      }).catch(error => {
-        console.error(error);
-      });
     },
 
+    /**
+     * Editor detach callback.
+     *
+     * @param {HTMLElement} element
+     *   The element to detach the editor from.
+     * @param {string} format
+     *   The text format used for the editor.
+     * @param {string} trigger
+     *   The event trigger for the detach.
+     */
     detach(element, format, trigger) {
       const id = getElementId(element);
       const editor = Drupal.CKEditor5Instances.get(id);
-
       if (!editor) {
         return;
       }
@@ -235,120 +454,184 @@
         editor.updateSourceElement();
       } else {
         element.removeAttribute('contentEditable');
-        return editor.destroy().then(() => {
-          Drupal.CKEditor5Instances.delete(id);
-          callbacks.delete(id);
-
-          if (required.has(id)) {
-            element.setAttribute('required', 'required');
-            required.delete(id);
-          }
-        }).catch(error => {
-          console.error(error);
-        });
+        // Return the promise to allow external code to queue code to
+        // execute after the destroy is complete.
+        return editor
+          .destroy()
+          .then(() => {
+            // Clean up stored references.
+            Drupal.CKEditor5Instances.delete(id);
+            callbacks.delete(id);
+            if (required.has(id)) {
+              element.setAttribute('required', 'required');
+              required.delete(id);
+            }
+          })
+          .catch((error) => {
+            // eslint-disable-next-line no-console
+            console.error(error);
+          });
       }
     },
 
+    /**
+     * Registers a callback which CKEditor 5 will call on change:data event.
+     *
+     * @param {HTMLElement} element
+     *   The element where the change occurred.
+     * @param {function} callback
+     *   Callback called with the value of the editor.
+     */
     onChange(element, callback) {
       callbacks.set(getElementId(element), callback);
     },
 
+    /**
+     * Attaches an inline editor to a DOM element.
+     *
+     * @param {HTMLElement} element
+     *   The element to attach the editor to.
+     * @param {object} format
+     *   The text format used in the editor.
+     * @param {string} [mainToolbarId]
+     *   The id attribute for the main editor toolbar, if any.
+     */
     attachInlineEditor(element, format, mainToolbarId) {
-      const {
-        editorDecoupled
-      } = CKEditor5;
+      const { editorDecoupled } = CKEditor5;
       const {
         toolbar,
         plugins,
         config: pluginConfig,
-        language
+        language,
       } = format.editorSettings;
       const extraPlugins = selectPlugins(plugins);
       const config = {
         extraPlugins,
         toolbar,
         language,
-        ...processConfig(pluginConfig)
+        ...processConfig(pluginConfig),
       };
       const id = setElementId(element);
-      const {
-        DecoupledEditor
-      } = editorDecoupled;
-      DecoupledEditor.create(element, config).then(editor => {
-        Drupal.CKEditor5Instances.set(id, editor);
-        const toolbar = document.getElementById(mainToolbarId);
-        toolbar.appendChild(editor.ui.view.toolbar.element);
-        editor.model.document.on('change:data', () => {
-          const callback = callbacks.get(id);
-
-          if (callback) {
-            debounce(callback, 400)(editor.getData());
-          }
+      const { DecoupledEditor } = editorDecoupled;
+
+      DecoupledEditor.create(element, config)
+        .then((editor) => {
+          Drupal.CKEditor5Instances.set(id, editor);
+          const toolbar = document.getElementById(mainToolbarId);
+          toolbar.appendChild(editor.ui.view.toolbar.element);
+          editor.model.document.on('change:data', () => {
+            const callback = callbacks.get(id);
+            if (callback) {
+              // Allow modules to update EditorModel by providing the current data.
+              debounce(callback, 400)(editor.getData());
+            }
+          });
+        })
+        .catch((error) => {
+          // eslint-disable-next-line no-console
+          console.error(error);
         });
-      }).catch(error => {
-        console.error(error);
-      });
-    }
-
+    },
   };
+
+  /**
+   * Public API for Drupal CKEditor 5 integration.
+   *
+   * @namespace
+   */
   Drupal.ckeditor5 = {
+    /**
+     * Variable storing the current dialog's save callback.
+     *
+     * @type {?function}
+     */
     saveCallback: null,
 
+    /**
+     * Open a dialog for a Drupal-based plugin.
+     *
+     * This dynamically loads jQuery UI (if necessary) using the Drupal AJAX
+     * framework, then opens a dialog at the specified Drupal path.
+     *
+     * @param {string} url
+     *   The URL that contains the contents of the dialog.
+     * @param {function} saveCallback
+     *   A function to be called upon saving the dialog.
+     * @param {object} dialogSettings
+     *   An object containing settings to be passed to the jQuery UI.
+     */
     openDialog(url, saveCallback, dialogSettings) {
-      const classes = dialogSettings.dialogClass ? dialogSettings.dialogClass.split(' ') : [];
+      // Add a consistent dialog class.
+      const classes = dialogSettings.dialogClass
+        ? dialogSettings.dialogClass.split(' ')
+        : [];
       classes.push('ui-dialog--narrow');
       dialogSettings.dialogClass = classes.join(' ');
-      dialogSettings.autoResize = window.matchMedia('(min-width: 600px)').matches;
+      dialogSettings.autoResize =
+        window.matchMedia('(min-width: 600px)').matches;
       dialogSettings.width = 'auto';
+
       const ckeditorAjaxDialog = Drupal.ajax({
         dialog: dialogSettings,
         dialogType: 'modal',
         selector: '.ckeditor5-dialog-loading-link',
         url,
-        progress: {
-          type: 'fullscreen'
-        },
+        progress: { type: 'fullscreen' },
         submit: {
-          editor_object: {}
-        }
+          editor_object: {},
+        },
       });
       ckeditorAjaxDialog.execute();
-      Drupal.ckeditor5.saveCallback = saveCallback;
-    }
 
+      // Store the save callback to be executed when this dialog is closed.
+      Drupal.ckeditor5.saveCallback = saveCallback;
+    },
   };
 
+  // Redirect on hash change when the original hash has an associated CKEditor 5.
   function redirectTextareaFragmentToCKEditor5Instance() {
     const hash = window.location.hash.substr(1);
     const element = document.getElementById(hash);
-
     if (element) {
       const editorID = getElementId(element);
       const editor = Drupal.CKEditor5Instances.get(editorID);
-
       if (editor) {
-        editor.sourceElement.nextElementSibling.setAttribute('id', `cke_${hash}`);
+        // Give the CKEditor 5 instance an ID.
+        editor.sourceElement.nextElementSibling.setAttribute(
+          'id',
+          `cke_${hash}`,
+        );
         window.location.replace(`#cke_${hash}`);
       }
     }
   }
 
-  $(window).on('hashchange.ckeditor', redirectTextareaFragmentToCKEditor5Instance);
+  $(window).on(
+    'hashchange.ckeditor',
+    redirectTextareaFragmentToCKEditor5Instance,
+  );
+
+  // Respond to new dialogs that are opened by CKEditor, closing the AJAX loader.
   $(window).on('dialog:beforecreate', () => {
-    $('.ckeditor5-dialog-loading').animate({
-      top: '-40px'
-    }, function removeDialogLoading() {
-      $(this).remove();
-    });
+    $('.ckeditor5-dialog-loading').animate(
+      { top: '-40px' },
+      function removeDialogLoading() {
+        $(this).remove();
+      },
+    );
   });
+
+  // Respond to dialogs that are saved, sending data back to CKEditor.
   $(window).on('editor:dialogsave', (e, values) => {
     if (Drupal.ckeditor5.saveCallback) {
       Drupal.ckeditor5.saveCallback(values);
     }
   });
+
+  // Respond to dialogs that are closed, removing the current save handler.
   $(window).on('dialog:afterclose', () => {
     if (Drupal.ckeditor5.saveCallback) {
       Drupal.ckeditor5.saveCallback = null;
     }
   });
-})(Drupal, Drupal.debounce, CKEditor5, jQuery, once);
\ No newline at end of file
+})(Drupal, Drupal.debounce, CKEditor5, jQuery, once);
diff --git a/core/modules/ckeditor5/js/ckeditor5.style.admin.es6.js b/core/modules/ckeditor5/js/ckeditor5.style.admin.es6.js
deleted file mode 100644
index f44521613513..000000000000
--- a/core/modules/ckeditor5/js/ckeditor5.style.admin.es6.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * @file
- * CKEditor 5 Style admin behavior.
- */
-
-(function ($, Drupal) {
-  /**
-   * Provides the summary for the "style" plugin settings vertical tab.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches summary behavior to the plugin settings vertical tab.
-   */
-  Drupal.behaviors.ckeditor5StyleSettingsSummary = {
-    attach() {
-      $('[data-ckeditor5-plugin-id="ckeditor5_style"]').drupalSetSummary(
-        (context) => {
-          const stylesElement = document.querySelector(
-            '[data-drupal-selector="edit-editor-settings-plugins-ckeditor5-style-styles"]',
-          );
-          const styleCount = stylesElement.value
-            .split('\n')
-            // Minimum length is 5: "p.z|Z" is the shortest possible style definition.
-            .filter((line) => line.trim().length >= 5).length;
-
-          if (styleCount === 0) {
-            return Drupal.t('No styles configured');
-          }
-          return Drupal.formatPlural(
-            styleCount,
-            'One style configured',
-            '@count styles configured',
-          );
-        },
-      );
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/ckeditor5/js/ckeditor5.style.admin.js b/core/modules/ckeditor5/js/ckeditor5.style.admin.js
index ffdf5db5c468..f44521613513 100644
--- a/core/modules/ckeditor5/js/ckeditor5.style.admin.js
+++ b/core/modules/ckeditor5/js/ckeditor5.style.admin.js
@@ -1,24 +1,39 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * CKEditor 5 Style admin behavior.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Provides the summary for the "style" plugin settings vertical tab.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches summary behavior to the plugin settings vertical tab.
+   */
   Drupal.behaviors.ckeditor5StyleSettingsSummary = {
     attach() {
-      $('[data-ckeditor5-plugin-id="ckeditor5_style"]').drupalSetSummary(context => {
-        const stylesElement = document.querySelector('[data-drupal-selector="edit-editor-settings-plugins-ckeditor5-style-styles"]');
-        const styleCount = stylesElement.value.split('\n').filter(line => line.trim().length >= 5).length;
-
-        if (styleCount === 0) {
-          return Drupal.t('No styles configured');
-        }
-
-        return Drupal.formatPlural(styleCount, 'One style configured', '@count styles configured');
-      });
-    }
+      $('[data-ckeditor5-plugin-id="ckeditor5_style"]').drupalSetSummary(
+        (context) => {
+          const stylesElement = document.querySelector(
+            '[data-drupal-selector="edit-editor-settings-plugins-ckeditor5-style-styles"]',
+          );
+          const styleCount = stylesElement.value
+            .split('\n')
+            // Minimum length is 5: "p.z|Z" is the shortest possible style definition.
+            .filter((line) => line.trim().length >= 5).length;
 
+          if (styleCount === 0) {
+            return Drupal.t('No styles configured');
+          }
+          return Drupal.formatPlural(
+            styleCount,
+            'One style configured',
+            '@count styles configured',
+          );
+        },
+      );
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/ckeditor5/tests/src/Nightwatch/Tests/drupalHtmlBuilderTest.es6.js b/core/modules/ckeditor5/tests/src/Nightwatch/Tests/drupalHtmlBuilderTest.es6.js
deleted file mode 100644
index 906097a3f7be..000000000000
--- a/core/modules/ckeditor5/tests/src/Nightwatch/Tests/drupalHtmlBuilderTest.es6.js
+++ /dev/null
@@ -1,131 +0,0 @@
-const assert = require('assert');
-const fs = require('fs');
-const path = require('path');
-// eslint-disable-next-line import/no-extraneous-dependencies
-const { JSDOM } = require('jsdom');
-
-// Nightwatch doesn't support ES modules. This workaround loads the class
-// directly here.
-// @todo remove this after https://www.drupal.org/project/drupal/issues/3247647
-//   has been resolved.
-// eslint-disable-next-line no-eval
-const DrupalHtmlBuilder = eval(
-  `(${fs
-    .readFileSync(
-      path.resolve(
-        __dirname,
-        '../../../../js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js',
-      ),
-    )
-    .toString()})`.replace('export default', ''),
-);
-const { document, Node } = new JSDOM(`<!DOCTYPE html>`).window;
-
-module.exports = {
-  '@tags': ['ckeditor5'],
-  '@unitTest': true,
-  'should return empty string when empty DocumentFragment is passed':
-    function () {
-      const drupalHtmlBuilder = new DrupalHtmlBuilder();
-      drupalHtmlBuilder.appendNode(document.createDocumentFragment());
-      assert.equal(drupalHtmlBuilder.build(), '');
-    },
-  'should create text from single text node': function () {
-    const drupalHtmlBuilder = new DrupalHtmlBuilder();
-    const text = 'foo bar';
-    const fragment = document.createDocumentFragment();
-    const textNode = document.createTextNode(text);
-    fragment.appendChild(textNode);
-
-    drupalHtmlBuilder.appendNode(fragment);
-    assert.equal(drupalHtmlBuilder.build(), text);
-  },
-  'should return correct HTML from fragment with paragraph': function () {
-    const drupalHtmlBuilder = new DrupalHtmlBuilder();
-    const fragment = document.createDocumentFragment();
-    const paragraph = document.createElement('p');
-    paragraph.textContent = 'foo bar';
-    fragment.appendChild(paragraph);
-
-    drupalHtmlBuilder.appendNode(fragment);
-    assert.equal(drupalHtmlBuilder.build(), '<p>foo bar</p>');
-  },
-  'should return correct HTML from fragment with multiple child nodes':
-    function () {
-      const drupalHtmlBuilder = new DrupalHtmlBuilder();
-      const fragment = document.createDocumentFragment();
-      const text = document.createTextNode('foo bar');
-      const paragraph = document.createElement('p');
-      const div = document.createElement('div');
-
-      paragraph.textContent = 'foo';
-      div.textContent = 'bar';
-
-      fragment.appendChild(text);
-      fragment.appendChild(paragraph);
-      fragment.appendChild(div);
-
-      drupalHtmlBuilder.appendNode(fragment);
-
-      assert.equal(
-        drupalHtmlBuilder.build(),
-        'foo bar<p>foo</p><div>bar</div>',
-      );
-    },
-  'should return correct HTML from fragment with comment': function () {
-    const drupalHtmlBuilder = new DrupalHtmlBuilder();
-    const fragment = document.createDocumentFragment();
-    const div = document.createElement('div');
-    const comment = document.createComment('bar');
-    div.textContent = 'bar';
-
-    fragment.appendChild(div);
-    fragment.appendChild(comment);
-
-    drupalHtmlBuilder.appendNode(fragment);
-
-    assert.equal(drupalHtmlBuilder.build(), '<div>bar</div>');
-  },
-  'should return correct HTML from fragment with attributes': function () {
-    const drupalHtmlBuilder = new DrupalHtmlBuilder();
-    const fragment = document.createDocumentFragment();
-    const div = document.createElement('div');
-    div.setAttribute('id', 'foo');
-    div.classList.add('bar');
-    div.textContent = 'baz';
-
-    fragment.appendChild(div);
-    drupalHtmlBuilder.appendNode(fragment);
-
-    assert.equal(
-      drupalHtmlBuilder.build(),
-      '<div id="foo" class="bar">baz</div>',
-    );
-  },
-  'should return correct HTML from fragment with self closing tag':
-    function () {
-      const drupalHtmlBuilder = new DrupalHtmlBuilder();
-      const fragment = document.createDocumentFragment();
-      const hr = document.createElement('hr');
-
-      fragment.appendChild(hr);
-      drupalHtmlBuilder.appendNode(fragment);
-
-      assert.equal(drupalHtmlBuilder.build(), '<hr>');
-    },
-  'attribute values should be escaped': function () {
-    const drupalHtmlBuilder = new DrupalHtmlBuilder();
-    const fragment = document.createDocumentFragment();
-    const div = document.createElement('div');
-    div.setAttribute('data-caption', 'Kittens & llamas are <em>cute</em>');
-    div.textContent = 'foo';
-
-    fragment.appendChild(div);
-    drupalHtmlBuilder.appendNode(fragment);
-
-    assert.equal(
-      drupalHtmlBuilder.build(),
-      '<div data-caption="Kittens &amp; llamas are &lt;em&gt;cute&lt;/em&gt;">foo</div>',
-    );
-  },
-};
diff --git a/core/modules/ckeditor5/tests/src/Nightwatch/Tests/drupalHtmlBuilderTest.js b/core/modules/ckeditor5/tests/src/Nightwatch/Tests/drupalHtmlBuilderTest.js
index cb40904c511e..906097a3f7be 100644
--- a/core/modules/ckeditor5/tests/src/Nightwatch/Tests/drupalHtmlBuilderTest.js
+++ b/core/modules/ckeditor5/tests/src/Nightwatch/Tests/drupalHtmlBuilderTest.js
@@ -1,39 +1,42 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
 const assert = require('assert');
-
 const fs = require('fs');
-
 const path = require('path');
+// eslint-disable-next-line import/no-extraneous-dependencies
+const { JSDOM } = require('jsdom');
 
-const {
-  JSDOM
-} = require('jsdom');
+// Nightwatch doesn't support ES modules. This workaround loads the class
+// directly here.
+// @todo remove this after https://www.drupal.org/project/drupal/issues/3247647
+//   has been resolved.
+// eslint-disable-next-line no-eval
+const DrupalHtmlBuilder = eval(
+  `(${fs
+    .readFileSync(
+      path.resolve(
+        __dirname,
+        '../../../../js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js',
+      ),
+    )
+    .toString()})`.replace('export default', ''),
+);
+const { document, Node } = new JSDOM(`<!DOCTYPE html>`).window;
 
-const DrupalHtmlBuilder = eval(`(${fs.readFileSync(path.resolve(__dirname, '../../../../js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js')).toString()})`.replace('export default', ''));
-const {
-  document,
-  Node
-} = new JSDOM(`<!DOCTYPE html>`).window;
 module.exports = {
   '@tags': ['ckeditor5'],
   '@unitTest': true,
-  'should return empty string when empty DocumentFragment is passed': function () {
-    const drupalHtmlBuilder = new DrupalHtmlBuilder();
-    drupalHtmlBuilder.appendNode(document.createDocumentFragment());
-    assert.equal(drupalHtmlBuilder.build(), '');
-  },
+  'should return empty string when empty DocumentFragment is passed':
+    function () {
+      const drupalHtmlBuilder = new DrupalHtmlBuilder();
+      drupalHtmlBuilder.appendNode(document.createDocumentFragment());
+      assert.equal(drupalHtmlBuilder.build(), '');
+    },
   'should create text from single text node': function () {
     const drupalHtmlBuilder = new DrupalHtmlBuilder();
     const text = 'foo bar';
     const fragment = document.createDocumentFragment();
     const textNode = document.createTextNode(text);
     fragment.appendChild(textNode);
+
     drupalHtmlBuilder.appendNode(fragment);
     assert.equal(drupalHtmlBuilder.build(), text);
   },
@@ -43,32 +46,44 @@ module.exports = {
     const paragraph = document.createElement('p');
     paragraph.textContent = 'foo bar';
     fragment.appendChild(paragraph);
+
     drupalHtmlBuilder.appendNode(fragment);
     assert.equal(drupalHtmlBuilder.build(), '<p>foo bar</p>');
   },
-  'should return correct HTML from fragment with multiple child nodes': function () {
-    const drupalHtmlBuilder = new DrupalHtmlBuilder();
-    const fragment = document.createDocumentFragment();
-    const text = document.createTextNode('foo bar');
-    const paragraph = document.createElement('p');
-    const div = document.createElement('div');
-    paragraph.textContent = 'foo';
-    div.textContent = 'bar';
-    fragment.appendChild(text);
-    fragment.appendChild(paragraph);
-    fragment.appendChild(div);
-    drupalHtmlBuilder.appendNode(fragment);
-    assert.equal(drupalHtmlBuilder.build(), 'foo bar<p>foo</p><div>bar</div>');
-  },
+  'should return correct HTML from fragment with multiple child nodes':
+    function () {
+      const drupalHtmlBuilder = new DrupalHtmlBuilder();
+      const fragment = document.createDocumentFragment();
+      const text = document.createTextNode('foo bar');
+      const paragraph = document.createElement('p');
+      const div = document.createElement('div');
+
+      paragraph.textContent = 'foo';
+      div.textContent = 'bar';
+
+      fragment.appendChild(text);
+      fragment.appendChild(paragraph);
+      fragment.appendChild(div);
+
+      drupalHtmlBuilder.appendNode(fragment);
+
+      assert.equal(
+        drupalHtmlBuilder.build(),
+        'foo bar<p>foo</p><div>bar</div>',
+      );
+    },
   'should return correct HTML from fragment with comment': function () {
     const drupalHtmlBuilder = new DrupalHtmlBuilder();
     const fragment = document.createDocumentFragment();
     const div = document.createElement('div');
     const comment = document.createComment('bar');
     div.textContent = 'bar';
+
     fragment.appendChild(div);
     fragment.appendChild(comment);
+
     drupalHtmlBuilder.appendNode(fragment);
+
     assert.equal(drupalHtmlBuilder.build(), '<div>bar</div>');
   },
   'should return correct HTML from fragment with attributes': function () {
@@ -78,26 +93,39 @@ module.exports = {
     div.setAttribute('id', 'foo');
     div.classList.add('bar');
     div.textContent = 'baz';
+
     fragment.appendChild(div);
     drupalHtmlBuilder.appendNode(fragment);
-    assert.equal(drupalHtmlBuilder.build(), '<div id="foo" class="bar">baz</div>');
-  },
-  'should return correct HTML from fragment with self closing tag': function () {
-    const drupalHtmlBuilder = new DrupalHtmlBuilder();
-    const fragment = document.createDocumentFragment();
-    const hr = document.createElement('hr');
-    fragment.appendChild(hr);
-    drupalHtmlBuilder.appendNode(fragment);
-    assert.equal(drupalHtmlBuilder.build(), '<hr>');
+
+    assert.equal(
+      drupalHtmlBuilder.build(),
+      '<div id="foo" class="bar">baz</div>',
+    );
   },
+  'should return correct HTML from fragment with self closing tag':
+    function () {
+      const drupalHtmlBuilder = new DrupalHtmlBuilder();
+      const fragment = document.createDocumentFragment();
+      const hr = document.createElement('hr');
+
+      fragment.appendChild(hr);
+      drupalHtmlBuilder.appendNode(fragment);
+
+      assert.equal(drupalHtmlBuilder.build(), '<hr>');
+    },
   'attribute values should be escaped': function () {
     const drupalHtmlBuilder = new DrupalHtmlBuilder();
     const fragment = document.createDocumentFragment();
     const div = document.createElement('div');
     div.setAttribute('data-caption', 'Kittens & llamas are <em>cute</em>');
     div.textContent = 'foo';
+
     fragment.appendChild(div);
     drupalHtmlBuilder.appendNode(fragment);
-    assert.equal(drupalHtmlBuilder.build(), '<div data-caption="Kittens &amp; llamas are &lt;em&gt;cute&lt;/em&gt;">foo</div>');
-  }
-};
\ No newline at end of file
+
+    assert.equal(
+      drupalHtmlBuilder.build(),
+      '<div data-caption="Kittens &amp; llamas are &lt;em&gt;cute&lt;/em&gt;">foo</div>',
+    );
+  },
+};
diff --git a/core/modules/comment/comment-entity-form.es6.js b/core/modules/comment/comment-entity-form.es6.js
deleted file mode 100644
index af54d92a9c9e..000000000000
--- a/core/modules/comment/comment-entity-form.es6.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * @file
- * Attaches comment behaviors to the entity form.
- */
-
-(function ($, Drupal) {
-  /**
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.commentFieldsetSummaries = {
-    attach(context) {
-      const $context = $(context);
-      $context
-        .find('fieldset.comment-entity-settings-form')
-        .drupalSetSummary((context) =>
-          Drupal.checkPlain(
-            $(context)
-              .find('.js-form-item-comment input:checked')
-              .next('label')[0].textContent,
-          ),
-        );
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/comment/comment-entity-form.js b/core/modules/comment/comment-entity-form.js
index 7b7c8b0ed644..af54d92a9c9e 100644
--- a/core/modules/comment/comment-entity-form.js
+++ b/core/modules/comment/comment-entity-form.js
@@ -1,16 +1,25 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches comment behaviors to the entity form.
+ */
 
 (function ($, Drupal) {
+  /**
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.commentFieldsetSummaries = {
     attach(context) {
       const $context = $(context);
-      $context.find('fieldset.comment-entity-settings-form').drupalSetSummary(context => Drupal.checkPlain($(context).find('.js-form-item-comment input:checked').next('label')[0].textContent));
-    }
-
+      $context
+        .find('fieldset.comment-entity-settings-form')
+        .drupalSetSummary((context) =>
+          Drupal.checkPlain(
+            $(context)
+              .find('.js-form-item-comment input:checked')
+              .next('label')[0].textContent,
+          ),
+        );
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/comment/js/comment-by-viewer.es6.js b/core/modules/comment/js/comment-by-viewer.es6.js
deleted file mode 100644
index 261c818192ac..000000000000
--- a/core/modules/comment/js/comment-by-viewer.es6.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * @file
- * Attaches behaviors for the Comment module's "by-viewer" class.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Add 'by-viewer' class to comments written by the current user.
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.commentByViewer = {
-    attach(context) {
-      const currentUserID = parseInt(drupalSettings.user.uid, 10);
-      $('[data-comment-user-id]')
-        .filter(function () {
-          return (
-            parseInt(this.getAttribute('data-comment-user-id'), 10) ===
-            currentUserID
-          );
-        })
-        .addClass('by-viewer');
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/comment/js/comment-by-viewer.js b/core/modules/comment/js/comment-by-viewer.js
index 3f47ceeaab27..261c818192ac 100644
--- a/core/modules/comment/js/comment-by-viewer.js
+++ b/core/modules/comment/js/comment-by-viewer.js
@@ -1,18 +1,25 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches behaviors for the Comment module's "by-viewer" class.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * Add 'by-viewer' class to comments written by the current user.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.commentByViewer = {
     attach(context) {
       const currentUserID = parseInt(drupalSettings.user.uid, 10);
-      $('[data-comment-user-id]').filter(function () {
-        return parseInt(this.getAttribute('data-comment-user-id'), 10) === currentUserID;
-      }).addClass('by-viewer');
-    }
-
+      $('[data-comment-user-id]')
+        .filter(function () {
+          return (
+            parseInt(this.getAttribute('data-comment-user-id'), 10) ===
+            currentUserID
+          );
+        })
+        .addClass('by-viewer');
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/comment/js/comment-new-indicator.es6.js b/core/modules/comment/js/comment-new-indicator.es6.js
deleted file mode 100644
index 485af485276a..000000000000
--- a/core/modules/comment/js/comment-new-indicator.es6.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * @file
- * Attaches behaviors for the Comment module's "new" indicator.
- *
- * May only be loaded for authenticated users, with the History module
- * installed.
- */
-
-(function ($, Drupal, window) {
-  /**
-   * Processes the markup for "new comment" indicators.
-   *
-   * @param {Array.<Element>} placeholders
-   *   The elements that should be processed.
-   */
-  function processCommentNewIndicators(placeholders) {
-    let isFirstNewComment = true;
-    const newCommentString = Drupal.t('new');
-    let $placeholder;
-
-    placeholders.forEach((placeholder) => {
-      $placeholder = $(placeholder);
-      const timestamp = parseInt(
-        $placeholder.attr('data-comment-timestamp'),
-        10,
-      );
-      const $node = $placeholder.closest('[data-history-node-id]');
-      const nodeID = $node.attr('data-history-node-id');
-      const lastViewTimestamp = Drupal.history.getLastRead(nodeID);
-
-      if (timestamp > lastViewTimestamp) {
-        // Turn the placeholder into an actual "new" indicator.
-        placeholder.textContent = newCommentString;
-        $placeholder
-          .removeClass('hidden')
-          .closest('.js-comment')
-          // Add 'new' class to the comment, so it can be styled.
-          .addClass('new');
-
-        // Insert "new" anchor just before the "comment-<cid>" anchor if
-        // this is the first new comment in the DOM.
-        if (isFirstNewComment) {
-          isFirstNewComment = false;
-          $placeholder.prev().before('<a id="new"></a>');
-          // If the URL points to the first new comment, then scroll to that
-          // comment.
-          if (window.location.hash === '#new') {
-            window.scrollTo(
-              0,
-              $placeholder.offset().top - Drupal.displace.offsets.top,
-            );
-          }
-        }
-      }
-    });
-  }
-
-  /**
-   * Renders "new" comment indicators wherever necessary.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches "new" comment indicators behavior.
-   */
-  Drupal.behaviors.commentNewIndicator = {
-    attach(context) {
-      // Collect all "new" comment indicator placeholders (and their
-      // corresponding node IDs) newer than 30 days ago that have not already
-      // been read after their last comment timestamp.
-      const nodeIDs = [];
-      const placeholders = once(
-        'history',
-        '[data-comment-timestamp]',
-        context,
-      ).filter((placeholder) => {
-        const $placeholder = $(placeholder);
-        const commentTimestamp = parseInt(
-          $placeholder.attr('data-comment-timestamp'),
-          10,
-        );
-        const nodeID = $placeholder
-          .closest('[data-history-node-id]')
-          .attr('data-history-node-id');
-        if (Drupal.history.needsServerCheck(nodeID, commentTimestamp)) {
-          nodeIDs.push(nodeID);
-          return true;
-        }
-
-        return false;
-      });
-
-      if (placeholders.length === 0) {
-        return;
-      }
-
-      // Fetch the node read timestamps from the server.
-      Drupal.history.fetchTimestamps(nodeIDs, () => {
-        processCommentNewIndicators(placeholders);
-      });
-    },
-  };
-})(jQuery, Drupal, window);
diff --git a/core/modules/comment/js/comment-new-indicator.js b/core/modules/comment/js/comment-new-indicator.js
index 63c6ee24558b..485af485276a 100644
--- a/core/modules/comment/js/comment-new-indicator.js
+++ b/core/modules/comment/js/comment-new-indicator.js
@@ -1,46 +1,87 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches behaviors for the Comment module's "new" indicator.
+ *
+ * May only be loaded for authenticated users, with the History module
+ * installed.
+ */
 
 (function ($, Drupal, window) {
+  /**
+   * Processes the markup for "new comment" indicators.
+   *
+   * @param {Array.<Element>} placeholders
+   *   The elements that should be processed.
+   */
   function processCommentNewIndicators(placeholders) {
     let isFirstNewComment = true;
     const newCommentString = Drupal.t('new');
     let $placeholder;
-    placeholders.forEach(placeholder => {
+
+    placeholders.forEach((placeholder) => {
       $placeholder = $(placeholder);
-      const timestamp = parseInt($placeholder.attr('data-comment-timestamp'), 10);
+      const timestamp = parseInt(
+        $placeholder.attr('data-comment-timestamp'),
+        10,
+      );
       const $node = $placeholder.closest('[data-history-node-id]');
       const nodeID = $node.attr('data-history-node-id');
       const lastViewTimestamp = Drupal.history.getLastRead(nodeID);
 
       if (timestamp > lastViewTimestamp) {
+        // Turn the placeholder into an actual "new" indicator.
         placeholder.textContent = newCommentString;
-        $placeholder.removeClass('hidden').closest('.js-comment').addClass('new');
+        $placeholder
+          .removeClass('hidden')
+          .closest('.js-comment')
+          // Add 'new' class to the comment, so it can be styled.
+          .addClass('new');
 
+        // Insert "new" anchor just before the "comment-<cid>" anchor if
+        // this is the first new comment in the DOM.
         if (isFirstNewComment) {
           isFirstNewComment = false;
           $placeholder.prev().before('<a id="new"></a>');
-
+          // If the URL points to the first new comment, then scroll to that
+          // comment.
           if (window.location.hash === '#new') {
-            window.scrollTo(0, $placeholder.offset().top - Drupal.displace.offsets.top);
+            window.scrollTo(
+              0,
+              $placeholder.offset().top - Drupal.displace.offsets.top,
+            );
           }
         }
       }
     });
   }
 
+  /**
+   * Renders "new" comment indicators wherever necessary.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches "new" comment indicators behavior.
+   */
   Drupal.behaviors.commentNewIndicator = {
     attach(context) {
+      // Collect all "new" comment indicator placeholders (and their
+      // corresponding node IDs) newer than 30 days ago that have not already
+      // been read after their last comment timestamp.
       const nodeIDs = [];
-      const placeholders = once('history', '[data-comment-timestamp]', context).filter(placeholder => {
+      const placeholders = once(
+        'history',
+        '[data-comment-timestamp]',
+        context,
+      ).filter((placeholder) => {
         const $placeholder = $(placeholder);
-        const commentTimestamp = parseInt($placeholder.attr('data-comment-timestamp'), 10);
-        const nodeID = $placeholder.closest('[data-history-node-id]').attr('data-history-node-id');
-
+        const commentTimestamp = parseInt(
+          $placeholder.attr('data-comment-timestamp'),
+          10,
+        );
+        const nodeID = $placeholder
+          .closest('[data-history-node-id]')
+          .attr('data-history-node-id');
         if (Drupal.history.needsServerCheck(nodeID, commentTimestamp)) {
           nodeIDs.push(nodeID);
           return true;
@@ -53,10 +94,10 @@
         return;
       }
 
+      // Fetch the node read timestamps from the server.
       Drupal.history.fetchTimestamps(nodeIDs, () => {
         processCommentNewIndicators(placeholders);
       });
-    }
-
+    },
   };
-})(jQuery, Drupal, window);
\ No newline at end of file
+})(jQuery, Drupal, window);
diff --git a/core/modules/comment/js/node-new-comments-link.es6.js b/core/modules/comment/js/node-new-comments-link.es6.js
deleted file mode 100644
index 074864b4a8ef..000000000000
--- a/core/modules/comment/js/node-new-comments-link.es6.js
+++ /dev/null
@@ -1,195 +0,0 @@
-/**
- * @file
- * Attaches behaviors for the Comment module's "X new comments" link.
- *
- * May only be loaded for authenticated users, with the History module
- * installed.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Hides a "new comment" element.
-   *
-   * @param {jQuery} $placeholder
-   *   The placeholder element of the new comment link.
-   *
-   * @return {jQuery}
-   *   The placeholder element passed in as a parameter.
-   */
-  function hide($placeholder) {
-    return (
-      $placeholder
-        // Find the parent <li>.
-        .closest('.comment-new-comments')
-        // Find the preceding <li>, if any, and give it the 'last' class.
-        .prev()
-        .addClass('last')
-        // Go back to the parent <li> and hide it.
-        .end()
-        .hide()
-    );
-  }
-
-  /**
-   * Removes a "new comment" element.
-   *
-   * @param {jQuery} $placeholder
-   *   The placeholder element of the new comment link.
-   */
-  function remove($placeholder) {
-    hide($placeholder).remove();
-  }
-
-  /**
-   * Shows a "new comment" element.
-   *
-   * @param {jQuery} $placeholder
-   *   The placeholder element of the new comment link.
-   *
-   * @return {jQuery}
-   *   The placeholder element passed in as a parameter.
-   */
-  function show($placeholder) {
-    return (
-      $placeholder
-        // Find the parent <li>.
-        .closest('.comment-new-comments')
-        // Find the preceding <li>, if any, and remove its 'last' class, if any.
-        .prev()
-        .removeClass('last')
-        // Go back to the parent <li> and show it.
-        .end()
-        .show()
-    );
-  }
-
-  /**
-   * Processes new comment links and adds appropriate text in relevant cases.
-   *
-   * @param {Array.<Element>} placeholders
-   *   The placeholder elements of the current page.
-   */
-  function processNodeNewCommentLinks(placeholders) {
-    // Figure out which placeholders need the "x new comments" links.
-    const $placeholdersToUpdate = {};
-    let fieldName = 'comment';
-    let $placeholder;
-    placeholders.forEach((placeholder) => {
-      $placeholder = $(placeholder);
-      const timestamp = parseInt(
-        $placeholder.attr('data-history-node-last-comment-timestamp'),
-        10,
-      );
-      fieldName = $placeholder.attr('data-history-node-field-name');
-      const nodeID = $placeholder
-        .closest('[data-history-node-id]')
-        .attr('data-history-node-id');
-      const lastViewTimestamp = Drupal.history.getLastRead(nodeID);
-
-      // Queue this placeholder's "X new comments" link to be downloaded from
-      // the server.
-      if (timestamp > lastViewTimestamp) {
-        $placeholdersToUpdate[nodeID] = $placeholder;
-      }
-      // No "X new comments" link necessary; remove it from the DOM.
-      else {
-        remove($placeholder);
-      }
-    });
-
-    // Perform an AJAX request to retrieve node view timestamps.
-    const nodeIDs = Object.keys($placeholdersToUpdate);
-    if (nodeIDs.length === 0) {
-      return;
-    }
-
-    /**
-     * Renders the "X new comments" links.
-     *
-     * Either use the data embedded in the page or perform an AJAX request to
-     * retrieve the same data.
-     *
-     * @param {object} results
-     *   Data about new comment links indexed by nodeID.
-     */
-    function render(results) {
-      Object.keys(results || {}).forEach((nodeID) => {
-        if ($placeholdersToUpdate.hasOwnProperty(nodeID)) {
-          const $placeholderItem = $placeholdersToUpdate[nodeID];
-          const result = results[nodeID];
-          $placeholderItem[0].textContent = Drupal.formatPlural(
-            result.new_comment_count,
-            '1 new comment',
-            '@count new comments',
-          );
-          $placeholderItem
-            .attr('href', result.first_new_comment_link)
-            .removeClass('hidden');
-          show($placeholderItem);
-        }
-      });
-    }
-
-    if (drupalSettings.comment && drupalSettings.comment.newCommentsLinks) {
-      render(drupalSettings.comment.newCommentsLinks.node[fieldName]);
-    } else {
-      $.ajax({
-        url: Drupal.url('comments/render_new_comments_node_links'),
-        type: 'POST',
-        data: { 'node_ids[]': nodeIDs, field_name: fieldName },
-        dataType: 'json',
-        success: render,
-      });
-    }
-  }
-
-  /**
-   * Render "X new comments" links wherever necessary.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches new comment links behavior.
-   */
-  Drupal.behaviors.nodeNewCommentsLink = {
-    attach(context) {
-      // Collect all "X new comments" node link placeholders (and their
-      // corresponding node IDs) newer than 30 days ago that have not already
-      // been read after their last comment timestamp.
-      const nodeIDs = [];
-      const placeholders = once(
-        'history',
-        '[data-history-node-last-comment-timestamp]',
-        context,
-      ).filter((placeholder) => {
-        const $placeholder = $(placeholder);
-        const lastCommentTimestamp = parseInt(
-          $placeholder.attr('data-history-node-last-comment-timestamp'),
-          10,
-        );
-        const nodeID = $placeholder
-          .closest('[data-history-node-id]')
-          .attr('data-history-node-id');
-        if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) {
-          nodeIDs.push(nodeID);
-          // Hide this placeholder link until it is certain we'll need it.
-          hide($placeholder);
-          return true;
-        }
-
-        // Remove this placeholder link from the DOM because we won't need it.
-        remove($placeholder);
-        return false;
-      });
-
-      if (placeholders.length === 0) {
-        return;
-      }
-
-      // Perform an AJAX request to retrieve node read timestamps.
-      Drupal.history.fetchTimestamps(nodeIDs, () => {
-        processNodeNewCommentLinks(placeholders);
-      });
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/comment/js/node-new-comments-link.js b/core/modules/comment/js/node-new-comments-link.js
index 6577421f21d6..074864b4a8ef 100644
--- a/core/modules/comment/js/node-new-comments-link.js
+++ b/core/modules/comment/js/node-new-comments-link.js
@@ -1,53 +1,130 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches behaviors for the Comment module's "X new comments" link.
+ *
+ * May only be loaded for authenticated users, with the History module
+ * installed.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * Hides a "new comment" element.
+   *
+   * @param {jQuery} $placeholder
+   *   The placeholder element of the new comment link.
+   *
+   * @return {jQuery}
+   *   The placeholder element passed in as a parameter.
+   */
   function hide($placeholder) {
-    return $placeholder.closest('.comment-new-comments').prev().addClass('last').end().hide();
+    return (
+      $placeholder
+        // Find the parent <li>.
+        .closest('.comment-new-comments')
+        // Find the preceding <li>, if any, and give it the 'last' class.
+        .prev()
+        .addClass('last')
+        // Go back to the parent <li> and hide it.
+        .end()
+        .hide()
+    );
   }
 
+  /**
+   * Removes a "new comment" element.
+   *
+   * @param {jQuery} $placeholder
+   *   The placeholder element of the new comment link.
+   */
   function remove($placeholder) {
     hide($placeholder).remove();
   }
 
+  /**
+   * Shows a "new comment" element.
+   *
+   * @param {jQuery} $placeholder
+   *   The placeholder element of the new comment link.
+   *
+   * @return {jQuery}
+   *   The placeholder element passed in as a parameter.
+   */
   function show($placeholder) {
-    return $placeholder.closest('.comment-new-comments').prev().removeClass('last').end().show();
+    return (
+      $placeholder
+        // Find the parent <li>.
+        .closest('.comment-new-comments')
+        // Find the preceding <li>, if any, and remove its 'last' class, if any.
+        .prev()
+        .removeClass('last')
+        // Go back to the parent <li> and show it.
+        .end()
+        .show()
+    );
   }
 
+  /**
+   * Processes new comment links and adds appropriate text in relevant cases.
+   *
+   * @param {Array.<Element>} placeholders
+   *   The placeholder elements of the current page.
+   */
   function processNodeNewCommentLinks(placeholders) {
+    // Figure out which placeholders need the "x new comments" links.
     const $placeholdersToUpdate = {};
     let fieldName = 'comment';
     let $placeholder;
-    placeholders.forEach(placeholder => {
+    placeholders.forEach((placeholder) => {
       $placeholder = $(placeholder);
-      const timestamp = parseInt($placeholder.attr('data-history-node-last-comment-timestamp'), 10);
+      const timestamp = parseInt(
+        $placeholder.attr('data-history-node-last-comment-timestamp'),
+        10,
+      );
       fieldName = $placeholder.attr('data-history-node-field-name');
-      const nodeID = $placeholder.closest('[data-history-node-id]').attr('data-history-node-id');
+      const nodeID = $placeholder
+        .closest('[data-history-node-id]')
+        .attr('data-history-node-id');
       const lastViewTimestamp = Drupal.history.getLastRead(nodeID);
 
+      // Queue this placeholder's "X new comments" link to be downloaded from
+      // the server.
       if (timestamp > lastViewTimestamp) {
         $placeholdersToUpdate[nodeID] = $placeholder;
-      } else {
+      }
+      // No "X new comments" link necessary; remove it from the DOM.
+      else {
         remove($placeholder);
       }
     });
-    const nodeIDs = Object.keys($placeholdersToUpdate);
 
+    // Perform an AJAX request to retrieve node view timestamps.
+    const nodeIDs = Object.keys($placeholdersToUpdate);
     if (nodeIDs.length === 0) {
       return;
     }
 
+    /**
+     * Renders the "X new comments" links.
+     *
+     * Either use the data embedded in the page or perform an AJAX request to
+     * retrieve the same data.
+     *
+     * @param {object} results
+     *   Data about new comment links indexed by nodeID.
+     */
     function render(results) {
-      Object.keys(results || {}).forEach(nodeID => {
+      Object.keys(results || {}).forEach((nodeID) => {
         if ($placeholdersToUpdate.hasOwnProperty(nodeID)) {
           const $placeholderItem = $placeholdersToUpdate[nodeID];
           const result = results[nodeID];
-          $placeholderItem[0].textContent = Drupal.formatPlural(result.new_comment_count, '1 new comment', '@count new comments');
-          $placeholderItem.attr('href', result.first_new_comment_link).removeClass('hidden');
+          $placeholderItem[0].textContent = Drupal.formatPlural(
+            result.new_comment_count,
+            '1 new comment',
+            '@count new comments',
+          );
+          $placeholderItem
+            .attr('href', result.first_new_comment_link)
+            .removeClass('hidden');
           show($placeholderItem);
         }
       });
@@ -59,30 +136,48 @@
       $.ajax({
         url: Drupal.url('comments/render_new_comments_node_links'),
         type: 'POST',
-        data: {
-          'node_ids[]': nodeIDs,
-          field_name: fieldName
-        },
+        data: { 'node_ids[]': nodeIDs, field_name: fieldName },
         dataType: 'json',
-        success: render
+        success: render,
       });
     }
   }
 
+  /**
+   * Render "X new comments" links wherever necessary.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches new comment links behavior.
+   */
   Drupal.behaviors.nodeNewCommentsLink = {
     attach(context) {
+      // Collect all "X new comments" node link placeholders (and their
+      // corresponding node IDs) newer than 30 days ago that have not already
+      // been read after their last comment timestamp.
       const nodeIDs = [];
-      const placeholders = once('history', '[data-history-node-last-comment-timestamp]', context).filter(placeholder => {
+      const placeholders = once(
+        'history',
+        '[data-history-node-last-comment-timestamp]',
+        context,
+      ).filter((placeholder) => {
         const $placeholder = $(placeholder);
-        const lastCommentTimestamp = parseInt($placeholder.attr('data-history-node-last-comment-timestamp'), 10);
-        const nodeID = $placeholder.closest('[data-history-node-id]').attr('data-history-node-id');
-
+        const lastCommentTimestamp = parseInt(
+          $placeholder.attr('data-history-node-last-comment-timestamp'),
+          10,
+        );
+        const nodeID = $placeholder
+          .closest('[data-history-node-id]')
+          .attr('data-history-node-id');
         if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) {
           nodeIDs.push(nodeID);
+          // Hide this placeholder link until it is certain we'll need it.
           hide($placeholder);
           return true;
         }
 
+        // Remove this placeholder link from the DOM because we won't need it.
         remove($placeholder);
         return false;
       });
@@ -91,10 +186,10 @@
         return;
       }
 
+      // Perform an AJAX request to retrieve node read timestamps.
       Drupal.history.fetchTimestamps(nodeIDs, () => {
         processNodeNewCommentLinks(placeholders);
       });
-    }
-
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/content_translation/content_translation.admin.es6.js b/core/modules/content_translation/content_translation.admin.es6.js
deleted file mode 100644
index d74009ec315b..000000000000
--- a/core/modules/content_translation/content_translation.admin.es6.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * @file
- * Content Translation admin behaviors.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Forces applicable options to be checked as translatable.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches content translation dependent options to the UI.
-   */
-  Drupal.behaviors.contentTranslationDependentOptions = {
-    attach(context) {
-      const $context = $(context);
-      const options = drupalSettings.contentTranslationDependentOptions;
-      let $fields;
-
-      function fieldsChangeHandler($fields, dependentColumns) {
-        return function (e) {
-          Drupal.behaviors.contentTranslationDependentOptions.check(
-            $fields,
-            dependentColumns,
-            $(e.target),
-          );
-        };
-      }
-
-      // We're given a generic name to look for so we find all inputs containing
-      // that name and copy over the input values that require all columns to be
-      // translatable.
-      if (options && options.dependent_selectors) {
-        Object.keys(options.dependent_selectors).forEach((field) => {
-          $fields = $context.find(`input[name^="${field}"]`);
-          const dependentColumns = options.dependent_selectors[field];
-
-          $fields.on('change', fieldsChangeHandler($fields, dependentColumns));
-          Drupal.behaviors.contentTranslationDependentOptions.check(
-            $fields,
-            dependentColumns,
-          );
-        });
-      }
-    },
-    check($fields, dependentColumns, $changed) {
-      let $element = $changed;
-      let column;
-
-      function filterFieldsList(index, field) {
-        return field.value === column;
-      }
-
-      // A field that has many different translatable parts can also define one
-      // or more columns that require all columns to be translatable.
-      Object.keys(dependentColumns || {}).forEach((index) => {
-        column = dependentColumns[index];
-
-        if (!$changed) {
-          $element = $fields.filter(filterFieldsList);
-        }
-
-        if ($element.is(`input[value="${column}"]:checked`)) {
-          $fields.prop('checked', true).not($element).prop('disabled', true);
-        } else {
-          $fields.prop('disabled', false);
-        }
-      });
-    },
-  };
-
-  /**
-   * Makes field translatability inherit bundle translatability.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches content translation behavior.
-   */
-  Drupal.behaviors.contentTranslation = {
-    attach(context) {
-      // Initially hide all field rows for non translatable bundles and all
-      // column rows for non translatable fields.
-      once(
-        'translation-entity-admin-hide',
-        // Keep jQuery because of the use of `:input`.
-        $(context).find('table .bundle-settings .translatable :input'),
-      ).forEach((input) => {
-        const $input = $(input);
-        const $bundleSettings = $input.closest('.bundle-settings');
-        if (!$input.is(':checked')) {
-          $bundleSettings.nextUntil('.bundle-settings').hide();
-        } else {
-          $bundleSettings
-            .nextUntil('.bundle-settings', '.field-settings')
-            .find('.translatable :input:not(:checked)')
-            .closest('.field-settings')
-            .nextUntil(':not(.column-settings)')
-            .hide();
-        }
-      });
-
-      // When a bundle is made translatable all of its fields should inherit
-      // this setting. Instead when it is made non translatable its fields are
-      // hidden, since their translatability no longer matters.
-      $(once('translation-entity-admin-bind', 'body'))
-        .on('click', 'table .bundle-settings .translatable :input', (e) => {
-          const $target = $(e.target);
-          const $bundleSettings = $target.closest('.bundle-settings');
-          const $settings = $bundleSettings.nextUntil('.bundle-settings');
-          const $fieldSettings = $settings.filter('.field-settings');
-          if ($target.is(':checked')) {
-            $bundleSettings
-              .find('.operations :input[name$="[language_alterable]"]')
-              .prop('checked', true);
-            $fieldSettings.find('.translatable :input').prop('checked', true);
-            $settings.show();
-          } else {
-            $settings.hide();
-          }
-        })
-        .on('click', 'table .field-settings .translatable :input', (e) => {
-          const $target = $(e.target);
-          const $fieldSettings = $target.closest('.field-settings');
-          const $columnSettings = $fieldSettings.nextUntil(
-            '.field-settings, .bundle-settings',
-          );
-          if ($target.is(':checked')) {
-            $columnSettings.show();
-          } else {
-            $columnSettings.hide();
-          }
-        });
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/content_translation/content_translation.admin.js b/core/modules/content_translation/content_translation.admin.js
index 768394bcd447..d74009ec315b 100644
--- a/core/modules/content_translation/content_translation.admin.js
+++ b/core/modules/content_translation/content_translation.admin.js
@@ -1,11 +1,17 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Content Translation admin behaviors.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * Forces applicable options to be checked as translatable.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches content translation dependent options to the UI.
+   */
   Drupal.behaviors.contentTranslationDependentOptions = {
     attach(context) {
       const $context = $(context);
@@ -14,20 +20,30 @@
 
       function fieldsChangeHandler($fields, dependentColumns) {
         return function (e) {
-          Drupal.behaviors.contentTranslationDependentOptions.check($fields, dependentColumns, $(e.target));
+          Drupal.behaviors.contentTranslationDependentOptions.check(
+            $fields,
+            dependentColumns,
+            $(e.target),
+          );
         };
       }
 
+      // We're given a generic name to look for so we find all inputs containing
+      // that name and copy over the input values that require all columns to be
+      // translatable.
       if (options && options.dependent_selectors) {
-        Object.keys(options.dependent_selectors).forEach(field => {
+        Object.keys(options.dependent_selectors).forEach((field) => {
           $fields = $context.find(`input[name^="${field}"]`);
           const dependentColumns = options.dependent_selectors[field];
+
           $fields.on('change', fieldsChangeHandler($fields, dependentColumns));
-          Drupal.behaviors.contentTranslationDependentOptions.check($fields, dependentColumns);
+          Drupal.behaviors.contentTranslationDependentOptions.check(
+            $fields,
+            dependentColumns,
+          );
         });
       }
     },
-
     check($fields, dependentColumns, $changed) {
       let $element = $changed;
       let column;
@@ -36,7 +52,9 @@
         return field.value === column;
       }
 
-      Object.keys(dependentColumns || {}).forEach(index => {
+      // A field that has many different translatable parts can also define one
+      // or more columns that require all columns to be translatable.
+      Object.keys(dependentColumns || {}).forEach((index) => {
         column = dependentColumns[index];
 
         if (!$changed) {
@@ -49,46 +67,71 @@
           $fields.prop('disabled', false);
         }
       });
-    }
-
+    },
   };
+
+  /**
+   * Makes field translatability inherit bundle translatability.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches content translation behavior.
+   */
   Drupal.behaviors.contentTranslation = {
     attach(context) {
-      once('translation-entity-admin-hide', $(context).find('table .bundle-settings .translatable :input')).forEach(input => {
+      // Initially hide all field rows for non translatable bundles and all
+      // column rows for non translatable fields.
+      once(
+        'translation-entity-admin-hide',
+        // Keep jQuery because of the use of `:input`.
+        $(context).find('table .bundle-settings .translatable :input'),
+      ).forEach((input) => {
         const $input = $(input);
         const $bundleSettings = $input.closest('.bundle-settings');
-
         if (!$input.is(':checked')) {
           $bundleSettings.nextUntil('.bundle-settings').hide();
         } else {
-          $bundleSettings.nextUntil('.bundle-settings', '.field-settings').find('.translatable :input:not(:checked)').closest('.field-settings').nextUntil(':not(.column-settings)').hide();
+          $bundleSettings
+            .nextUntil('.bundle-settings', '.field-settings')
+            .find('.translatable :input:not(:checked)')
+            .closest('.field-settings')
+            .nextUntil(':not(.column-settings)')
+            .hide();
         }
       });
-      $(once('translation-entity-admin-bind', 'body')).on('click', 'table .bundle-settings .translatable :input', e => {
-        const $target = $(e.target);
-        const $bundleSettings = $target.closest('.bundle-settings');
-        const $settings = $bundleSettings.nextUntil('.bundle-settings');
-        const $fieldSettings = $settings.filter('.field-settings');
-
-        if ($target.is(':checked')) {
-          $bundleSettings.find('.operations :input[name$="[language_alterable]"]').prop('checked', true);
-          $fieldSettings.find('.translatable :input').prop('checked', true);
-          $settings.show();
-        } else {
-          $settings.hide();
-        }
-      }).on('click', 'table .field-settings .translatable :input', e => {
-        const $target = $(e.target);
-        const $fieldSettings = $target.closest('.field-settings');
-        const $columnSettings = $fieldSettings.nextUntil('.field-settings, .bundle-settings');
-
-        if ($target.is(':checked')) {
-          $columnSettings.show();
-        } else {
-          $columnSettings.hide();
-        }
-      });
-    }
 
+      // When a bundle is made translatable all of its fields should inherit
+      // this setting. Instead when it is made non translatable its fields are
+      // hidden, since their translatability no longer matters.
+      $(once('translation-entity-admin-bind', 'body'))
+        .on('click', 'table .bundle-settings .translatable :input', (e) => {
+          const $target = $(e.target);
+          const $bundleSettings = $target.closest('.bundle-settings');
+          const $settings = $bundleSettings.nextUntil('.bundle-settings');
+          const $fieldSettings = $settings.filter('.field-settings');
+          if ($target.is(':checked')) {
+            $bundleSettings
+              .find('.operations :input[name$="[language_alterable]"]')
+              .prop('checked', true);
+            $fieldSettings.find('.translatable :input').prop('checked', true);
+            $settings.show();
+          } else {
+            $settings.hide();
+          }
+        })
+        .on('click', 'table .field-settings .translatable :input', (e) => {
+          const $target = $(e.target);
+          const $fieldSettings = $target.closest('.field-settings');
+          const $columnSettings = $fieldSettings.nextUntil(
+            '.field-settings, .bundle-settings',
+          );
+          if ($target.is(':checked')) {
+            $columnSettings.show();
+          } else {
+            $columnSettings.hide();
+          }
+        });
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/contextual/js/contextual.es6.js b/core/modules/contextual/js/contextual.es6.js
deleted file mode 100644
index b5fe7d094fb0..000000000000
--- a/core/modules/contextual/js/contextual.es6.js
+++ /dev/null
@@ -1,321 +0,0 @@
-/**
- * @file
- * Attaches behaviors for the Contextual module.
- */
-
-(function ($, Drupal, drupalSettings, _, Backbone, JSON, storage) {
-  const options = $.extend(
-    drupalSettings.contextual,
-    // Merge strings on top of drupalSettings so that they are not mutable.
-    {
-      strings: {
-        open: Drupal.t('Open'),
-        close: Drupal.t('Close'),
-      },
-    },
-  );
-
-  // Clear the cached contextual links whenever the current user's set of
-  // permissions changes.
-  const cachedPermissionsHash = storage.getItem(
-    'Drupal.contextual.permissionsHash',
-  );
-  const permissionsHash = drupalSettings.user.permissionsHash;
-  if (cachedPermissionsHash !== permissionsHash) {
-    if (typeof permissionsHash === 'string') {
-      _.chain(storage)
-        .keys()
-        .each((key) => {
-          if (key.substring(0, 18) === 'Drupal.contextual.') {
-            storage.removeItem(key);
-          }
-        });
-    }
-    storage.setItem('Drupal.contextual.permissionsHash', permissionsHash);
-  }
-
-  /**
-   * Determines if a contextual link is nested & overlapping, if so: adjusts it.
-   *
-   * This only deals with two levels of nesting; deeper levels are not touched.
-   *
-   * @param {jQuery} $contextual
-   *   A contextual links placeholder DOM element, containing the actual
-   *   contextual links as rendered by the server.
-   */
-  function adjustIfNestedAndOverlapping($contextual) {
-    const $contextuals = $contextual
-      // @todo confirm that .closest() is not sufficient
-      .parents('.contextual-region')
-      .eq(-1)
-      .find('.contextual');
-
-    // Early-return when there's no nesting.
-    if ($contextuals.length <= 1) {
-      return;
-    }
-
-    // If the two contextual links overlap, then we move the second one.
-    const firstTop = $contextuals.eq(0).offset().top;
-    const secondTop = $contextuals.eq(1).offset().top;
-    if (firstTop === secondTop) {
-      const $nestedContextual = $contextuals.eq(1);
-
-      // Retrieve height of nested contextual link.
-      let height = 0;
-      const $trigger = $nestedContextual.find('.trigger');
-      // Elements with the .visually-hidden class have no dimensions, so this
-      // class must be temporarily removed to the calculate the height.
-      $trigger.removeClass('visually-hidden');
-      height = $nestedContextual.height();
-      $trigger.addClass('visually-hidden');
-
-      // Adjust nested contextual link's position.
-      $nestedContextual.css({ top: $nestedContextual.position().top + height });
-    }
-  }
-
-  /**
-   * Initializes a contextual link: updates its DOM, sets up model and views.
-   *
-   * @param {jQuery} $contextual
-   *   A contextual links placeholder DOM element, containing the actual
-   *   contextual links as rendered by the server.
-   * @param {string} html
-   *   The server-side rendered HTML for this contextual link.
-   */
-  function initContextual($contextual, html) {
-    const $region = $contextual.closest('.contextual-region');
-    const contextual = Drupal.contextual;
-
-    $contextual
-      // Update the placeholder to contain its rendered contextual links.
-      .html(html)
-      // Use the placeholder as a wrapper with a specific class to provide
-      // positioning and behavior attachment context.
-      .addClass('contextual')
-      // Ensure a trigger element exists before the actual contextual links.
-      .prepend(Drupal.theme('contextualTrigger'));
-
-    // Set the destination parameter on each of the contextual links.
-    const destination = `destination=${Drupal.encodePath(
-      Drupal.url(drupalSettings.path.currentPath),
-    )}`;
-    $contextual.find('.contextual-links a').each(function () {
-      const url = this.getAttribute('href');
-      const glue = url.indexOf('?') === -1 ? '?' : '&';
-      this.setAttribute('href', url + glue + destination);
-    });
-
-    let title = '';
-    const $regionHeading = $region.find('h2');
-    if ($regionHeading.length) {
-      title = $regionHeading[0].textContent.trim();
-    }
-    // Create a model and the appropriate views.
-    const model = new contextual.StateModel({
-      title,
-    });
-    const viewOptions = $.extend({ el: $contextual, model }, options);
-    contextual.views.push({
-      visual: new contextual.VisualView(viewOptions),
-      aural: new contextual.AuralView(viewOptions),
-      keyboard: new contextual.KeyboardView(viewOptions),
-    });
-    contextual.regionViews.push(
-      new contextual.RegionView($.extend({ el: $region, model }, options)),
-    );
-
-    // Add the model to the collection. This must happen after the views have
-    // been associated with it, otherwise collection change event handlers can't
-    // trigger the model change event handler in its views.
-    contextual.collection.add(model);
-
-    // Let other JavaScript react to the adding of a new contextual link.
-    $(document).trigger(
-      'drupalContextualLinkAdded',
-      Drupal.deprecatedProperty({
-        target: {
-          $el: $contextual,
-          $region,
-          model,
-        },
-        deprecatedProperty: 'model',
-        message:
-          'The model property is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no replacement.',
-      }),
-    );
-
-    // Fix visual collisions between contextual link triggers.
-    adjustIfNestedAndOverlapping($contextual);
-  }
-
-  /**
-   * Attaches outline behavior for regions associated with contextual links.
-   *
-   * Events
-   *   Contextual triggers an event that can be used by other scripts.
-   *   - drupalContextualLinkAdded: Triggered when a contextual link is added.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *  Attaches the outline behavior to the right context.
-   */
-  Drupal.behaviors.contextual = {
-    attach(context) {
-      const $context = $(context);
-
-      // Find all contextual links placeholders, if any.
-      let $placeholders = $(
-        once('contextual-render', '[data-contextual-id]', context),
-      );
-      if ($placeholders.length === 0) {
-        return;
-      }
-
-      // Collect the IDs for all contextual links placeholders.
-      const ids = [];
-      $placeholders.each(function () {
-        ids.push({
-          id: $(this).attr('data-contextual-id'),
-          token: $(this).attr('data-contextual-token'),
-        });
-      });
-
-      const uncachedIDs = [];
-      const uncachedTokens = [];
-      ids.forEach((contextualID) => {
-        const html = storage.getItem(`Drupal.contextual.${contextualID.id}`);
-        if (html && html.length) {
-          // Initialize after the current execution cycle, to make the AJAX
-          // request for retrieving the uncached contextual links as soon as
-          // possible, but also to ensure that other Drupal behaviors have had
-          // the chance to set up an event listener on the Backbone collection
-          // Drupal.contextual.collection.
-          window.setTimeout(() => {
-            initContextual(
-              $context
-                .find(`[data-contextual-id="${contextualID.id}"]:empty`)
-                .eq(0),
-              html,
-            );
-          });
-          return;
-        }
-        uncachedIDs.push(contextualID.id);
-        uncachedTokens.push(contextualID.token);
-      });
-
-      // Perform an AJAX request to let the server render the contextual links
-      // for each of the placeholders.
-      if (uncachedIDs.length > 0) {
-        $.ajax({
-          url: Drupal.url('contextual/render'),
-          type: 'POST',
-          data: { 'ids[]': uncachedIDs, 'tokens[]': uncachedTokens },
-          dataType: 'json',
-          success(results) {
-            _.each(results, (html, contextualID) => {
-              // Store the metadata.
-              storage.setItem(`Drupal.contextual.${contextualID}`, html);
-              // If the rendered contextual links are empty, then the current
-              // user does not have permission to access the associated links:
-              // don't render anything.
-              if (html.length > 0) {
-                // Update the placeholders to contain its rendered contextual
-                // links. Usually there will only be one placeholder, but it's
-                // possible for multiple identical placeholders exist on the
-                // page (probably because the same content appears more than
-                // once).
-                $placeholders = $context.find(
-                  `[data-contextual-id="${contextualID}"]`,
-                );
-
-                // Initialize the contextual links.
-                for (let i = 0; i < $placeholders.length; i++) {
-                  initContextual($placeholders.eq(i), html);
-                }
-              }
-            });
-          },
-        });
-      }
-    },
-  };
-
-  /**
-   * Namespace for contextual related functionality.
-   *
-   * @namespace
-   *
-   * @private
-   */
-  Drupal.contextual = {
-    /**
-     * The {@link Drupal.contextual.View} instances associated with each list
-     * element of contextual links.
-     *
-     * @type {Array}
-     *
-     * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-     *  replacement.
-     */
-    views: [],
-
-    /**
-     * The {@link Drupal.contextual.RegionView} instances associated with each
-     * contextual region element.
-     *
-     * @type {Array}
-     *
-     * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-     *  replacement.
-     */
-    regionViews: [],
-  };
-
-  /**
-   * A Backbone.Collection of {@link Drupal.contextual.StateModel} instances.
-   *
-   * @type {Backbone.Collection}
-   *
-   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-   *  replacement.
-   */
-  Drupal.contextual.collection = new Backbone.Collection([], {
-    model: Drupal.contextual.StateModel,
-  });
-
-  /**
-   * A trigger is an interactive element often bound to a click handler.
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   */
-  Drupal.theme.contextualTrigger = function () {
-    return '<button class="trigger visually-hidden focusable" type="button"></button>';
-  };
-
-  /**
-   * Bind Ajax contextual links when added.
-   *
-   * @param {jQuery.Event} event
-   *   The `drupalContextualLinkAdded` event.
-   * @param {object} data
-   *   An object containing the data relevant to the event.
-   *
-   * @listens event:drupalContextualLinkAdded
-   */
-  $(document).on('drupalContextualLinkAdded', (event, data) => {
-    Drupal.ajax.bindAjaxLinks(data.$el[0]);
-  });
-})(
-  jQuery,
-  Drupal,
-  drupalSettings,
-  _,
-  Backbone,
-  window.JSON,
-  window.sessionStorage,
-);
diff --git a/core/modules/contextual/js/contextual.js b/core/modules/contextual/js/contextual.js
index f4abf7ec1573..b5fe7d094fb0 100644
--- a/core/modules/contextual/js/contextual.js
+++ b/core/modules/contextual/js/contextual.js
@@ -1,175 +1,321 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches behaviors for the Contextual module.
+ */
 
 (function ($, Drupal, drupalSettings, _, Backbone, JSON, storage) {
-  const options = $.extend(drupalSettings.contextual, {
-    strings: {
-      open: Drupal.t('Open'),
-      close: Drupal.t('Close')
-    }
-  });
-  const cachedPermissionsHash = storage.getItem('Drupal.contextual.permissionsHash');
-  const permissionsHash = drupalSettings.user.permissionsHash;
+  const options = $.extend(
+    drupalSettings.contextual,
+    // Merge strings on top of drupalSettings so that they are not mutable.
+    {
+      strings: {
+        open: Drupal.t('Open'),
+        close: Drupal.t('Close'),
+      },
+    },
+  );
 
+  // Clear the cached contextual links whenever the current user's set of
+  // permissions changes.
+  const cachedPermissionsHash = storage.getItem(
+    'Drupal.contextual.permissionsHash',
+  );
+  const permissionsHash = drupalSettings.user.permissionsHash;
   if (cachedPermissionsHash !== permissionsHash) {
     if (typeof permissionsHash === 'string') {
-      _.chain(storage).keys().each(key => {
-        if (key.substring(0, 18) === 'Drupal.contextual.') {
-          storage.removeItem(key);
-        }
-      });
+      _.chain(storage)
+        .keys()
+        .each((key) => {
+          if (key.substring(0, 18) === 'Drupal.contextual.') {
+            storage.removeItem(key);
+          }
+        });
     }
-
     storage.setItem('Drupal.contextual.permissionsHash', permissionsHash);
   }
 
+  /**
+   * Determines if a contextual link is nested & overlapping, if so: adjusts it.
+   *
+   * This only deals with two levels of nesting; deeper levels are not touched.
+   *
+   * @param {jQuery} $contextual
+   *   A contextual links placeholder DOM element, containing the actual
+   *   contextual links as rendered by the server.
+   */
   function adjustIfNestedAndOverlapping($contextual) {
-    const $contextuals = $contextual.parents('.contextual-region').eq(-1).find('.contextual');
+    const $contextuals = $contextual
+      // @todo confirm that .closest() is not sufficient
+      .parents('.contextual-region')
+      .eq(-1)
+      .find('.contextual');
 
+    // Early-return when there's no nesting.
     if ($contextuals.length <= 1) {
       return;
     }
 
+    // If the two contextual links overlap, then we move the second one.
     const firstTop = $contextuals.eq(0).offset().top;
     const secondTop = $contextuals.eq(1).offset().top;
-
     if (firstTop === secondTop) {
       const $nestedContextual = $contextuals.eq(1);
+
+      // Retrieve height of nested contextual link.
       let height = 0;
       const $trigger = $nestedContextual.find('.trigger');
+      // Elements with the .visually-hidden class have no dimensions, so this
+      // class must be temporarily removed to the calculate the height.
       $trigger.removeClass('visually-hidden');
       height = $nestedContextual.height();
       $trigger.addClass('visually-hidden');
-      $nestedContextual.css({
-        top: $nestedContextual.position().top + height
-      });
+
+      // Adjust nested contextual link's position.
+      $nestedContextual.css({ top: $nestedContextual.position().top + height });
     }
   }
 
+  /**
+   * Initializes a contextual link: updates its DOM, sets up model and views.
+   *
+   * @param {jQuery} $contextual
+   *   A contextual links placeholder DOM element, containing the actual
+   *   contextual links as rendered by the server.
+   * @param {string} html
+   *   The server-side rendered HTML for this contextual link.
+   */
   function initContextual($contextual, html) {
     const $region = $contextual.closest('.contextual-region');
     const contextual = Drupal.contextual;
-    $contextual.html(html).addClass('contextual').prepend(Drupal.theme('contextualTrigger'));
-    const destination = `destination=${Drupal.encodePath(Drupal.url(drupalSettings.path.currentPath))}`;
+
+    $contextual
+      // Update the placeholder to contain its rendered contextual links.
+      .html(html)
+      // Use the placeholder as a wrapper with a specific class to provide
+      // positioning and behavior attachment context.
+      .addClass('contextual')
+      // Ensure a trigger element exists before the actual contextual links.
+      .prepend(Drupal.theme('contextualTrigger'));
+
+    // Set the destination parameter on each of the contextual links.
+    const destination = `destination=${Drupal.encodePath(
+      Drupal.url(drupalSettings.path.currentPath),
+    )}`;
     $contextual.find('.contextual-links a').each(function () {
       const url = this.getAttribute('href');
       const glue = url.indexOf('?') === -1 ? '?' : '&';
       this.setAttribute('href', url + glue + destination);
     });
+
     let title = '';
     const $regionHeading = $region.find('h2');
-
     if ($regionHeading.length) {
       title = $regionHeading[0].textContent.trim();
     }
-
+    // Create a model and the appropriate views.
     const model = new contextual.StateModel({
-      title
+      title,
     });
-    const viewOptions = $.extend({
-      el: $contextual,
-      model
-    }, options);
+    const viewOptions = $.extend({ el: $contextual, model }, options);
     contextual.views.push({
       visual: new contextual.VisualView(viewOptions),
       aural: new contextual.AuralView(viewOptions),
-      keyboard: new contextual.KeyboardView(viewOptions)
+      keyboard: new contextual.KeyboardView(viewOptions),
     });
-    contextual.regionViews.push(new contextual.RegionView($.extend({
-      el: $region,
-      model
-    }, options)));
+    contextual.regionViews.push(
+      new contextual.RegionView($.extend({ el: $region, model }, options)),
+    );
+
+    // Add the model to the collection. This must happen after the views have
+    // been associated with it, otherwise collection change event handlers can't
+    // trigger the model change event handler in its views.
     contextual.collection.add(model);
-    $(document).trigger('drupalContextualLinkAdded', Drupal.deprecatedProperty({
-      target: {
-        $el: $contextual,
-        $region,
-        model
-      },
-      deprecatedProperty: 'model',
-      message: 'The model property is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no replacement.'
-    }));
+
+    // Let other JavaScript react to the adding of a new contextual link.
+    $(document).trigger(
+      'drupalContextualLinkAdded',
+      Drupal.deprecatedProperty({
+        target: {
+          $el: $contextual,
+          $region,
+          model,
+        },
+        deprecatedProperty: 'model',
+        message:
+          'The model property is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no replacement.',
+      }),
+    );
+
+    // Fix visual collisions between contextual link triggers.
     adjustIfNestedAndOverlapping($contextual);
   }
 
+  /**
+   * Attaches outline behavior for regions associated with contextual links.
+   *
+   * Events
+   *   Contextual triggers an event that can be used by other scripts.
+   *   - drupalContextualLinkAdded: Triggered when a contextual link is added.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *  Attaches the outline behavior to the right context.
+   */
   Drupal.behaviors.contextual = {
     attach(context) {
       const $context = $(context);
-      let $placeholders = $(once('contextual-render', '[data-contextual-id]', context));
 
+      // Find all contextual links placeholders, if any.
+      let $placeholders = $(
+        once('contextual-render', '[data-contextual-id]', context),
+      );
       if ($placeholders.length === 0) {
         return;
       }
 
+      // Collect the IDs for all contextual links placeholders.
       const ids = [];
       $placeholders.each(function () {
         ids.push({
           id: $(this).attr('data-contextual-id'),
-          token: $(this).attr('data-contextual-token')
+          token: $(this).attr('data-contextual-token'),
         });
       });
+
       const uncachedIDs = [];
       const uncachedTokens = [];
-      ids.forEach(contextualID => {
+      ids.forEach((contextualID) => {
         const html = storage.getItem(`Drupal.contextual.${contextualID.id}`);
-
         if (html && html.length) {
+          // Initialize after the current execution cycle, to make the AJAX
+          // request for retrieving the uncached contextual links as soon as
+          // possible, but also to ensure that other Drupal behaviors have had
+          // the chance to set up an event listener on the Backbone collection
+          // Drupal.contextual.collection.
           window.setTimeout(() => {
-            initContextual($context.find(`[data-contextual-id="${contextualID.id}"]:empty`).eq(0), html);
+            initContextual(
+              $context
+                .find(`[data-contextual-id="${contextualID.id}"]:empty`)
+                .eq(0),
+              html,
+            );
           });
           return;
         }
-
         uncachedIDs.push(contextualID.id);
         uncachedTokens.push(contextualID.token);
       });
 
+      // Perform an AJAX request to let the server render the contextual links
+      // for each of the placeholders.
       if (uncachedIDs.length > 0) {
         $.ajax({
           url: Drupal.url('contextual/render'),
           type: 'POST',
-          data: {
-            'ids[]': uncachedIDs,
-            'tokens[]': uncachedTokens
-          },
+          data: { 'ids[]': uncachedIDs, 'tokens[]': uncachedTokens },
           dataType: 'json',
-
           success(results) {
             _.each(results, (html, contextualID) => {
+              // Store the metadata.
               storage.setItem(`Drupal.contextual.${contextualID}`, html);
-
+              // If the rendered contextual links are empty, then the current
+              // user does not have permission to access the associated links:
+              // don't render anything.
               if (html.length > 0) {
-                $placeholders = $context.find(`[data-contextual-id="${contextualID}"]`);
+                // Update the placeholders to contain its rendered contextual
+                // links. Usually there will only be one placeholder, but it's
+                // possible for multiple identical placeholders exist on the
+                // page (probably because the same content appears more than
+                // once).
+                $placeholders = $context.find(
+                  `[data-contextual-id="${contextualID}"]`,
+                );
 
+                // Initialize the contextual links.
                 for (let i = 0; i < $placeholders.length; i++) {
                   initContextual($placeholders.eq(i), html);
                 }
               }
             });
-          }
-
+          },
         });
       }
-    }
-
+    },
   };
+
+  /**
+   * Namespace for contextual related functionality.
+   *
+   * @namespace
+   *
+   * @private
+   */
   Drupal.contextual = {
+    /**
+     * The {@link Drupal.contextual.View} instances associated with each list
+     * element of contextual links.
+     *
+     * @type {Array}
+     *
+     * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+     *  replacement.
+     */
     views: [],
-    regionViews: []
+
+    /**
+     * The {@link Drupal.contextual.RegionView} instances associated with each
+     * contextual region element.
+     *
+     * @type {Array}
+     *
+     * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+     *  replacement.
+     */
+    regionViews: [],
   };
+
+  /**
+   * A Backbone.Collection of {@link Drupal.contextual.StateModel} instances.
+   *
+   * @type {Backbone.Collection}
+   *
+   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+   *  replacement.
+   */
   Drupal.contextual.collection = new Backbone.Collection([], {
-    model: Drupal.contextual.StateModel
+    model: Drupal.contextual.StateModel,
   });
 
+  /**
+   * A trigger is an interactive element often bound to a click handler.
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   */
   Drupal.theme.contextualTrigger = function () {
     return '<button class="trigger visually-hidden focusable" type="button"></button>';
   };
 
+  /**
+   * Bind Ajax contextual links when added.
+   *
+   * @param {jQuery.Event} event
+   *   The `drupalContextualLinkAdded` event.
+   * @param {object} data
+   *   An object containing the data relevant to the event.
+   *
+   * @listens event:drupalContextualLinkAdded
+   */
   $(document).on('drupalContextualLinkAdded', (event, data) => {
     Drupal.ajax.bindAjaxLinks(data.$el[0]);
   });
-})(jQuery, Drupal, drupalSettings, _, Backbone, window.JSON, window.sessionStorage);
\ No newline at end of file
+})(
+  jQuery,
+  Drupal,
+  drupalSettings,
+  _,
+  Backbone,
+  window.JSON,
+  window.sessionStorage,
+);
diff --git a/core/modules/contextual/js/contextual.toolbar.es6.js b/core/modules/contextual/js/contextual.toolbar.es6.js
deleted file mode 100644
index 2cbac3e139c5..000000000000
--- a/core/modules/contextual/js/contextual.toolbar.es6.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * @file
- * Attaches behaviors for the Contextual module's edit toolbar tab.
- */
-
-(function ($, Drupal, Backbone) {
-  const strings = {
-    tabbingReleased: Drupal.t(
-      'Tabbing is no longer constrained by the Contextual module.',
-    ),
-    tabbingConstrained: Drupal.t(
-      'Tabbing is constrained to a set of @contextualsCount and the edit mode toggle.',
-    ),
-    pressEsc: Drupal.t('Press the esc key to exit.'),
-  };
-
-  /**
-   * Initializes a contextual link: updates its DOM, sets up model and views.
-   *
-   * @param {HTMLElement} context
-   *   A contextual links DOM element as rendered by the server.
-   */
-  function initContextualToolbar(context) {
-    if (!Drupal.contextual || !Drupal.contextual.collection) {
-      return;
-    }
-
-    const contextualToolbar = Drupal.contextualToolbar;
-    contextualToolbar.model = new contextualToolbar.StateModel(
-      {
-        // Checks whether localStorage indicates we should start in edit mode
-        // rather than view mode.
-        // @see Drupal.contextualToolbar.VisualView.persist
-        isViewing:
-          localStorage.getItem('Drupal.contextualToolbar.isViewing') !==
-          'false',
-      },
-      {
-        contextualCollection: Drupal.contextual.collection,
-      },
-    );
-
-    const viewOptions = {
-      el: $('.toolbar .toolbar-bar .contextual-toolbar-tab'),
-      model: contextualToolbar.model,
-      strings,
-    };
-    new contextualToolbar.VisualView(viewOptions);
-    new contextualToolbar.AuralView(viewOptions);
-  }
-
-  /**
-   * Attaches contextual's edit toolbar tab behavior.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches contextual toolbar behavior on a contextualToolbar-init event.
-   */
-  Drupal.behaviors.contextualToolbar = {
-    attach(context) {
-      if (once('contextualToolbar-init', 'body').length) {
-        initContextualToolbar(context);
-      }
-    },
-  };
-
-  /**
-   * Namespace for the contextual toolbar.
-   *
-   * @namespace
-   *
-   * @private
-   */
-  Drupal.contextualToolbar = {
-    /**
-     * The {@link Drupal.contextualToolbar.StateModel} instance.
-     *
-     * @type {?Drupal.contextualToolbar.StateModel}
-     *
-     * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is
-     * no replacement.
-     */
-    model: null,
-  };
-})(jQuery, Drupal, Backbone);
diff --git a/core/modules/contextual/js/contextual.toolbar.js b/core/modules/contextual/js/contextual.toolbar.js
index 4a5673a6e272..2cbac3e139c5 100644
--- a/core/modules/contextual/js/contextual.toolbar.js
+++ b/core/modules/contextual/js/contextual.toolbar.js
@@ -1,46 +1,86 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches behaviors for the Contextual module's edit toolbar tab.
+ */
 
 (function ($, Drupal, Backbone) {
   const strings = {
-    tabbingReleased: Drupal.t('Tabbing is no longer constrained by the Contextual module.'),
-    tabbingConstrained: Drupal.t('Tabbing is constrained to a set of @contextualsCount and the edit mode toggle.'),
-    pressEsc: Drupal.t('Press the esc key to exit.')
+    tabbingReleased: Drupal.t(
+      'Tabbing is no longer constrained by the Contextual module.',
+    ),
+    tabbingConstrained: Drupal.t(
+      'Tabbing is constrained to a set of @contextualsCount and the edit mode toggle.',
+    ),
+    pressEsc: Drupal.t('Press the esc key to exit.'),
   };
 
+  /**
+   * Initializes a contextual link: updates its DOM, sets up model and views.
+   *
+   * @param {HTMLElement} context
+   *   A contextual links DOM element as rendered by the server.
+   */
   function initContextualToolbar(context) {
     if (!Drupal.contextual || !Drupal.contextual.collection) {
       return;
     }
 
     const contextualToolbar = Drupal.contextualToolbar;
-    contextualToolbar.model = new contextualToolbar.StateModel({
-      isViewing: localStorage.getItem('Drupal.contextualToolbar.isViewing') !== 'false'
-    }, {
-      contextualCollection: Drupal.contextual.collection
-    });
+    contextualToolbar.model = new contextualToolbar.StateModel(
+      {
+        // Checks whether localStorage indicates we should start in edit mode
+        // rather than view mode.
+        // @see Drupal.contextualToolbar.VisualView.persist
+        isViewing:
+          localStorage.getItem('Drupal.contextualToolbar.isViewing') !==
+          'false',
+      },
+      {
+        contextualCollection: Drupal.contextual.collection,
+      },
+    );
+
     const viewOptions = {
       el: $('.toolbar .toolbar-bar .contextual-toolbar-tab'),
       model: contextualToolbar.model,
-      strings
+      strings,
     };
     new contextualToolbar.VisualView(viewOptions);
     new contextualToolbar.AuralView(viewOptions);
   }
 
+  /**
+   * Attaches contextual's edit toolbar tab behavior.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches contextual toolbar behavior on a contextualToolbar-init event.
+   */
   Drupal.behaviors.contextualToolbar = {
     attach(context) {
       if (once('contextualToolbar-init', 'body').length) {
         initContextualToolbar(context);
       }
-    }
-
+    },
   };
+
+  /**
+   * Namespace for the contextual toolbar.
+   *
+   * @namespace
+   *
+   * @private
+   */
   Drupal.contextualToolbar = {
-    model: null
+    /**
+     * The {@link Drupal.contextualToolbar.StateModel} instance.
+     *
+     * @type {?Drupal.contextualToolbar.StateModel}
+     *
+     * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is
+     * no replacement.
+     */
+    model: null,
   };
-})(jQuery, Drupal, Backbone);
\ No newline at end of file
+})(jQuery, Drupal, Backbone);
diff --git a/core/modules/contextual/js/models/StateModel.es6.js b/core/modules/contextual/js/models/StateModel.es6.js
deleted file mode 100644
index 09fe8ed4eec6..000000000000
--- a/core/modules/contextual/js/models/StateModel.es6.js
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * @file
- * A Backbone Model for the state of a contextual link's trigger, list & region.
- */
-
-(function (Drupal, Backbone) {
-  /**
-   * Models the state of a contextual link's trigger, list & region.
-   *
-   * @constructor
-   *
-   * @augments Backbone.Model
-   *
-   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-   *  replacement.
-   */
-  Drupal.contextual.StateModel = Backbone.Model.extend(
-    /** @lends Drupal.contextual.StateModel# */ {
-      /**
-       * @type {object}
-       *
-       * @prop {string} title
-       * @prop {bool} regionIsHovered
-       * @prop {bool} hasFocus
-       * @prop {bool} isOpen
-       * @prop {bool} isLocked
-       */
-      defaults: /** @lends Drupal.contextual.StateModel# */ {
-        /**
-         * The title of the entity to which these contextual links apply.
-         *
-         * @type {string}
-         */
-        title: '',
-
-        /**
-         * Represents if the contextual region is being hovered.
-         *
-         * @type {bool}
-         */
-        regionIsHovered: false,
-
-        /**
-         * Represents if the contextual trigger or options have focus.
-         *
-         * @type {bool}
-         */
-        hasFocus: false,
-
-        /**
-         * Represents if the contextual options for an entity are available to
-         * be selected (i.e. whether the list of options is visible).
-         *
-         * @type {bool}
-         */
-        isOpen: false,
-
-        /**
-         * When the model is locked, the trigger remains active.
-         *
-         * @type {bool}
-         */
-        isLocked: false,
-      },
-
-      /**
-       * Opens or closes the contextual link.
-       *
-       * If it is opened, then also give focus.
-       *
-       * @return {Drupal.contextual.StateModel}
-       *   The current contextual state model.
-       */
-      toggleOpen() {
-        const newIsOpen = !this.get('isOpen');
-        this.set('isOpen', newIsOpen);
-        if (newIsOpen) {
-          this.focus();
-        }
-        return this;
-      },
-
-      /**
-       * Closes this contextual link.
-       *
-       * Does not call blur() because we want to allow a contextual link to have
-       * focus, yet be closed for example when hovering.
-       *
-       * @return {Drupal.contextual.StateModel}
-       *   The current contextual state model.
-       */
-      close() {
-        this.set('isOpen', false);
-        return this;
-      },
-
-      /**
-       * Gives focus to this contextual link.
-       *
-       * Also closes + removes focus from every other contextual link.
-       *
-       * @return {Drupal.contextual.StateModel}
-       *   The current contextual state model.
-       */
-      focus() {
-        this.set('hasFocus', true);
-        const cid = this.cid;
-        this.collection.each((model) => {
-          if (model.cid !== cid) {
-            model.close().blur();
-          }
-        });
-        return this;
-      },
-
-      /**
-       * Removes focus from this contextual link, unless it is open.
-       *
-       * @return {Drupal.contextual.StateModel}
-       *   The current contextual state model.
-       */
-      blur() {
-        if (!this.get('isOpen')) {
-          this.set('hasFocus', false);
-        }
-        return this;
-      },
-    },
-  );
-})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/models/StateModel.js b/core/modules/contextual/js/models/StateModel.js
index a132a7c1fb26..09fe8ed4eec6 100644
--- a/core/modules/contextual/js/models/StateModel.js
+++ b/core/modules/contextual/js/models/StateModel.js
@@ -1,54 +1,130 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone Model for the state of a contextual link's trigger, list & region.
+ */
 
 (function (Drupal, Backbone) {
-  Drupal.contextual.StateModel = Backbone.Model.extend({
-    defaults: {
-      title: '',
-      regionIsHovered: false,
-      hasFocus: false,
-      isOpen: false,
-      isLocked: false
-    },
+  /**
+   * Models the state of a contextual link's trigger, list & region.
+   *
+   * @constructor
+   *
+   * @augments Backbone.Model
+   *
+   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+   *  replacement.
+   */
+  Drupal.contextual.StateModel = Backbone.Model.extend(
+    /** @lends Drupal.contextual.StateModel# */ {
+      /**
+       * @type {object}
+       *
+       * @prop {string} title
+       * @prop {bool} regionIsHovered
+       * @prop {bool} hasFocus
+       * @prop {bool} isOpen
+       * @prop {bool} isLocked
+       */
+      defaults: /** @lends Drupal.contextual.StateModel# */ {
+        /**
+         * The title of the entity to which these contextual links apply.
+         *
+         * @type {string}
+         */
+        title: '',
 
-    toggleOpen() {
-      const newIsOpen = !this.get('isOpen');
-      this.set('isOpen', newIsOpen);
+        /**
+         * Represents if the contextual region is being hovered.
+         *
+         * @type {bool}
+         */
+        regionIsHovered: false,
 
-      if (newIsOpen) {
-        this.focus();
-      }
+        /**
+         * Represents if the contextual trigger or options have focus.
+         *
+         * @type {bool}
+         */
+        hasFocus: false,
 
-      return this;
-    },
+        /**
+         * Represents if the contextual options for an entity are available to
+         * be selected (i.e. whether the list of options is visible).
+         *
+         * @type {bool}
+         */
+        isOpen: false,
 
-    close() {
-      this.set('isOpen', false);
-      return this;
-    },
+        /**
+         * When the model is locked, the trigger remains active.
+         *
+         * @type {bool}
+         */
+        isLocked: false,
+      },
 
-    focus() {
-      this.set('hasFocus', true);
-      const cid = this.cid;
-      this.collection.each(model => {
-        if (model.cid !== cid) {
-          model.close().blur();
+      /**
+       * Opens or closes the contextual link.
+       *
+       * If it is opened, then also give focus.
+       *
+       * @return {Drupal.contextual.StateModel}
+       *   The current contextual state model.
+       */
+      toggleOpen() {
+        const newIsOpen = !this.get('isOpen');
+        this.set('isOpen', newIsOpen);
+        if (newIsOpen) {
+          this.focus();
         }
-      });
-      return this;
-    },
+        return this;
+      },
 
-    blur() {
-      if (!this.get('isOpen')) {
-        this.set('hasFocus', false);
-      }
+      /**
+       * Closes this contextual link.
+       *
+       * Does not call blur() because we want to allow a contextual link to have
+       * focus, yet be closed for example when hovering.
+       *
+       * @return {Drupal.contextual.StateModel}
+       *   The current contextual state model.
+       */
+      close() {
+        this.set('isOpen', false);
+        return this;
+      },
 
-      return this;
-    }
+      /**
+       * Gives focus to this contextual link.
+       *
+       * Also closes + removes focus from every other contextual link.
+       *
+       * @return {Drupal.contextual.StateModel}
+       *   The current contextual state model.
+       */
+      focus() {
+        this.set('hasFocus', true);
+        const cid = this.cid;
+        this.collection.each((model) => {
+          if (model.cid !== cid) {
+            model.close().blur();
+          }
+        });
+        return this;
+      },
 
-  });
-})(Drupal, Backbone);
\ No newline at end of file
+      /**
+       * Removes focus from this contextual link, unless it is open.
+       *
+       * @return {Drupal.contextual.StateModel}
+       *   The current contextual state model.
+       */
+      blur() {
+        if (!this.get('isOpen')) {
+          this.set('hasFocus', false);
+        }
+        return this;
+      },
+    },
+  );
+})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/toolbar/models/StateModel.es6.js b/core/modules/contextual/js/toolbar/models/StateModel.es6.js
deleted file mode 100644
index 07ab5dba4714..000000000000
--- a/core/modules/contextual/js/toolbar/models/StateModel.es6.js
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * @file
- * A Backbone Model for the state of Contextual module's edit toolbar tab.
- */
-
-(function (Drupal, Backbone) {
-  /**
-   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-   *  replacement.
-   */
-  Drupal.contextualToolbar.StateModel = Backbone.Model.extend(
-    /** @lends Drupal.contextualToolbar.StateModel# */ {
-      /**
-       * @type {object}
-       *
-       * @prop {bool} isViewing
-       * @prop {bool} isVisible
-       * @prop {number} contextualCount
-       * @prop {Drupal~TabbingContext} tabbingContext
-       */
-      defaults: /** @lends Drupal.contextualToolbar.StateModel# */ {
-        /**
-         * Indicates whether the toggle is currently in "view" or "edit" mode.
-         *
-         * @type {bool}
-         */
-        isViewing: true,
-
-        /**
-         * Indicates whether the toggle should be visible or hidden. Automatically
-         * calculated, depends on contextualCount.
-         *
-         * @type {bool}
-         */
-        isVisible: false,
-
-        /**
-         * Tracks how many contextual links exist on the page.
-         *
-         * @type {number}
-         */
-        contextualCount: 0,
-
-        /**
-         * A TabbingContext object as returned by {@link Drupal~TabbingManager}:
-         * the set of tabbable elements when edit mode is enabled.
-         *
-         * @type {?Drupal~TabbingContext}
-         */
-        tabbingContext: null,
-      },
-
-      /**
-       * Models the state of the edit mode toggle.
-       *
-       * @constructs
-       *
-       * @augments Backbone.Model
-       *
-       * @param {object} attrs
-       *   Attributes for the backbone model.
-       * @param {object} options
-       *   An object with the following option:
-       * @param {Backbone.collection} options.contextualCollection
-       *   The collection of {@link Drupal.contextual.StateModel} models that
-       *   represent the contextual links on the page.
-       */
-      initialize(attrs, options) {
-        // Respond to new/removed contextual links.
-        this.listenTo(
-          options.contextualCollection,
-          'reset remove add',
-          this.countContextualLinks,
-        );
-        this.listenTo(
-          options.contextualCollection,
-          'add',
-          this.lockNewContextualLinks,
-        );
-
-        // Automatically determine visibility.
-        this.listenTo(this, 'change:contextualCount', this.updateVisibility);
-
-        // Whenever edit mode is toggled, lock all contextual links.
-        this.listenTo(this, 'change:isViewing', (model, isViewing) => {
-          options.contextualCollection.each((contextualModel) => {
-            contextualModel.set('isLocked', !isViewing);
-          });
-        });
-      },
-
-      /**
-       * Tracks the number of contextual link models in the collection.
-       *
-       * @param {Drupal.contextual.StateModel} contextualModel
-       *   The contextual links model that was added or removed.
-       * @param {Backbone.Collection} contextualCollection
-       *    The collection of contextual link models.
-       */
-      countContextualLinks(contextualModel, contextualCollection) {
-        this.set('contextualCount', contextualCollection.length);
-      },
-
-      /**
-       * Lock newly added contextual links if edit mode is enabled.
-       *
-       * @param {Drupal.contextual.StateModel} contextualModel
-       *   The contextual links model that was added.
-       * @param {Backbone.Collection} [contextualCollection]
-       *    The collection of contextual link models.
-       */
-      lockNewContextualLinks(contextualModel, contextualCollection) {
-        if (!this.get('isViewing')) {
-          contextualModel.set('isLocked', true);
-        }
-      },
-
-      /**
-       * Automatically updates visibility of the view/edit mode toggle.
-       */
-      updateVisibility() {
-        this.set('isVisible', this.get('contextualCount') > 0);
-      },
-    },
-  );
-})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/toolbar/models/StateModel.js b/core/modules/contextual/js/toolbar/models/StateModel.js
index f6dedcf05024..07ab5dba4714 100644
--- a/core/modules/contextual/js/toolbar/models/StateModel.js
+++ b/core/modules/contextual/js/toolbar/models/StateModel.js
@@ -1,43 +1,126 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone Model for the state of Contextual module's edit toolbar tab.
+ */
 
 (function (Drupal, Backbone) {
-  Drupal.contextualToolbar.StateModel = Backbone.Model.extend({
-    defaults: {
-      isViewing: true,
-      isVisible: false,
-      contextualCount: 0,
-      tabbingContext: null
-    },
+  /**
+   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+   *  replacement.
+   */
+  Drupal.contextualToolbar.StateModel = Backbone.Model.extend(
+    /** @lends Drupal.contextualToolbar.StateModel# */ {
+      /**
+       * @type {object}
+       *
+       * @prop {bool} isViewing
+       * @prop {bool} isVisible
+       * @prop {number} contextualCount
+       * @prop {Drupal~TabbingContext} tabbingContext
+       */
+      defaults: /** @lends Drupal.contextualToolbar.StateModel# */ {
+        /**
+         * Indicates whether the toggle is currently in "view" or "edit" mode.
+         *
+         * @type {bool}
+         */
+        isViewing: true,
 
-    initialize(attrs, options) {
-      this.listenTo(options.contextualCollection, 'reset remove add', this.countContextualLinks);
-      this.listenTo(options.contextualCollection, 'add', this.lockNewContextualLinks);
-      this.listenTo(this, 'change:contextualCount', this.updateVisibility);
-      this.listenTo(this, 'change:isViewing', (model, isViewing) => {
-        options.contextualCollection.each(contextualModel => {
-          contextualModel.set('isLocked', !isViewing);
-        });
-      });
-    },
+        /**
+         * Indicates whether the toggle should be visible or hidden. Automatically
+         * calculated, depends on contextualCount.
+         *
+         * @type {bool}
+         */
+        isVisible: false,
 
-    countContextualLinks(contextualModel, contextualCollection) {
-      this.set('contextualCount', contextualCollection.length);
-    },
+        /**
+         * Tracks how many contextual links exist on the page.
+         *
+         * @type {number}
+         */
+        contextualCount: 0,
 
-    lockNewContextualLinks(contextualModel, contextualCollection) {
-      if (!this.get('isViewing')) {
-        contextualModel.set('isLocked', true);
-      }
-    },
+        /**
+         * A TabbingContext object as returned by {@link Drupal~TabbingManager}:
+         * the set of tabbable elements when edit mode is enabled.
+         *
+         * @type {?Drupal~TabbingContext}
+         */
+        tabbingContext: null,
+      },
+
+      /**
+       * Models the state of the edit mode toggle.
+       *
+       * @constructs
+       *
+       * @augments Backbone.Model
+       *
+       * @param {object} attrs
+       *   Attributes for the backbone model.
+       * @param {object} options
+       *   An object with the following option:
+       * @param {Backbone.collection} options.contextualCollection
+       *   The collection of {@link Drupal.contextual.StateModel} models that
+       *   represent the contextual links on the page.
+       */
+      initialize(attrs, options) {
+        // Respond to new/removed contextual links.
+        this.listenTo(
+          options.contextualCollection,
+          'reset remove add',
+          this.countContextualLinks,
+        );
+        this.listenTo(
+          options.contextualCollection,
+          'add',
+          this.lockNewContextualLinks,
+        );
 
-    updateVisibility() {
-      this.set('isVisible', this.get('contextualCount') > 0);
-    }
+        // Automatically determine visibility.
+        this.listenTo(this, 'change:contextualCount', this.updateVisibility);
 
-  });
-})(Drupal, Backbone);
\ No newline at end of file
+        // Whenever edit mode is toggled, lock all contextual links.
+        this.listenTo(this, 'change:isViewing', (model, isViewing) => {
+          options.contextualCollection.each((contextualModel) => {
+            contextualModel.set('isLocked', !isViewing);
+          });
+        });
+      },
+
+      /**
+       * Tracks the number of contextual link models in the collection.
+       *
+       * @param {Drupal.contextual.StateModel} contextualModel
+       *   The contextual links model that was added or removed.
+       * @param {Backbone.Collection} contextualCollection
+       *    The collection of contextual link models.
+       */
+      countContextualLinks(contextualModel, contextualCollection) {
+        this.set('contextualCount', contextualCollection.length);
+      },
+
+      /**
+       * Lock newly added contextual links if edit mode is enabled.
+       *
+       * @param {Drupal.contextual.StateModel} contextualModel
+       *   The contextual links model that was added.
+       * @param {Backbone.Collection} [contextualCollection]
+       *    The collection of contextual link models.
+       */
+      lockNewContextualLinks(contextualModel, contextualCollection) {
+        if (!this.get('isViewing')) {
+          contextualModel.set('isLocked', true);
+        }
+      },
+
+      /**
+       * Automatically updates visibility of the view/edit mode toggle.
+       */
+      updateVisibility() {
+        this.set('isVisible', this.get('contextualCount') > 0);
+      },
+    },
+  );
+})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/toolbar/views/AuralView.es6.js b/core/modules/contextual/js/toolbar/views/AuralView.es6.js
deleted file mode 100644
index 45449de62bd8..000000000000
--- a/core/modules/contextual/js/toolbar/views/AuralView.es6.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * @file
- * A Backbone View that provides the aural view of the edit mode toggle.
- */
-
-(function ($, Drupal, Backbone, _) {
-  /**
-   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-   *  replacement.
-   */
-  Drupal.contextualToolbar.AuralView = Backbone.View.extend(
-    /** @lends Drupal.contextualToolbar.AuralView# */ {
-      /**
-       * Tracks whether the tabbing constraint announcement has been read once.
-       *
-       * @type {bool}
-       */
-      announcedOnce: false,
-
-      /**
-       * Renders the aural view of the edit mode toggle (screen reader support).
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       *
-       * @param {object} options
-       *   Options for the view.
-       */
-      initialize(options) {
-        this.options = options;
-
-        this.listenTo(this.model, 'change', this.render);
-        this.listenTo(this.model, 'change:isViewing', this.manageTabbing);
-
-        $(document).on('keyup', _.bind(this.onKeypress, this));
-        this.manageTabbing();
-      },
-
-      /**
-       * {@inheritdoc}
-       *
-       * @return {Drupal.contextualToolbar.AuralView}
-       *   The current contextual toolbar aural view.
-       */
-      render() {
-        // Render the state.
-        this.$el
-          .find('button')
-          .attr('aria-pressed', !this.model.get('isViewing'));
-
-        return this;
-      },
-
-      /**
-       * Limits tabbing to the contextual links and edit mode toolbar tab.
-       */
-      manageTabbing() {
-        let tabbingContext = this.model.get('tabbingContext');
-        // Always release an existing tabbing context.
-        if (tabbingContext) {
-          // Only announce release when the context was active.
-          if (tabbingContext.active) {
-            Drupal.announce(this.options.strings.tabbingReleased);
-          }
-          tabbingContext.release();
-        }
-        // Create a new tabbing context when edit mode is enabled.
-        if (!this.model.get('isViewing')) {
-          tabbingContext = Drupal.tabbingManager.constrain(
-            $('.contextual-toolbar-tab, .contextual'),
-          );
-          this.model.set('tabbingContext', tabbingContext);
-          this.announceTabbingConstraint();
-          this.announcedOnce = true;
-        }
-      },
-
-      /**
-       * Announces the current tabbing constraint.
-       */
-      announceTabbingConstraint() {
-        const strings = this.options.strings;
-        Drupal.announce(
-          Drupal.formatString(strings.tabbingConstrained, {
-            '@contextualsCount': Drupal.formatPlural(
-              Drupal.contextual.collection.length,
-              '@count contextual link',
-              '@count contextual links',
-            ),
-          }),
-        );
-        Drupal.announce(strings.pressEsc);
-      },
-
-      /**
-       * Responds to esc and tab key press events.
-       *
-       * @param {jQuery.Event} event
-       *   The keypress event.
-       */
-      onKeypress(event) {
-        // The first tab key press is tracked so that an announcement about
-        // tabbing constraints can be raised if edit mode is enabled when the page
-        // is loaded.
-        if (
-          !this.announcedOnce &&
-          event.keyCode === 9 &&
-          !this.model.get('isViewing')
-        ) {
-          this.announceTabbingConstraint();
-          // Set announce to true so that this conditional block won't run again.
-          this.announcedOnce = true;
-        }
-        // Respond to the ESC key. Exit out of edit mode.
-        if (event.keyCode === 27) {
-          this.model.set('isViewing', true);
-        }
-      },
-    },
-  );
-})(jQuery, Drupal, Backbone, _);
diff --git a/core/modules/contextual/js/toolbar/views/AuralView.js b/core/modules/contextual/js/toolbar/views/AuralView.js
index 59890d579997..45449de62bd8 100644
--- a/core/modules/contextual/js/toolbar/views/AuralView.js
+++ b/core/modules/contextual/js/toolbar/views/AuralView.js
@@ -1,64 +1,122 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone View that provides the aural view of the edit mode toggle.
+ */
 
 (function ($, Drupal, Backbone, _) {
-  Drupal.contextualToolbar.AuralView = Backbone.View.extend({
-    announcedOnce: false,
+  /**
+   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+   *  replacement.
+   */
+  Drupal.contextualToolbar.AuralView = Backbone.View.extend(
+    /** @lends Drupal.contextualToolbar.AuralView# */ {
+      /**
+       * Tracks whether the tabbing constraint announcement has been read once.
+       *
+       * @type {bool}
+       */
+      announcedOnce: false,
 
-    initialize(options) {
-      this.options = options;
-      this.listenTo(this.model, 'change', this.render);
-      this.listenTo(this.model, 'change:isViewing', this.manageTabbing);
-      $(document).on('keyup', _.bind(this.onKeypress, this));
-      this.manageTabbing();
-    },
-
-    render() {
-      this.$el.find('button').attr('aria-pressed', !this.model.get('isViewing'));
-      return this;
-    },
+      /**
+       * Renders the aural view of the edit mode toggle (screen reader support).
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       *
+       * @param {object} options
+       *   Options for the view.
+       */
+      initialize(options) {
+        this.options = options;
 
-    manageTabbing() {
-      let tabbingContext = this.model.get('tabbingContext');
+        this.listenTo(this.model, 'change', this.render);
+        this.listenTo(this.model, 'change:isViewing', this.manageTabbing);
 
-      if (tabbingContext) {
-        if (tabbingContext.active) {
-          Drupal.announce(this.options.strings.tabbingReleased);
-        }
-
-        tabbingContext.release();
-      }
+        $(document).on('keyup', _.bind(this.onKeypress, this));
+        this.manageTabbing();
+      },
 
-      if (!this.model.get('isViewing')) {
-        tabbingContext = Drupal.tabbingManager.constrain($('.contextual-toolbar-tab, .contextual'));
-        this.model.set('tabbingContext', tabbingContext);
-        this.announceTabbingConstraint();
-        this.announcedOnce = true;
-      }
-    },
+      /**
+       * {@inheritdoc}
+       *
+       * @return {Drupal.contextualToolbar.AuralView}
+       *   The current contextual toolbar aural view.
+       */
+      render() {
+        // Render the state.
+        this.$el
+          .find('button')
+          .attr('aria-pressed', !this.model.get('isViewing'));
 
-    announceTabbingConstraint() {
-      const strings = this.options.strings;
-      Drupal.announce(Drupal.formatString(strings.tabbingConstrained, {
-        '@contextualsCount': Drupal.formatPlural(Drupal.contextual.collection.length, '@count contextual link', '@count contextual links')
-      }));
-      Drupal.announce(strings.pressEsc);
-    },
+        return this;
+      },
 
-    onKeypress(event) {
-      if (!this.announcedOnce && event.keyCode === 9 && !this.model.get('isViewing')) {
-        this.announceTabbingConstraint();
-        this.announcedOnce = true;
-      }
+      /**
+       * Limits tabbing to the contextual links and edit mode toolbar tab.
+       */
+      manageTabbing() {
+        let tabbingContext = this.model.get('tabbingContext');
+        // Always release an existing tabbing context.
+        if (tabbingContext) {
+          // Only announce release when the context was active.
+          if (tabbingContext.active) {
+            Drupal.announce(this.options.strings.tabbingReleased);
+          }
+          tabbingContext.release();
+        }
+        // Create a new tabbing context when edit mode is enabled.
+        if (!this.model.get('isViewing')) {
+          tabbingContext = Drupal.tabbingManager.constrain(
+            $('.contextual-toolbar-tab, .contextual'),
+          );
+          this.model.set('tabbingContext', tabbingContext);
+          this.announceTabbingConstraint();
+          this.announcedOnce = true;
+        }
+      },
 
-      if (event.keyCode === 27) {
-        this.model.set('isViewing', true);
-      }
-    }
+      /**
+       * Announces the current tabbing constraint.
+       */
+      announceTabbingConstraint() {
+        const strings = this.options.strings;
+        Drupal.announce(
+          Drupal.formatString(strings.tabbingConstrained, {
+            '@contextualsCount': Drupal.formatPlural(
+              Drupal.contextual.collection.length,
+              '@count contextual link',
+              '@count contextual links',
+            ),
+          }),
+        );
+        Drupal.announce(strings.pressEsc);
+      },
 
-  });
-})(jQuery, Drupal, Backbone, _);
\ No newline at end of file
+      /**
+       * Responds to esc and tab key press events.
+       *
+       * @param {jQuery.Event} event
+       *   The keypress event.
+       */
+      onKeypress(event) {
+        // The first tab key press is tracked so that an announcement about
+        // tabbing constraints can be raised if edit mode is enabled when the page
+        // is loaded.
+        if (
+          !this.announcedOnce &&
+          event.keyCode === 9 &&
+          !this.model.get('isViewing')
+        ) {
+          this.announceTabbingConstraint();
+          // Set announce to true so that this conditional block won't run again.
+          this.announcedOnce = true;
+        }
+        // Respond to the ESC key. Exit out of edit mode.
+        if (event.keyCode === 27) {
+          this.model.set('isViewing', true);
+        }
+      },
+    },
+  );
+})(jQuery, Drupal, Backbone, _);
diff --git a/core/modules/contextual/js/toolbar/views/VisualView.es6.js b/core/modules/contextual/js/toolbar/views/VisualView.es6.js
deleted file mode 100644
index b939af8b25bc..000000000000
--- a/core/modules/contextual/js/toolbar/views/VisualView.es6.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * @file
- * A Backbone View that provides the visual view of the edit mode toggle.
- */
-
-(function (Drupal, Backbone) {
-  /**
-   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-   *  replacement.
-   */
-  Drupal.contextualToolbar.VisualView = Backbone.View.extend(
-    /** @lends Drupal.contextualToolbar.VisualView# */ {
-      /**
-       * Events for the Backbone view.
-       *
-       * @return {object}
-       *   A mapping of events to be used in the view.
-       */
-      events() {
-        // Prevents delay and simulated mouse events.
-        const touchEndToClick = function (event) {
-          event.preventDefault();
-          event.target.click();
-        };
-
-        return {
-          click() {
-            this.model.set('isViewing', !this.model.get('isViewing'));
-          },
-          touchend: touchEndToClick,
-        };
-      },
-
-      /**
-       * Renders the visual view of the edit mode toggle.
-       *
-       * Listens to mouse & touch and handles edit mode toggle interactions.
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       */
-      initialize() {
-        this.listenTo(this.model, 'change', this.render);
-        this.listenTo(this.model, 'change:isViewing', this.persist);
-      },
-
-      /**
-       * {@inheritdoc}
-       *
-       * @return {Drupal.contextualToolbar.VisualView}
-       *   The current contextual toolbar visual view.
-       */
-      render() {
-        // Render the visibility.
-        this.$el.toggleClass('hidden', !this.model.get('isVisible'));
-        // Render the state.
-        this.$el
-          .find('button')
-          .toggleClass('is-active', !this.model.get('isViewing'));
-
-        return this;
-      },
-
-      /**
-       * Model change handler; persists the isViewing value to localStorage.
-       *
-       * `isViewing === true` is the default, so only stores in localStorage when
-       * it's not the default value (i.e. false).
-       *
-       * @param {Drupal.contextualToolbar.StateModel} model
-       *   A {@link Drupal.contextualToolbar.StateModel} model.
-       * @param {bool} isViewing
-       *   The value of the isViewing attribute in the model.
-       */
-      persist(model, isViewing) {
-        if (!isViewing) {
-          localStorage.setItem('Drupal.contextualToolbar.isViewing', 'false');
-        } else {
-          localStorage.removeItem('Drupal.contextualToolbar.isViewing');
-        }
-      },
-    },
-  );
-})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/toolbar/views/VisualView.js b/core/modules/contextual/js/toolbar/views/VisualView.js
index 556c439eee85..b939af8b25bc 100644
--- a/core/modules/contextual/js/toolbar/views/VisualView.js
+++ b/core/modules/contextual/js/toolbar/views/VisualView.js
@@ -1,45 +1,85 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone View that provides the visual view of the edit mode toggle.
+ */
 
 (function (Drupal, Backbone) {
-  Drupal.contextualToolbar.VisualView = Backbone.View.extend({
-    events() {
-      const touchEndToClick = function (event) {
-        event.preventDefault();
-        event.target.click();
-      };
+  /**
+   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+   *  replacement.
+   */
+  Drupal.contextualToolbar.VisualView = Backbone.View.extend(
+    /** @lends Drupal.contextualToolbar.VisualView# */ {
+      /**
+       * Events for the Backbone view.
+       *
+       * @return {object}
+       *   A mapping of events to be used in the view.
+       */
+      events() {
+        // Prevents delay and simulated mouse events.
+        const touchEndToClick = function (event) {
+          event.preventDefault();
+          event.target.click();
+        };
 
-      return {
-        click() {
-          this.model.set('isViewing', !this.model.get('isViewing'));
-        },
+        return {
+          click() {
+            this.model.set('isViewing', !this.model.get('isViewing'));
+          },
+          touchend: touchEndToClick,
+        };
+      },
 
-        touchend: touchEndToClick
-      };
-    },
+      /**
+       * Renders the visual view of the edit mode toggle.
+       *
+       * Listens to mouse & touch and handles edit mode toggle interactions.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       */
+      initialize() {
+        this.listenTo(this.model, 'change', this.render);
+        this.listenTo(this.model, 'change:isViewing', this.persist);
+      },
 
-    initialize() {
-      this.listenTo(this.model, 'change', this.render);
-      this.listenTo(this.model, 'change:isViewing', this.persist);
-    },
+      /**
+       * {@inheritdoc}
+       *
+       * @return {Drupal.contextualToolbar.VisualView}
+       *   The current contextual toolbar visual view.
+       */
+      render() {
+        // Render the visibility.
+        this.$el.toggleClass('hidden', !this.model.get('isVisible'));
+        // Render the state.
+        this.$el
+          .find('button')
+          .toggleClass('is-active', !this.model.get('isViewing'));
 
-    render() {
-      this.$el.toggleClass('hidden', !this.model.get('isVisible'));
-      this.$el.find('button').toggleClass('is-active', !this.model.get('isViewing'));
-      return this;
-    },
+        return this;
+      },
 
-    persist(model, isViewing) {
-      if (!isViewing) {
-        localStorage.setItem('Drupal.contextualToolbar.isViewing', 'false');
-      } else {
-        localStorage.removeItem('Drupal.contextualToolbar.isViewing');
-      }
-    }
-
-  });
-})(Drupal, Backbone);
\ No newline at end of file
+      /**
+       * Model change handler; persists the isViewing value to localStorage.
+       *
+       * `isViewing === true` is the default, so only stores in localStorage when
+       * it's not the default value (i.e. false).
+       *
+       * @param {Drupal.contextualToolbar.StateModel} model
+       *   A {@link Drupal.contextualToolbar.StateModel} model.
+       * @param {bool} isViewing
+       *   The value of the isViewing attribute in the model.
+       */
+      persist(model, isViewing) {
+        if (!isViewing) {
+          localStorage.setItem('Drupal.contextualToolbar.isViewing', 'false');
+        } else {
+          localStorage.removeItem('Drupal.contextualToolbar.isViewing');
+        }
+      },
+    },
+  );
+})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/views/AuralView.es6.js b/core/modules/contextual/js/views/AuralView.es6.js
deleted file mode 100644
index 1e317242c1e1..000000000000
--- a/core/modules/contextual/js/views/AuralView.es6.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * @file
- * A Backbone View that provides the aural view of a contextual link.
- */
-
-(function (Drupal, Backbone) {
-  /**
-   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-   *  replacement.
-   */
-  Drupal.contextual.AuralView = Backbone.View.extend(
-    /** @lends Drupal.contextual.AuralView# */ {
-      /**
-       * Renders the aural view of a contextual link (i.e. screen reader support).
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       *
-       * @param {object} options
-       *   Options for the view.
-       */
-      initialize(options) {
-        this.options = options;
-
-        this.listenTo(this.model, 'change', this.render);
-
-        // Initial render.
-        this.render();
-      },
-
-      /**
-       * {@inheritdoc}
-       */
-      render() {
-        const isOpen = this.model.get('isOpen');
-
-        // Set the hidden property of the links.
-        this.$el.find('.contextual-links').prop('hidden', !isOpen);
-
-        // Update the view of the trigger.
-        const $trigger = this.$el.find('.trigger');
-        $trigger
-          .each((index, element) => {
-            element.textContent = Drupal.t(
-              '@action @title configuration options',
-              {
-                '@action': !isOpen
-                  ? this.options.strings.open
-                  : this.options.strings.close,
-                '@title': this.model.get('title'),
-              },
-            );
-          })
-          .attr('aria-pressed', isOpen);
-      },
-    },
-  );
-})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/views/AuralView.js b/core/modules/contextual/js/views/AuralView.js
index 49c8dcb265e3..1e317242c1e1 100644
--- a/core/modules/contextual/js/views/AuralView.js
+++ b/core/modules/contextual/js/views/AuralView.js
@@ -1,29 +1,59 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone View that provides the aural view of a contextual link.
+ */
 
 (function (Drupal, Backbone) {
-  Drupal.contextual.AuralView = Backbone.View.extend({
-    initialize(options) {
-      this.options = options;
-      this.listenTo(this.model, 'change', this.render);
-      this.render();
-    },
+  /**
+   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+   *  replacement.
+   */
+  Drupal.contextual.AuralView = Backbone.View.extend(
+    /** @lends Drupal.contextual.AuralView# */ {
+      /**
+       * Renders the aural view of a contextual link (i.e. screen reader support).
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       *
+       * @param {object} options
+       *   Options for the view.
+       */
+      initialize(options) {
+        this.options = options;
+
+        this.listenTo(this.model, 'change', this.render);
+
+        // Initial render.
+        this.render();
+      },
 
-    render() {
-      const isOpen = this.model.get('isOpen');
-      this.$el.find('.contextual-links').prop('hidden', !isOpen);
-      const $trigger = this.$el.find('.trigger');
-      $trigger.each((index, element) => {
-        element.textContent = Drupal.t('@action @title configuration options', {
-          '@action': !isOpen ? this.options.strings.open : this.options.strings.close,
-          '@title': this.model.get('title')
-        });
-      }).attr('aria-pressed', isOpen);
-    }
+      /**
+       * {@inheritdoc}
+       */
+      render() {
+        const isOpen = this.model.get('isOpen');
 
-  });
-})(Drupal, Backbone);
\ No newline at end of file
+        // Set the hidden property of the links.
+        this.$el.find('.contextual-links').prop('hidden', !isOpen);
+
+        // Update the view of the trigger.
+        const $trigger = this.$el.find('.trigger');
+        $trigger
+          .each((index, element) => {
+            element.textContent = Drupal.t(
+              '@action @title configuration options',
+              {
+                '@action': !isOpen
+                  ? this.options.strings.open
+                  : this.options.strings.close,
+                '@title': this.model.get('title'),
+              },
+            );
+          })
+          .attr('aria-pressed', isOpen);
+      },
+    },
+  );
+})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/views/KeyboardView.es6.js b/core/modules/contextual/js/views/KeyboardView.es6.js
deleted file mode 100644
index d7bb101835cf..000000000000
--- a/core/modules/contextual/js/views/KeyboardView.es6.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * @file
- * A Backbone View that provides keyboard interaction for a contextual link.
- */
-
-(function (Drupal, Backbone) {
-  /**
-   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-   *  replacement.
-   */
-  Drupal.contextual.KeyboardView = Backbone.View.extend(
-    /** @lends Drupal.contextual.KeyboardView# */ {
-      /**
-       * @type {object}
-       */
-      events: {
-        'focus .trigger': 'focus',
-        'focus .contextual-links a': 'focus',
-        'blur .trigger': function () {
-          this.model.blur();
-        },
-        'blur .contextual-links a': function () {
-          // Set up a timeout to allow a user to tab between the trigger and the
-          // contextual links without the menu dismissing.
-          const that = this;
-          this.timer = window.setTimeout(() => {
-            that.model.close().blur();
-          }, 150);
-        },
-      },
-
-      /**
-       * Provides keyboard interaction for a contextual link.
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       */
-      initialize() {
-        /**
-         * The timer is used to create a delay before dismissing the contextual
-         * links on blur. This is only necessary when keyboard users tab into
-         * contextual links without edit mode (i.e. without TabbingManager).
-         * That means that if we decide to disable tabbing of contextual links
-         * without edit mode, all this timer logic can go away.
-         *
-         * @type {NaN|number}
-         */
-        this.timer = NaN;
-      },
-
-      /**
-       * Sets focus on the model; Clears the timer that dismisses the links.
-       */
-      focus() {
-        // Clear the timeout that might have been set by blurring a link.
-        window.clearTimeout(this.timer);
-        this.model.focus();
-      },
-    },
-  );
-})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/views/KeyboardView.js b/core/modules/contextual/js/views/KeyboardView.js
index 3f10479b3514..d7bb101835cf 100644
--- a/core/modules/contextual/js/views/KeyboardView.js
+++ b/core/modules/contextual/js/views/KeyboardView.js
@@ -1,34 +1,62 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone View that provides keyboard interaction for a contextual link.
+ */
 
 (function (Drupal, Backbone) {
-  Drupal.contextual.KeyboardView = Backbone.View.extend({
-    events: {
-      'focus .trigger': 'focus',
-      'focus .contextual-links a': 'focus',
-      'blur .trigger': function () {
-        this.model.blur();
+  /**
+   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+   *  replacement.
+   */
+  Drupal.contextual.KeyboardView = Backbone.View.extend(
+    /** @lends Drupal.contextual.KeyboardView# */ {
+      /**
+       * @type {object}
+       */
+      events: {
+        'focus .trigger': 'focus',
+        'focus .contextual-links a': 'focus',
+        'blur .trigger': function () {
+          this.model.blur();
+        },
+        'blur .contextual-links a': function () {
+          // Set up a timeout to allow a user to tab between the trigger and the
+          // contextual links without the menu dismissing.
+          const that = this;
+          this.timer = window.setTimeout(() => {
+            that.model.close().blur();
+          }, 150);
+        },
       },
-      'blur .contextual-links a': function () {
-        const that = this;
-        this.timer = window.setTimeout(() => {
-          that.model.close().blur();
-        }, 150);
-      }
-    },
-
-    initialize() {
-      this.timer = NaN;
-    },
 
-    focus() {
-      window.clearTimeout(this.timer);
-      this.model.focus();
-    }
+      /**
+       * Provides keyboard interaction for a contextual link.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       */
+      initialize() {
+        /**
+         * The timer is used to create a delay before dismissing the contextual
+         * links on blur. This is only necessary when keyboard users tab into
+         * contextual links without edit mode (i.e. without TabbingManager).
+         * That means that if we decide to disable tabbing of contextual links
+         * without edit mode, all this timer logic can go away.
+         *
+         * @type {NaN|number}
+         */
+        this.timer = NaN;
+      },
 
-  });
-})(Drupal, Backbone);
\ No newline at end of file
+      /**
+       * Sets focus on the model; Clears the timer that dismisses the links.
+       */
+      focus() {
+        // Clear the timeout that might have been set by blurring a link.
+        window.clearTimeout(this.timer);
+        this.model.focus();
+      },
+    },
+  );
+})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/views/RegionView.es6.js b/core/modules/contextual/js/views/RegionView.es6.js
deleted file mode 100644
index 08ec5880beaa..000000000000
--- a/core/modules/contextual/js/views/RegionView.es6.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * @file
- * A Backbone View that renders the visual view of a contextual region element.
- */
-
-(function (Drupal, Backbone) {
-  /**
-   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-   *  replacement.
-   */
-  Drupal.contextual.RegionView = Backbone.View.extend(
-    /** @lends Drupal.contextual.RegionView# */ {
-      /**
-       * Events for the Backbone view.
-       *
-       * @return {object}
-       *   A mapping of events to be used in the view.
-       */
-      events() {
-        // Used for tracking the presence of touch events. When true, the
-        // mousemove and mouseenter event handlers are effectively disabled.
-        // This is used instead of preventDefault() on touchstart as some
-        // touchstart events are not cancelable.
-        let touchStart = false;
-        return {
-          touchstart() {
-            // Set to true so the mouseenter and mouseleave events that follow
-            // know to not execute any hover related logic.
-            touchStart = true;
-          },
-          mouseenter() {
-            if (!touchStart) {
-              this.model.set('regionIsHovered', true);
-            }
-          },
-          mouseleave() {
-            if (!touchStart) {
-              this.model.close().blur().set('regionIsHovered', false);
-            }
-          },
-          mousemove() {
-            // Because there are scenarios where there are both touchscreens
-            // and pointer devices, the touchStart flag should be set back to
-            // false after mouseenter and mouseleave complete. It will be set to
-            // true if another touchstart event occurs.
-            touchStart = false;
-          },
-        };
-      },
-
-      /**
-       * Renders the visual view of a contextual region element.
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       */
-      initialize() {
-        this.listenTo(this.model, 'change:hasFocus', this.render);
-      },
-
-      /**
-       * {@inheritdoc}
-       *
-       * @return {Drupal.contextual.RegionView}
-       *   The current contextual region view.
-       */
-      render() {
-        this.$el.toggleClass('focus', this.model.get('hasFocus'));
-
-        return this;
-      },
-    },
-  );
-})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/views/RegionView.js b/core/modules/contextual/js/views/RegionView.js
index 7edac95a36ef..08ec5880beaa 100644
--- a/core/modules/contextual/js/views/RegionView.js
+++ b/core/modules/contextual/js/views/RegionView.js
@@ -1,46 +1,75 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone View that renders the visual view of a contextual region element.
+ */
 
 (function (Drupal, Backbone) {
-  Drupal.contextual.RegionView = Backbone.View.extend({
-    events() {
-      let touchStart = false;
-      return {
-        touchstart() {
-          touchStart = true;
-        },
+  /**
+   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+   *  replacement.
+   */
+  Drupal.contextual.RegionView = Backbone.View.extend(
+    /** @lends Drupal.contextual.RegionView# */ {
+      /**
+       * Events for the Backbone view.
+       *
+       * @return {object}
+       *   A mapping of events to be used in the view.
+       */
+      events() {
+        // Used for tracking the presence of touch events. When true, the
+        // mousemove and mouseenter event handlers are effectively disabled.
+        // This is used instead of preventDefault() on touchstart as some
+        // touchstart events are not cancelable.
+        let touchStart = false;
+        return {
+          touchstart() {
+            // Set to true so the mouseenter and mouseleave events that follow
+            // know to not execute any hover related logic.
+            touchStart = true;
+          },
+          mouseenter() {
+            if (!touchStart) {
+              this.model.set('regionIsHovered', true);
+            }
+          },
+          mouseleave() {
+            if (!touchStart) {
+              this.model.close().blur().set('regionIsHovered', false);
+            }
+          },
+          mousemove() {
+            // Because there are scenarios where there are both touchscreens
+            // and pointer devices, the touchStart flag should be set back to
+            // false after mouseenter and mouseleave complete. It will be set to
+            // true if another touchstart event occurs.
+            touchStart = false;
+          },
+        };
+      },
 
-        mouseenter() {
-          if (!touchStart) {
-            this.model.set('regionIsHovered', true);
-          }
-        },
+      /**
+       * Renders the visual view of a contextual region element.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       */
+      initialize() {
+        this.listenTo(this.model, 'change:hasFocus', this.render);
+      },
 
-        mouseleave() {
-          if (!touchStart) {
-            this.model.close().blur().set('regionIsHovered', false);
-          }
-        },
+      /**
+       * {@inheritdoc}
+       *
+       * @return {Drupal.contextual.RegionView}
+       *   The current contextual region view.
+       */
+      render() {
+        this.$el.toggleClass('focus', this.model.get('hasFocus'));
 
-        mousemove() {
-          touchStart = false;
-        }
-
-      };
-    },
-
-    initialize() {
-      this.listenTo(this.model, 'change:hasFocus', this.render);
+        return this;
+      },
     },
-
-    render() {
-      this.$el.toggleClass('focus', this.model.get('hasFocus'));
-      return this;
-    }
-
-  });
-})(Drupal, Backbone);
\ No newline at end of file
+  );
+})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/views/VisualView.es6.js b/core/modules/contextual/js/views/VisualView.es6.js
deleted file mode 100644
index 7f984cc8170f..000000000000
--- a/core/modules/contextual/js/views/VisualView.es6.js
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * @file
- * A Backbone View that provides the visual view of a contextual link.
- */
-
-(function (Drupal, Backbone) {
-  /**
-   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
-   *  replacement.
-   */
-  Drupal.contextual.VisualView = Backbone.View.extend(
-    /** @lends Drupal.contextual.VisualView# */ {
-      /**
-       * Events for the Backbone view.
-       *
-       * @return {object}
-       *   A mapping of events to be used in the view.
-       */
-      events() {
-        // Prevents delay and simulated mouse events.
-        const touchEndToClick = function (event) {
-          event.preventDefault();
-          event.target.click();
-        };
-
-        // Used for tracking the presence of touch events. When true, the
-        // mousemove and mouseenter event handlers are effectively disabled.
-        // This is used instead of preventDefault() on touchstart as some
-        // touchstart events are not cancelable.
-        let touchStart = false;
-
-        return {
-          touchstart() {
-            // Set to true so the mouseenter events that follows knows to not
-            // execute any hover related logic.
-            touchStart = true;
-          },
-          mouseenter() {
-            // We only want mouse hover events on non-touch.
-            if (!touchStart) {
-              this.model.focus();
-            }
-          },
-          mousemove() {
-            // Because there are scenarios where there are both touchscreens
-            // and pointer devices, the touchStart flag should be set back to
-            // false after mouseenter and mouseleave complete. It will be set to
-            // true if another touchstart event occurs.
-            touchStart = false;
-          },
-          'click .trigger': function () {
-            this.model.toggleOpen();
-          },
-          'touchend .trigger': touchEndToClick,
-          'click .contextual-links a': function () {
-            this.model.close().blur();
-          },
-          'touchend .contextual-links a': touchEndToClick,
-        };
-      },
-
-      /**
-       * Renders the visual view of a contextual link. Listens to mouse & touch.
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       */
-      initialize() {
-        this.listenTo(this.model, 'change', this.render);
-      },
-
-      /**
-       * {@inheritdoc}
-       *
-       * @return {Drupal.contextual.VisualView}
-       *   The current contextual visual view.
-       */
-      render() {
-        const isOpen = this.model.get('isOpen');
-        // The trigger should be visible when:
-        //  - the mouse hovered over the region,
-        //  - the trigger is locked,
-        //  - and for as long as the contextual menu is open.
-        const isVisible =
-          this.model.get('isLocked') ||
-          this.model.get('regionIsHovered') ||
-          isOpen;
-
-        this.$el
-          // The open state determines if the links are visible.
-          .toggleClass('open', isOpen)
-          // Update the visibility of the trigger.
-          .find('.trigger')
-          .toggleClass('visually-hidden', !isVisible);
-
-        // Nested contextual region handling: hide any nested contextual triggers.
-        if ('isOpen' in this.model.changed) {
-          this.$el
-            .closest('.contextual-region')
-            .find('.contextual .trigger:not(:first)')
-            .toggle(!isOpen);
-        }
-
-        return this;
-      },
-    },
-  );
-})(Drupal, Backbone);
diff --git a/core/modules/contextual/js/views/VisualView.js b/core/modules/contextual/js/views/VisualView.js
index d571ac02373a..7f984cc8170f 100644
--- a/core/modules/contextual/js/views/VisualView.js
+++ b/core/modules/contextual/js/views/VisualView.js
@@ -1,60 +1,109 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone View that provides the visual view of a contextual link.
+ */
 
 (function (Drupal, Backbone) {
-  Drupal.contextual.VisualView = Backbone.View.extend({
-    events() {
-      const touchEndToClick = function (event) {
-        event.preventDefault();
-        event.target.click();
-      };
-
-      let touchStart = false;
-      return {
-        touchstart() {
-          touchStart = true;
-        },
-
-        mouseenter() {
-          if (!touchStart) {
-            this.model.focus();
-          }
-        },
-
-        mousemove() {
-          touchStart = false;
-        },
-
-        'click .trigger': function () {
-          this.model.toggleOpen();
-        },
-        'touchend .trigger': touchEndToClick,
-        'click .contextual-links a': function () {
-          this.model.close().blur();
-        },
-        'touchend .contextual-links a': touchEndToClick
-      };
-    },
+  /**
+   * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no
+   *  replacement.
+   */
+  Drupal.contextual.VisualView = Backbone.View.extend(
+    /** @lends Drupal.contextual.VisualView# */ {
+      /**
+       * Events for the Backbone view.
+       *
+       * @return {object}
+       *   A mapping of events to be used in the view.
+       */
+      events() {
+        // Prevents delay and simulated mouse events.
+        const touchEndToClick = function (event) {
+          event.preventDefault();
+          event.target.click();
+        };
 
-    initialize() {
-      this.listenTo(this.model, 'change', this.render);
-    },
+        // Used for tracking the presence of touch events. When true, the
+        // mousemove and mouseenter event handlers are effectively disabled.
+        // This is used instead of preventDefault() on touchstart as some
+        // touchstart events are not cancelable.
+        let touchStart = false;
+
+        return {
+          touchstart() {
+            // Set to true so the mouseenter events that follows knows to not
+            // execute any hover related logic.
+            touchStart = true;
+          },
+          mouseenter() {
+            // We only want mouse hover events on non-touch.
+            if (!touchStart) {
+              this.model.focus();
+            }
+          },
+          mousemove() {
+            // Because there are scenarios where there are both touchscreens
+            // and pointer devices, the touchStart flag should be set back to
+            // false after mouseenter and mouseleave complete. It will be set to
+            // true if another touchstart event occurs.
+            touchStart = false;
+          },
+          'click .trigger': function () {
+            this.model.toggleOpen();
+          },
+          'touchend .trigger': touchEndToClick,
+          'click .contextual-links a': function () {
+            this.model.close().blur();
+          },
+          'touchend .contextual-links a': touchEndToClick,
+        };
+      },
 
-    render() {
-      const isOpen = this.model.get('isOpen');
-      const isVisible = this.model.get('isLocked') || this.model.get('regionIsHovered') || isOpen;
-      this.$el.toggleClass('open', isOpen).find('.trigger').toggleClass('visually-hidden', !isVisible);
+      /**
+       * Renders the visual view of a contextual link. Listens to mouse & touch.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       */
+      initialize() {
+        this.listenTo(this.model, 'change', this.render);
+      },
 
-      if ('isOpen' in this.model.changed) {
-        this.$el.closest('.contextual-region').find('.contextual .trigger:not(:first)').toggle(!isOpen);
-      }
+      /**
+       * {@inheritdoc}
+       *
+       * @return {Drupal.contextual.VisualView}
+       *   The current contextual visual view.
+       */
+      render() {
+        const isOpen = this.model.get('isOpen');
+        // The trigger should be visible when:
+        //  - the mouse hovered over the region,
+        //  - the trigger is locked,
+        //  - and for as long as the contextual menu is open.
+        const isVisible =
+          this.model.get('isLocked') ||
+          this.model.get('regionIsHovered') ||
+          isOpen;
 
-      return this;
-    }
+        this.$el
+          // The open state determines if the links are visible.
+          .toggleClass('open', isOpen)
+          // Update the visibility of the trigger.
+          .find('.trigger')
+          .toggleClass('visually-hidden', !isVisible);
 
-  });
-})(Drupal, Backbone);
\ No newline at end of file
+        // Nested contextual region handling: hide any nested contextual triggers.
+        if ('isOpen' in this.model.changed) {
+          this.$el
+            .closest('.contextual-region')
+            .find('.contextual .trigger:not(:first)')
+            .toggle(!isOpen);
+        }
+
+        return this;
+      },
+    },
+  );
+})(Drupal, Backbone);
diff --git a/core/modules/editor/js/editor.admin.es6.js b/core/modules/editor/js/editor.admin.es6.js
deleted file mode 100644
index 94d1dab06e51..000000000000
--- a/core/modules/editor/js/editor.admin.es6.js
+++ /dev/null
@@ -1,1037 +0,0 @@
-/**
- * @file
- * Provides a JavaScript API to broadcast text editor configuration changes.
- *
- * Filter implementations may listen to the drupalEditorFeatureAdded,
- * drupalEditorFeatureRemoved, and drupalEditorFeatureRemoved events on document
- * to automatically adjust their settings based on the editor configuration.
- */
-
-(function ($, Drupal, document) {
-  /**
-   * Editor configuration namespace.
-   *
-   * @namespace
-   */
-  Drupal.editorConfiguration = {
-    /**
-     * Must be called by a specific text editor's configuration whenever a
-     * feature is added by the user.
-     *
-     * Triggers the drupalEditorFeatureAdded event on the document, which
-     * receives a {@link Drupal.EditorFeature} object.
-     *
-     * @param {Drupal.EditorFeature} feature
-     *   A text editor feature object.
-     *
-     * @fires event:drupalEditorFeatureAdded
-     */
-    addedFeature(feature) {
-      $(document).trigger('drupalEditorFeatureAdded', feature);
-    },
-
-    /**
-     * Must be called by a specific text editor's configuration whenever a
-     * feature is removed by the user.
-     *
-     * Triggers the drupalEditorFeatureRemoved event on the document, which
-     * receives a {@link Drupal.EditorFeature} object.
-     *
-     * @param {Drupal.EditorFeature} feature
-     *   A text editor feature object.
-     *
-     * @fires event:drupalEditorFeatureRemoved
-     */
-    removedFeature(feature) {
-      $(document).trigger('drupalEditorFeatureRemoved', feature);
-    },
-
-    /**
-     * Must be called by a specific text editor's configuration whenever a
-     * feature is modified, i.e. has different rules.
-     *
-     * For example when the "Bold" button is configured to use the `<b>` tag
-     * instead of the `<strong>` tag.
-     *
-     * Triggers the drupalEditorFeatureModified event on the document, which
-     * receives a {@link Drupal.EditorFeature} object.
-     *
-     * @param {Drupal.EditorFeature} feature
-     *   A text editor feature object.
-     *
-     * @fires event:drupalEditorFeatureModified
-     */
-    modifiedFeature(feature) {
-      $(document).trigger('drupalEditorFeatureModified', feature);
-    },
-
-    /**
-     * May be called by a specific text editor's configuration whenever a
-     * feature is being added, to check whether it would require the filter
-     * settings to be updated.
-     *
-     * The canonical use case is when a text editor is being enabled:
-     * preferably
-     * this would not cause the filter settings to be changed; rather, the
-     * default set of buttons (features) for the text editor should adjust
-     * itself to not cause filter setting changes.
-     *
-     * Note: for filters to integrate with this functionality, it is necessary
-     * that they implement
-     * `Drupal.filterSettingsForEditors[filterID].getRules()`.
-     *
-     * @param {Drupal.EditorFeature} feature
-     *   A text editor feature object.
-     *
-     * @return {bool}
-     *   Whether the given feature is allowed by the current filters.
-     */
-    featureIsAllowedByFilters(feature) {
-      /**
-       * Provided a section of a feature or filter rule, checks if no property
-       * values are defined for all properties: attributes, classes and styles.
-       *
-       * @param {object} section
-       *   The section to check.
-       *
-       * @return {bool}
-       *   Returns true if the section has empty properties, false otherwise.
-       */
-      function emptyProperties(section) {
-        return (
-          section.attributes.length === 0 &&
-          section.classes.length === 0 &&
-          section.styles.length === 0
-        );
-      }
-
-      /**
-       * Generate the universe U of possible values that can result from the
-       * feature's rules' requirements.
-       *
-       * This generates an object of this form:
-       *   var universe = {
-       *     a: {
-       *       'touchedByAllowedPropertyRule': false,
-       *       'tag': false,
-       *       'attributes:href': false,
-       *       'classes:external': false,
-       *     },
-       *     strong: {
-       *       'touchedByAllowedPropertyRule': false,
-       *       'tag': false,
-       *     },
-       *     img: {
-       *       'touchedByAllowedPropertyRule': false,
-       *       'tag': false,
-       *       'attributes:src': false
-       *     }
-       *   };
-       *
-       * In this example, the given text editor feature resulted in the above
-       * universe, which shows that it must be allowed to generate the a,
-       * strong and img tags. For the a tag, it must be able to set the "href"
-       * attribute and the "external" class. For the strong tag, no further
-       * properties are required. For the img tag, the "src" attribute is
-       * required. The "tag" key is used to track whether that tag was
-       * explicitly allowed by one of the filter's rules. The
-       * "touchedByAllowedPropertyRule" key is used for state tracking that is
-       * essential for filterStatusAllowsFeature() to be able to reason: when
-       * all of a filter's rules have been applied, and none of the forbidden
-       * rules matched (which would have resulted in early termination) yet the
-       * universe has not been made empty (which would be the end result if
-       * everything in the universe were explicitly allowed), then this piece
-       * of state data enables us to determine whether a tag whose properties
-       * were not all explicitly allowed are in fact still allowed, because its
-       * tag was explicitly allowed and there were no filter rules applying
-       * "allowed tag property value" restrictions for this particular tag.
-       *
-       * @param {object} feature
-       *   The feature in question.
-       *
-       * @return {object}
-       *   The universe generated.
-       *
-       * @see findPropertyValueOnTag()
-       * @see filterStatusAllowsFeature()
-       */
-      function generateUniverseFromFeatureRequirements(feature) {
-        const properties = ['attributes', 'styles', 'classes'];
-        const universe = {};
-
-        for (let r = 0; r < feature.rules.length; r++) {
-          const featureRule = feature.rules[r];
-
-          // For each tag required by this feature rule, create a basic entry in
-          // the universe.
-          const requiredTags = featureRule.required.tags;
-          for (let t = 0; t < requiredTags.length; t++) {
-            universe[requiredTags[t]] = {
-              // Whether this tag was allowed or not.
-              tag: false,
-              // Whether any filter rule that applies to this tag had an allowed
-              // property rule. i.e. will become true if >=1 filter rule has >=1
-              // allowed property rule.
-              touchedByAllowedPropertyRule: false,
-            };
-          }
-
-          // If no required properties are defined for this rule, we can move on
-          // to the next feature.
-          if (emptyProperties(featureRule.required)) {
-            continue;
-          }
-
-          // Expand the existing universe, assume that each tags' property
-          // value is disallowed. If the filter rules allow everything in the
-          // feature's universe, then the feature is allowed.
-          for (let p = 0; p < properties.length; p++) {
-            const property = properties[p];
-            for (let pv = 0; pv < featureRule.required[property].length; pv++) {
-              const propertyValue = featureRule.required[property];
-              universe[requiredTags][`${property}:${propertyValue}`] = false;
-            }
-          }
-        }
-
-        return universe;
-      }
-
-      /**
-       * Finds out if a specific property value (potentially containing
-       * wildcards) exists on the given tag. When the "allowing" parameter
-       * equals true, the universe will be updated if that specific property
-       * value exists. Returns true if found, false otherwise.
-       *
-       * @param {object} universe
-       *   The universe to check.
-       * @param {string} tag
-       *   The tag to look for.
-       * @param {string} property
-       *   The property to check.
-       * @param {string} propertyValue
-       *   The property value to check.
-       * @param {bool} allowing
-       *   Whether to update the universe or not.
-       *
-       * @return {bool}
-       *   Returns true if found, false otherwise.
-       */
-      function findPropertyValueOnTag(
-        universe,
-        tag,
-        property,
-        propertyValue,
-        allowing,
-      ) {
-        // If the tag does not exist in the universe, then it definitely can't
-        // have this specific property value.
-        if (!universe.hasOwnProperty(tag)) {
-          return false;
-        }
-
-        const key = `${property}:${propertyValue}`;
-
-        // Track whether a tag was touched by a filter rule that allows specific
-        // property values on this particular tag.
-        // @see generateUniverseFromFeatureRequirements
-        if (allowing) {
-          universe[tag].touchedByAllowedPropertyRule = true;
-        }
-
-        // The simple case: no wildcard in property value.
-        if (propertyValue.indexOf('*') === -1) {
-          if (
-            universe.hasOwnProperty(tag) &&
-            universe[tag].hasOwnProperty(key)
-          ) {
-            if (allowing) {
-              universe[tag][key] = true;
-            }
-            return true;
-          }
-          return false;
-        }
-        // The complex case: wildcard in property value.
-
-        let atLeastOneFound = false;
-        const regex = key.replace(/\*/g, '[^ ]*');
-        Object.keys(universe[tag]).forEach((key) => {
-          if (key.match(regex)) {
-            atLeastOneFound = true;
-            if (allowing) {
-              universe[tag][key] = true;
-            }
-          }
-        });
-        return atLeastOneFound;
-      }
-
-      /**
-       * Calls findPropertyValuesOnAllTags for all tags in the universe.
-       *
-       * @param {object} universe
-       *   The universe to check.
-       * @param {string} property
-       *   The property to check.
-       * @param {Array} propertyValues
-       *   Values of the property to check.
-       * @param {bool} allowing
-       *   Whether to update the universe or not.
-       *
-       * @return {bool}
-       *   Returns true if found, false otherwise.
-       */
-      function findPropertyValuesOnAllTags(
-        universe,
-        property,
-        propertyValues,
-        allowing,
-      ) {
-        let atLeastOneFound = false;
-        Object.keys(universe).forEach((tag) => {
-          if (
-            // eslint-disable-next-line no-use-before-define
-            findPropertyValuesOnTag(
-              universe,
-              tag,
-              property,
-              propertyValues,
-              allowing,
-            )
-          ) {
-            atLeastOneFound = true;
-          }
-        });
-        return atLeastOneFound;
-      }
-
-      /**
-       * Calls findPropertyValueOnTag on the given tag for every property value
-       * that is listed in the "propertyValues" parameter. Supports the wildcard
-       * tag.
-       *
-       * @param {object} universe
-       *   The universe to check.
-       * @param {string} tag
-       *   The tag to look for.
-       * @param {string} property
-       *   The property to check.
-       * @param {Array} propertyValues
-       *   Values of the property to check.
-       * @param {bool} allowing
-       *   Whether to update the universe or not.
-       *
-       * @return {bool}
-       *   Returns true if found, false otherwise.
-       */
-      function findPropertyValuesOnTag(
-        universe,
-        tag,
-        property,
-        propertyValues,
-        allowing,
-      ) {
-        // Detect the wildcard case.
-        if (tag === '*') {
-          return findPropertyValuesOnAllTags(
-            universe,
-            property,
-            propertyValues,
-            allowing,
-          );
-        }
-
-        let atLeastOneFound = false;
-        propertyValues.forEach((propertyValue) => {
-          if (
-            findPropertyValueOnTag(
-              universe,
-              tag,
-              property,
-              propertyValue,
-              allowing,
-            )
-          ) {
-            atLeastOneFound = true;
-          }
-        });
-        return atLeastOneFound;
-      }
-
-      /**
-       * Calls deleteFromUniverseIfAllowed for all tags in the universe.
-       *
-       * @param {object} universe
-       *   The universe to delete from.
-       *
-       * @return {bool}
-       *   Whether something was deleted from the universe.
-       */
-      function deleteAllTagsFromUniverseIfAllowed(universe) {
-        let atLeastOneDeleted = false;
-        Object.keys(universe).forEach((tag) => {
-          // eslint-disable-next-line no-use-before-define
-          if (deleteFromUniverseIfAllowed(universe, tag)) {
-            atLeastOneDeleted = true;
-          }
-        });
-        return atLeastOneDeleted;
-      }
-
-      /**
-       * Deletes a tag from the universe if the tag itself and each of its
-       * properties are marked as allowed.
-       *
-       * @param {object} universe
-       *   The universe to delete from.
-       * @param {string} tag
-       *   The tag to check.
-       *
-       * @return {bool}
-       *   Whether something was deleted from the universe.
-       */
-      function deleteFromUniverseIfAllowed(universe, tag) {
-        // Detect the wildcard case.
-        if (tag === '*') {
-          return deleteAllTagsFromUniverseIfAllowed(universe);
-        }
-        if (
-          universe.hasOwnProperty(tag) &&
-          Object.keys(universe[tag])
-            .filter((key) => key !== 'touchedByAllowedPropertyRule')
-            .every((key) => universe[tag][key])
-        ) {
-          delete universe[tag];
-          return true;
-        }
-        return false;
-      }
-
-      /**
-       * Checks if any filter rule forbids either a tag or a tag property value
-       * that exists in the universe.
-       *
-       * @param {object} universe
-       *   Universe to check.
-       * @param {object} filterStatus
-       *   Filter status to use for check.
-       *
-       * @return {bool}
-       *   Whether any filter rule forbids something in the universe.
-       */
-      function anyForbiddenFilterRuleMatches(universe, filterStatus) {
-        const properties = ['attributes', 'styles', 'classes'];
-
-        // Check if a tag in the universe is forbidden.
-        const allRequiredTags = Object.keys(universe);
-        let filterRule;
-        for (let i = 0; i < filterStatus.rules.length; i++) {
-          filterRule = filterStatus.rules[i];
-          if (filterRule.allow === false) {
-            const intersection = filterRule.tags.filter((tag) =>
-              allRequiredTags.includes(tag),
-            );
-            if (intersection.length > 0) {
-              return true;
-            }
-          }
-        }
-
-        // Check if a property value of a tag in the universe is forbidden.
-        // For all filter rules…
-        for (let n = 0; n < filterStatus.rules.length; n++) {
-          filterRule = filterStatus.rules[n];
-          // … if there are tags with restricted property values …
-          if (
-            filterRule.restrictedTags.tags.length &&
-            !emptyProperties(filterRule.restrictedTags.forbidden)
-          ) {
-            // … for all those tags …
-            for (let j = 0; j < filterRule.restrictedTags.tags.length; j++) {
-              const tag = filterRule.restrictedTags.tags[j];
-              // … then iterate over all properties …
-              for (let k = 0; k < properties.length; k++) {
-                const property = properties[k];
-                // … and return true if just one of the forbidden property
-                // values for this tag and property is listed in the universe.
-                if (
-                  findPropertyValuesOnTag(
-                    universe,
-                    tag,
-                    property,
-                    filterRule.restrictedTags.forbidden[property],
-                    false,
-                  )
-                ) {
-                  return true;
-                }
-              }
-            }
-          }
-        }
-
-        return false;
-      }
-
-      /**
-       * Applies every filter rule's explicit allowing of a tag or a tag
-       * property value to the universe. Whenever both the tag and all of its
-       * required property values are marked as explicitly allowed, they are
-       * deleted from the universe.
-       *
-       * @param {object} universe
-       *   Universe to delete from.
-       * @param {object} filterStatus
-       *   The filter status in question.
-       */
-      function markAllowedTagsAndPropertyValues(universe, filterStatus) {
-        const properties = ['attributes', 'styles', 'classes'];
-
-        // Check if a tag in the universe is allowed.
-        let filterRule;
-        let tag;
-        for (
-          let l = 0;
-          Object.keys(universe).length > 0 && l < filterStatus.rules.length;
-          l++
-        ) {
-          filterRule = filterStatus.rules[l];
-          if (filterRule.allow === true) {
-            for (
-              let m = 0;
-              Object.keys(universe).length > 0 && m < filterRule.tags.length;
-              m++
-            ) {
-              tag = filterRule.tags[m];
-              if (universe.hasOwnProperty(tag)) {
-                universe[tag].tag = true;
-                deleteFromUniverseIfAllowed(universe, tag);
-              }
-            }
-          }
-        }
-
-        // Check if a property value of a tag in the universe is allowed.
-        // For all filter rules…
-        for (
-          let i = 0;
-          Object.keys(universe).length > 0 && i < filterStatus.rules.length;
-          i++
-        ) {
-          filterRule = filterStatus.rules[i];
-          // … if there are tags with restricted property values …
-          if (
-            filterRule.restrictedTags.tags.length &&
-            !emptyProperties(filterRule.restrictedTags.allowed)
-          ) {
-            // … for all those tags …
-            for (
-              let j = 0;
-              Object.keys(universe).length > 0 &&
-              j < filterRule.restrictedTags.tags.length;
-              j++
-            ) {
-              tag = filterRule.restrictedTags.tags[j];
-              // … then iterate over all properties …
-              for (let k = 0; k < properties.length; k++) {
-                const property = properties[k];
-                // … and try to delete this tag from the universe if just one
-                // of the allowed property values for this tag and property is
-                // listed in the universe. (Because everything might be allowed
-                // now.)
-                if (
-                  findPropertyValuesOnTag(
-                    universe,
-                    tag,
-                    property,
-                    filterRule.restrictedTags.allowed[property],
-                    true,
-                  )
-                ) {
-                  deleteFromUniverseIfAllowed(universe, tag);
-                }
-              }
-            }
-          }
-        }
-      }
-
-      /**
-       * Checks whether the current status of a filter allows a specific feature
-       * by building the universe of potential values from the feature's
-       * requirements and then checking whether anything in the filter prevents
-       * that.
-       *
-       * @param {object} filterStatus
-       *   The filter status in question.
-       * @param {object} feature
-       *   The feature requested.
-       *
-       * @return {bool}
-       *   Whether the current status of the filter allows specified feature.
-       *
-       * @see generateUniverseFromFeatureRequirements()
-       */
-      function filterStatusAllowsFeature(filterStatus, feature) {
-        // An inactive filter by definition allows the feature.
-        if (!filterStatus.active) {
-          return true;
-        }
-
-        // A feature that specifies no rules has no HTML requirements and is
-        // hence allowed by definition.
-        if (feature.rules.length === 0) {
-          return true;
-        }
-
-        // Analogously for a filter that specifies no rules.
-        if (filterStatus.rules.length === 0) {
-          return true;
-        }
-
-        // Generate the universe U of possible values that can result from the
-        // feature's rules' requirements.
-        const universe = generateUniverseFromFeatureRequirements(feature);
-
-        // If anything that is in the universe (and is thus required by the
-        // feature) is forbidden by any of the filter's rules, then this filter
-        // does not allow this feature.
-        if (anyForbiddenFilterRuleMatches(universe, filterStatus)) {
-          return false;
-        }
-
-        // Mark anything in the universe that is allowed by any of the filter's
-        // rules as allowed. If everything is explicitly allowed, then the
-        // universe will become empty.
-        markAllowedTagsAndPropertyValues(universe, filterStatus);
-
-        // If there was at least one filter rule allowing tags, then everything
-        // in the universe must be allowed for this feature to be allowed, and
-        // thus by now it must be empty. However, it is still possible that the
-        // filter allows the feature, due to no rules for allowing tag property
-        // values and/or rules for forbidding tag property values. For details:
-        // see the comments below.
-        // @see generateUniverseFromFeatureRequirements()
-        if (filterStatus.rules.some(({ allow }) => allow)) {
-          // If the universe is empty, then everything was explicitly allowed
-          // and our job is done: this filter allows this feature!
-          if (Object.keys(universe).length === 0) {
-            return true;
-          }
-          // Otherwise, it is still possible that this feature is allowed.
-
-          // Every tag must be explicitly allowed if there are filter rules
-          // doing tag whitelisting.
-          if (
-            !Object.keys(universe).every((tagName) => universe[tagName].tag)
-          ) {
-            return false;
-          }
-          // Every tag was explicitly allowed, but since the universe is not
-          // empty, one or more tag properties are disallowed. However, if
-          // only blacklisting of tag properties was applied to these tags,
-          // and no whitelisting was ever applied, then it's still fine:
-          // since none of the tag properties were blacklisted, we got to
-          // this point, and since no whitelisting was applied, it doesn't
-          // matter that the properties: this could never have happened
-          // anyway. It's only this late that we can know this for certain.
-
-          const tags = Object.keys(universe);
-          // Figure out if there was any rule applying whitelisting tag
-          // restrictions to each of the remaining tags.
-          for (let i = 0; i < tags.length; i++) {
-            const tag = tags[i];
-            if (universe.hasOwnProperty(tag)) {
-              if (universe[tag].touchedByAllowedPropertyRule === false) {
-                delete universe[tag];
-              }
-            }
-          }
-          return Object.keys(universe).length === 0;
-        }
-        // Otherwise, if all filter rules were doing blacklisting, then the sole
-        // fact that we got to this point indicates that this filter allows for
-        // everything that is required for this feature.
-
-        return true;
-      }
-
-      // If any filter's current status forbids the editor feature, return
-      // false.
-      Drupal.filterConfiguration.update();
-      return Object.keys(Drupal.filterConfiguration.statuses).every(
-        (filterID) =>
-          filterStatusAllowsFeature(
-            Drupal.filterConfiguration.statuses[filterID],
-            feature,
-          ),
-      );
-    },
-  };
-
-  /**
-   * Constructor for an editor feature HTML rule.
-   *
-   * Intended to be used in combination with {@link Drupal.EditorFeature}.
-   *
-   * A text editor feature rule object describes both:
-   *  - required HTML tags, attributes, styles and classes: without these, the
-   *    text editor feature is unable to function. It's possible that a
-   *  - allowed HTML tags, attributes, styles and classes: these are optional
-   *    in the strictest sense, but it is possible that the feature generates
-   *    them.
-   *
-   * The structure can be very clearly seen below: there's a "required" and an
-   * "allowed" key. For each of those, there are objects with the "tags",
-   * "attributes", "styles" and "classes" keys. For all these keys the values
-   * are initialized to the empty array. List each possible value as an array
-   * value. Besides the "required" and "allowed" keys, there's an optional
-   * "raw" key: it allows text editor implementations to optionally pass in
-   * their raw representation instead of the Drupal-defined representation for
-   * HTML rules.
-   *
-   * @example
-   * tags: ['<a>']
-   * attributes: ['href', 'alt']
-   * styles: ['color', 'text-decoration']
-   * classes: ['external', 'internal']
-   *
-   * @constructor
-   *
-   * @see Drupal.EditorFeature
-   */
-  Drupal.EditorFeatureHTMLRule = function () {
-    /**
-     *
-     * @type {Object}
-     *
-     * @prop {Array} tags
-     * @prop {Array} attributes
-     * @prop {Array} styles
-     * @prop {Array} classes
-     */
-    this.required = {
-      tags: [],
-      attributes: [],
-      styles: [],
-      classes: [],
-    };
-
-    /**
-     *
-     * @type {Object}
-     *
-     * @prop {Array} tags
-     * @prop {Array} attributes
-     * @prop {Array} styles
-     * @prop {Array} classes
-     */
-    this.allowed = {
-      tags: [],
-      attributes: [],
-      styles: [],
-      classes: [],
-    };
-
-    /**
-     *
-     * @type {null}
-     */
-    this.raw = null;
-  };
-
-  /**
-   * A text editor feature object. Initialized with the feature name.
-   *
-   * Contains a set of HTML rules ({@link Drupal.EditorFeatureHTMLRule} objects)
-   * that describe which HTML tags, attributes, styles and classes are required
-   * (i.e. essential for the feature to function at all) and which are allowed
-   * (i.e. the feature may generate this, but they're not essential).
-   *
-   * It is necessary to allow for multiple HTML rules per feature: with just
-   * one HTML rule per feature, there is not enough expressiveness to describe
-   * certain cases. For example: a "table" feature would probably require the
-   * `<table>` tag, and might allow e.g. the "summary" attribute on that tag.
-   * However, the table feature would also require the `<tr>` and `<td>` tags,
-   * but it doesn't make sense to allow for a "summary" attribute on these tags.
-   * Hence these would need to be split in two separate rules.
-   *
-   * HTML rules must be added with the `addHTMLRule()` method. A feature that
-   * has zero HTML rules does not create or modify HTML.
-   *
-   * @constructor
-   *
-   * @param {string} name
-   *   The name of the feature.
-   *
-   * @see Drupal.EditorFeatureHTMLRule
-   */
-  Drupal.EditorFeature = function (name) {
-    this.name = name;
-    this.rules = [];
-  };
-
-  /**
-   * Adds an HTML rule to the list of HTML rules for this feature.
-   *
-   * @param {Drupal.EditorFeatureHTMLRule} rule
-   *   A text editor feature HTML rule.
-   */
-  Drupal.EditorFeature.prototype.addHTMLRule = function (rule) {
-    this.rules.push(rule);
-  };
-
-  /**
-   * Text filter status object. Initialized with the filter ID.
-   *
-   * Indicates whether the text filter is currently active (enabled) or not.
-   *
-   * Contains a set of HTML rules ({@link Drupal.FilterHTMLRule} objects) that
-   * describe which HTML tags are allowed or forbidden. They can also describe
-   * for a set of tags (or all tags) which attributes, styles and classes are
-   * allowed and which are forbidden.
-   *
-   * It is necessary to allow for multiple HTML rules per feature, for
-   * analogous reasons as {@link Drupal.EditorFeature}.
-   *
-   * HTML rules must be added with the `addHTMLRule()` method. A filter that has
-   * zero HTML rules does not disallow any HTML.
-   *
-   * @constructor
-   *
-   * @param {string} name
-   *   The name of the feature.
-   *
-   * @see Drupal.FilterHTMLRule
-   */
-  Drupal.FilterStatus = function (name) {
-    /**
-     *
-     * @type {string}
-     */
-    this.name = name;
-
-    /**
-     *
-     * @type {bool}
-     */
-    this.active = false;
-
-    /**
-     *
-     * @type {Array.<Drupal.FilterHTMLRule>}
-     */
-    this.rules = [];
-  };
-
-  /**
-   * Adds an HTML rule to the list of HTML rules for this filter.
-   *
-   * @param {Drupal.FilterHTMLRule} rule
-   *   A text filter HTML rule.
-   */
-  Drupal.FilterStatus.prototype.addHTMLRule = function (rule) {
-    this.rules.push(rule);
-  };
-
-  /**
-   * A text filter HTML rule object.
-   *
-   * Intended to be used in combination with {@link Drupal.FilterStatus}.
-   *
-   * A text filter rule object describes:
-   *  1. allowed or forbidden tags: (optional) whitelist or blacklist HTML tags
-   *  2. restricted tag properties: (optional) whitelist or blacklist
-   *     attributes, styles and classes on a set of HTML tags.
-   *
-   * Typically, each text filter rule object does either 1 or 2, not both.
-   *
-   * The structure can be very clearly seen below:
-   *  1. use the "tags" key to list HTML tags, and set the "allow" key to
-   *     either true (to allow these HTML tags) or false (to forbid these HTML
-   *     tags). If you leave the "tags" key's default value (the empty array),
-   *     no restrictions are applied.
-   *  2. all nested within the "restrictedTags" key: use the "tags" subkey to
-   *     list HTML tags to which you want to apply property restrictions, then
-   *     use the "allowed" subkey to whitelist specific property values, and
-   *     similarly use the "forbidden" subkey to blacklist specific property
-   *     values.
-   *
-   * @example
-   * <caption>Whitelist the "p", "strong" and "a" HTML tags.</caption>
-   * {
-   *   tags: ['p', 'strong', 'a'],
-   *   allow: true,
-   *   restrictedTags: {
-   *     tags: [],
-   *     allowed: { attributes: [], styles: [], classes: [] },
-   *     forbidden: { attributes: [], styles: [], classes: [] }
-   *   }
-   * }
-   * @example
-   * <caption>For the "a" HTML tag, only allow the "href" attribute
-   * and the "external" class and disallow the "target" attribute.</caption>
-   * {
-   *   tags: [],
-   *   allow: null,
-   *   restrictedTags: {
-   *     tags: ['a'],
-   *     allowed: { attributes: ['href'], styles: [], classes: ['external'] },
-   *     forbidden: { attributes: ['target'], styles: [], classes: [] }
-   *   }
-   * }
-   * @example
-   * <caption>For all tags, allow the "data-*" attribute (that is, any
-   * attribute that begins with "data-").</caption>
-   * {
-   *   tags: [],
-   *   allow: null,
-   *   restrictedTags: {
-   *     tags: ['*'],
-   *     allowed: { attributes: ['data-*'], styles: [], classes: [] },
-   *     forbidden: { attributes: [], styles: [], classes: [] }
-   *   }
-   * }
-   *
-   * @return {object}
-   *   An object with the following structure:
-   * ```
-   * {
-   *   tags: Array,
-   *   allow: null,
-   *   restrictedTags: {
-   *     tags: Array,
-   *     allowed: {attributes: Array, styles: Array, classes: Array},
-   *     forbidden: {attributes: Array, styles: Array, classes: Array}
-   *   }
-   * }
-   * ```
-   *
-   * @see Drupal.FilterStatus
-   */
-  Drupal.FilterHTMLRule = function () {
-    // Allow or forbid tags.
-    this.tags = [];
-    this.allow = null;
-
-    // Apply restrictions to properties set on tags.
-    this.restrictedTags = {
-      tags: [],
-      allowed: { attributes: [], styles: [], classes: [] },
-      forbidden: { attributes: [], styles: [], classes: [] },
-    };
-
-    return this;
-  };
-
-  Drupal.FilterHTMLRule.prototype.clone = function () {
-    const clone = new Drupal.FilterHTMLRule();
-    clone.tags = this.tags.slice(0);
-    clone.allow = this.allow;
-    clone.restrictedTags.tags = this.restrictedTags.tags.slice(0);
-    clone.restrictedTags.allowed.attributes =
-      this.restrictedTags.allowed.attributes.slice(0);
-    clone.restrictedTags.allowed.styles =
-      this.restrictedTags.allowed.styles.slice(0);
-    clone.restrictedTags.allowed.classes =
-      this.restrictedTags.allowed.classes.slice(0);
-    clone.restrictedTags.forbidden.attributes =
-      this.restrictedTags.forbidden.attributes.slice(0);
-    clone.restrictedTags.forbidden.styles =
-      this.restrictedTags.forbidden.styles.slice(0);
-    clone.restrictedTags.forbidden.classes =
-      this.restrictedTags.forbidden.classes.slice(0);
-    return clone;
-  };
-
-  /**
-   * Tracks the configuration of all text filters in {@link Drupal.FilterStatus}
-   * objects for {@link Drupal.editorConfiguration.featureIsAllowedByFilters}.
-   *
-   * @namespace
-   */
-  Drupal.filterConfiguration = {
-    /**
-     * Drupal.FilterStatus objects, keyed by filter ID.
-     *
-     * @type {Object.<string, Drupal.FilterStatus>}
-     */
-    statuses: {},
-
-    /**
-     * Live filter setting parsers.
-     *
-     * Object keyed by filter ID, for those filters that implement it.
-     *
-     * Filters should load the implementing JavaScript on the filter
-     * configuration form and implement
-     * `Drupal.filterSettings[filterID].getRules()`, which should return an
-     * array of {@link Drupal.FilterHTMLRule} objects.
-     *
-     * @namespace
-     */
-    liveSettingParsers: {},
-
-    /**
-     * Updates all {@link Drupal.FilterStatus} objects to reflect current state.
-     *
-     * Automatically checks whether a filter is currently enabled or not. To
-     * support more fine-grained.
-     *
-     * If a filter implements a live setting parser, then that will be used to
-     * keep the HTML rules for the {@link Drupal.FilterStatus} object
-     * up-to-date.
-     */
-    update() {
-      Object.keys(Drupal.filterConfiguration.statuses || {}).forEach(
-        (filterID) => {
-          // Update status.
-          Drupal.filterConfiguration.statuses[filterID].active = $(
-            `[name="filters[${filterID}][status]"]`,
-          ).is(':checked');
-
-          // Update current rules.
-          if (Drupal.filterConfiguration.liveSettingParsers[filterID]) {
-            Drupal.filterConfiguration.statuses[filterID].rules =
-              Drupal.filterConfiguration.liveSettingParsers[
-                filterID
-              ].getRules();
-          }
-        },
-      );
-    },
-  };
-
-  /**
-   * Initializes {@link Drupal.filterConfiguration}.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Gets filter configuration from filter form input.
-   */
-  Drupal.behaviors.initializeFilterConfiguration = {
-    attach(context, settings) {
-      once(
-        'filter-editor-status',
-        '#filters-status-wrapper input.form-checkbox',
-        context,
-      ).forEach((checkbox) => {
-        const $checkbox = $(checkbox);
-        const nameAttribute = $checkbox.attr('name');
-
-        // The filter's checkbox has a name attribute of the form
-        // "filters[<name of filter>][status]", parse "<name of filter>" from
-        // it.
-        const filterID = nameAttribute.substring(8, nameAttribute.indexOf(']'));
-
-        // Create a Drupal.FilterStatus object to track the state (whether it's
-        // active or not and its current settings, if any) of each filter.
-        Drupal.filterConfiguration.statuses[filterID] = new Drupal.FilterStatus(
-          filterID,
-        );
-      });
-    },
-  };
-})(jQuery, Drupal, document);
diff --git a/core/modules/editor/js/editor.admin.js b/core/modules/editor/js/editor.admin.js
index 6d05f3804cd0..94d1dab06e51 100644
--- a/core/modules/editor/js/editor.admin.js
+++ b/core/modules/editor/js/editor.admin.js
@@ -1,51 +1,192 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Provides a JavaScript API to broadcast text editor configuration changes.
+ *
+ * Filter implementations may listen to the drupalEditorFeatureAdded,
+ * drupalEditorFeatureRemoved, and drupalEditorFeatureRemoved events on document
+ * to automatically adjust their settings based on the editor configuration.
+ */
 
 (function ($, Drupal, document) {
+  /**
+   * Editor configuration namespace.
+   *
+   * @namespace
+   */
   Drupal.editorConfiguration = {
+    /**
+     * Must be called by a specific text editor's configuration whenever a
+     * feature is added by the user.
+     *
+     * Triggers the drupalEditorFeatureAdded event on the document, which
+     * receives a {@link Drupal.EditorFeature} object.
+     *
+     * @param {Drupal.EditorFeature} feature
+     *   A text editor feature object.
+     *
+     * @fires event:drupalEditorFeatureAdded
+     */
     addedFeature(feature) {
       $(document).trigger('drupalEditorFeatureAdded', feature);
     },
 
+    /**
+     * Must be called by a specific text editor's configuration whenever a
+     * feature is removed by the user.
+     *
+     * Triggers the drupalEditorFeatureRemoved event on the document, which
+     * receives a {@link Drupal.EditorFeature} object.
+     *
+     * @param {Drupal.EditorFeature} feature
+     *   A text editor feature object.
+     *
+     * @fires event:drupalEditorFeatureRemoved
+     */
     removedFeature(feature) {
       $(document).trigger('drupalEditorFeatureRemoved', feature);
     },
 
+    /**
+     * Must be called by a specific text editor's configuration whenever a
+     * feature is modified, i.e. has different rules.
+     *
+     * For example when the "Bold" button is configured to use the `<b>` tag
+     * instead of the `<strong>` tag.
+     *
+     * Triggers the drupalEditorFeatureModified event on the document, which
+     * receives a {@link Drupal.EditorFeature} object.
+     *
+     * @param {Drupal.EditorFeature} feature
+     *   A text editor feature object.
+     *
+     * @fires event:drupalEditorFeatureModified
+     */
     modifiedFeature(feature) {
       $(document).trigger('drupalEditorFeatureModified', feature);
     },
 
+    /**
+     * May be called by a specific text editor's configuration whenever a
+     * feature is being added, to check whether it would require the filter
+     * settings to be updated.
+     *
+     * The canonical use case is when a text editor is being enabled:
+     * preferably
+     * this would not cause the filter settings to be changed; rather, the
+     * default set of buttons (features) for the text editor should adjust
+     * itself to not cause filter setting changes.
+     *
+     * Note: for filters to integrate with this functionality, it is necessary
+     * that they implement
+     * `Drupal.filterSettingsForEditors[filterID].getRules()`.
+     *
+     * @param {Drupal.EditorFeature} feature
+     *   A text editor feature object.
+     *
+     * @return {bool}
+     *   Whether the given feature is allowed by the current filters.
+     */
     featureIsAllowedByFilters(feature) {
+      /**
+       * Provided a section of a feature or filter rule, checks if no property
+       * values are defined for all properties: attributes, classes and styles.
+       *
+       * @param {object} section
+       *   The section to check.
+       *
+       * @return {bool}
+       *   Returns true if the section has empty properties, false otherwise.
+       */
       function emptyProperties(section) {
-        return section.attributes.length === 0 && section.classes.length === 0 && section.styles.length === 0;
+        return (
+          section.attributes.length === 0 &&
+          section.classes.length === 0 &&
+          section.styles.length === 0
+        );
       }
 
+      /**
+       * Generate the universe U of possible values that can result from the
+       * feature's rules' requirements.
+       *
+       * This generates an object of this form:
+       *   var universe = {
+       *     a: {
+       *       'touchedByAllowedPropertyRule': false,
+       *       'tag': false,
+       *       'attributes:href': false,
+       *       'classes:external': false,
+       *     },
+       *     strong: {
+       *       'touchedByAllowedPropertyRule': false,
+       *       'tag': false,
+       *     },
+       *     img: {
+       *       'touchedByAllowedPropertyRule': false,
+       *       'tag': false,
+       *       'attributes:src': false
+       *     }
+       *   };
+       *
+       * In this example, the given text editor feature resulted in the above
+       * universe, which shows that it must be allowed to generate the a,
+       * strong and img tags. For the a tag, it must be able to set the "href"
+       * attribute and the "external" class. For the strong tag, no further
+       * properties are required. For the img tag, the "src" attribute is
+       * required. The "tag" key is used to track whether that tag was
+       * explicitly allowed by one of the filter's rules. The
+       * "touchedByAllowedPropertyRule" key is used for state tracking that is
+       * essential for filterStatusAllowsFeature() to be able to reason: when
+       * all of a filter's rules have been applied, and none of the forbidden
+       * rules matched (which would have resulted in early termination) yet the
+       * universe has not been made empty (which would be the end result if
+       * everything in the universe were explicitly allowed), then this piece
+       * of state data enables us to determine whether a tag whose properties
+       * were not all explicitly allowed are in fact still allowed, because its
+       * tag was explicitly allowed and there were no filter rules applying
+       * "allowed tag property value" restrictions for this particular tag.
+       *
+       * @param {object} feature
+       *   The feature in question.
+       *
+       * @return {object}
+       *   The universe generated.
+       *
+       * @see findPropertyValueOnTag()
+       * @see filterStatusAllowsFeature()
+       */
       function generateUniverseFromFeatureRequirements(feature) {
         const properties = ['attributes', 'styles', 'classes'];
         const universe = {};
 
         for (let r = 0; r < feature.rules.length; r++) {
           const featureRule = feature.rules[r];
-          const requiredTags = featureRule.required.tags;
 
+          // For each tag required by this feature rule, create a basic entry in
+          // the universe.
+          const requiredTags = featureRule.required.tags;
           for (let t = 0; t < requiredTags.length; t++) {
             universe[requiredTags[t]] = {
+              // Whether this tag was allowed or not.
               tag: false,
-              touchedByAllowedPropertyRule: false
+              // Whether any filter rule that applies to this tag had an allowed
+              // property rule. i.e. will become true if >=1 filter rule has >=1
+              // allowed property rule.
+              touchedByAllowedPropertyRule: false,
             };
           }
 
+          // If no required properties are defined for this rule, we can move on
+          // to the next feature.
           if (emptyProperties(featureRule.required)) {
             continue;
           }
 
+          // Expand the existing universe, assume that each tags' property
+          // value is disallowed. If the filter rules allow everything in the
+          // feature's universe, then the feature is allowed.
           for (let p = 0; p < properties.length; p++) {
             const property = properties[p];
-
             for (let pv = 0; pv < featureRule.required[property].length; pv++) {
               const propertyValue = featureRule.required[property];
               universe[requiredTags][`${property}:${propertyValue}`] = false;
@@ -56,35 +197,68 @@
         return universe;
       }
 
-      function findPropertyValueOnTag(universe, tag, property, propertyValue, allowing) {
+      /**
+       * Finds out if a specific property value (potentially containing
+       * wildcards) exists on the given tag. When the "allowing" parameter
+       * equals true, the universe will be updated if that specific property
+       * value exists. Returns true if found, false otherwise.
+       *
+       * @param {object} universe
+       *   The universe to check.
+       * @param {string} tag
+       *   The tag to look for.
+       * @param {string} property
+       *   The property to check.
+       * @param {string} propertyValue
+       *   The property value to check.
+       * @param {bool} allowing
+       *   Whether to update the universe or not.
+       *
+       * @return {bool}
+       *   Returns true if found, false otherwise.
+       */
+      function findPropertyValueOnTag(
+        universe,
+        tag,
+        property,
+        propertyValue,
+        allowing,
+      ) {
+        // If the tag does not exist in the universe, then it definitely can't
+        // have this specific property value.
         if (!universe.hasOwnProperty(tag)) {
           return false;
         }
 
         const key = `${property}:${propertyValue}`;
 
+        // Track whether a tag was touched by a filter rule that allows specific
+        // property values on this particular tag.
+        // @see generateUniverseFromFeatureRequirements
         if (allowing) {
           universe[tag].touchedByAllowedPropertyRule = true;
         }
 
+        // The simple case: no wildcard in property value.
         if (propertyValue.indexOf('*') === -1) {
-          if (universe.hasOwnProperty(tag) && universe[tag].hasOwnProperty(key)) {
+          if (
+            universe.hasOwnProperty(tag) &&
+            universe[tag].hasOwnProperty(key)
+          ) {
             if (allowing) {
               universe[tag][key] = true;
             }
-
             return true;
           }
-
           return false;
         }
+        // The complex case: wildcard in property value.
 
         let atLeastOneFound = false;
         const regex = key.replace(/\*/g, '[^ ]*');
-        Object.keys(universe[tag]).forEach(key => {
+        Object.keys(universe[tag]).forEach((key) => {
           if (key.match(regex)) {
             atLeastOneFound = true;
-
             if (allowing) {
               universe[tag][key] = true;
             }
@@ -93,33 +267,111 @@
         return atLeastOneFound;
       }
 
-      function findPropertyValuesOnAllTags(universe, property, propertyValues, allowing) {
+      /**
+       * Calls findPropertyValuesOnAllTags for all tags in the universe.
+       *
+       * @param {object} universe
+       *   The universe to check.
+       * @param {string} property
+       *   The property to check.
+       * @param {Array} propertyValues
+       *   Values of the property to check.
+       * @param {bool} allowing
+       *   Whether to update the universe or not.
+       *
+       * @return {bool}
+       *   Returns true if found, false otherwise.
+       */
+      function findPropertyValuesOnAllTags(
+        universe,
+        property,
+        propertyValues,
+        allowing,
+      ) {
         let atLeastOneFound = false;
-        Object.keys(universe).forEach(tag => {
-          if (findPropertyValuesOnTag(universe, tag, property, propertyValues, allowing)) {
+        Object.keys(universe).forEach((tag) => {
+          if (
+            // eslint-disable-next-line no-use-before-define
+            findPropertyValuesOnTag(
+              universe,
+              tag,
+              property,
+              propertyValues,
+              allowing,
+            )
+          ) {
             atLeastOneFound = true;
           }
         });
         return atLeastOneFound;
       }
 
-      function findPropertyValuesOnTag(universe, tag, property, propertyValues, allowing) {
+      /**
+       * Calls findPropertyValueOnTag on the given tag for every property value
+       * that is listed in the "propertyValues" parameter. Supports the wildcard
+       * tag.
+       *
+       * @param {object} universe
+       *   The universe to check.
+       * @param {string} tag
+       *   The tag to look for.
+       * @param {string} property
+       *   The property to check.
+       * @param {Array} propertyValues
+       *   Values of the property to check.
+       * @param {bool} allowing
+       *   Whether to update the universe or not.
+       *
+       * @return {bool}
+       *   Returns true if found, false otherwise.
+       */
+      function findPropertyValuesOnTag(
+        universe,
+        tag,
+        property,
+        propertyValues,
+        allowing,
+      ) {
+        // Detect the wildcard case.
         if (tag === '*') {
-          return findPropertyValuesOnAllTags(universe, property, propertyValues, allowing);
+          return findPropertyValuesOnAllTags(
+            universe,
+            property,
+            propertyValues,
+            allowing,
+          );
         }
 
         let atLeastOneFound = false;
-        propertyValues.forEach(propertyValue => {
-          if (findPropertyValueOnTag(universe, tag, property, propertyValue, allowing)) {
+        propertyValues.forEach((propertyValue) => {
+          if (
+            findPropertyValueOnTag(
+              universe,
+              tag,
+              property,
+              propertyValue,
+              allowing,
+            )
+          ) {
             atLeastOneFound = true;
           }
         });
         return atLeastOneFound;
       }
 
+      /**
+       * Calls deleteFromUniverseIfAllowed for all tags in the universe.
+       *
+       * @param {object} universe
+       *   The universe to delete from.
+       *
+       * @return {bool}
+       *   Whether something was deleted from the universe.
+       */
       function deleteAllTagsFromUniverseIfAllowed(universe) {
         let atLeastOneDeleted = false;
-        Object.keys(universe).forEach(tag => {
+        Object.keys(universe).forEach((tag) => {
+          // eslint-disable-next-line no-use-before-define
           if (deleteFromUniverseIfAllowed(universe, tag)) {
             atLeastOneDeleted = true;
           }
@@ -127,47 +379,91 @@
         return atLeastOneDeleted;
       }
 
+      /**
+       * Deletes a tag from the universe if the tag itself and each of its
+       * properties are marked as allowed.
+       *
+       * @param {object} universe
+       *   The universe to delete from.
+       * @param {string} tag
+       *   The tag to check.
+       *
+       * @return {bool}
+       *   Whether something was deleted from the universe.
+       */
       function deleteFromUniverseIfAllowed(universe, tag) {
+        // Detect the wildcard case.
         if (tag === '*') {
           return deleteAllTagsFromUniverseIfAllowed(universe);
         }
-
-        if (universe.hasOwnProperty(tag) && Object.keys(universe[tag]).filter(key => key !== 'touchedByAllowedPropertyRule').every(key => universe[tag][key])) {
+        if (
+          universe.hasOwnProperty(tag) &&
+          Object.keys(universe[tag])
+            .filter((key) => key !== 'touchedByAllowedPropertyRule')
+            .every((key) => universe[tag][key])
+        ) {
           delete universe[tag];
           return true;
         }
-
         return false;
       }
 
+      /**
+       * Checks if any filter rule forbids either a tag or a tag property value
+       * that exists in the universe.
+       *
+       * @param {object} universe
+       *   Universe to check.
+       * @param {object} filterStatus
+       *   Filter status to use for check.
+       *
+       * @return {bool}
+       *   Whether any filter rule forbids something in the universe.
+       */
       function anyForbiddenFilterRuleMatches(universe, filterStatus) {
         const properties = ['attributes', 'styles', 'classes'];
+
+        // Check if a tag in the universe is forbidden.
         const allRequiredTags = Object.keys(universe);
         let filterRule;
-
         for (let i = 0; i < filterStatus.rules.length; i++) {
           filterRule = filterStatus.rules[i];
-
           if (filterRule.allow === false) {
-            const intersection = filterRule.tags.filter(tag => allRequiredTags.includes(tag));
-
+            const intersection = filterRule.tags.filter((tag) =>
+              allRequiredTags.includes(tag),
+            );
             if (intersection.length > 0) {
               return true;
             }
           }
         }
 
+        // Check if a property value of a tag in the universe is forbidden.
+        // For all filter rules…
         for (let n = 0; n < filterStatus.rules.length; n++) {
           filterRule = filterStatus.rules[n];
-
-          if (filterRule.restrictedTags.tags.length && !emptyProperties(filterRule.restrictedTags.forbidden)) {
+          // … if there are tags with restricted property values …
+          if (
+            filterRule.restrictedTags.tags.length &&
+            !emptyProperties(filterRule.restrictedTags.forbidden)
+          ) {
+            // … for all those tags …
             for (let j = 0; j < filterRule.restrictedTags.tags.length; j++) {
               const tag = filterRule.restrictedTags.tags[j];
-
+              // … then iterate over all properties …
               for (let k = 0; k < properties.length; k++) {
                 const property = properties[k];
-
-                if (findPropertyValuesOnTag(universe, tag, property, filterRule.restrictedTags.forbidden[property], false)) {
+                // … and return true if just one of the forbidden property
+                // values for this tag and property is listed in the universe.
+                if (
+                  findPropertyValuesOnTag(
+                    universe,
+                    tag,
+                    property,
+                    filterRule.restrictedTags.forbidden[property],
+                    false,
+                  )
+                ) {
                   return true;
                 }
               }
@@ -178,18 +474,36 @@
         return false;
       }
 
+      /**
+       * Applies every filter rule's explicit allowing of a tag or a tag
+       * property value to the universe. Whenever both the tag and all of its
+       * required property values are marked as explicitly allowed, they are
+       * deleted from the universe.
+       *
+       * @param {object} universe
+       *   Universe to delete from.
+       * @param {object} filterStatus
+       *   The filter status in question.
+       */
       function markAllowedTagsAndPropertyValues(universe, filterStatus) {
         const properties = ['attributes', 'styles', 'classes'];
+
+        // Check if a tag in the universe is allowed.
         let filterRule;
         let tag;
-
-        for (let l = 0; Object.keys(universe).length > 0 && l < filterStatus.rules.length; l++) {
+        for (
+          let l = 0;
+          Object.keys(universe).length > 0 && l < filterStatus.rules.length;
+          l++
+        ) {
           filterRule = filterStatus.rules[l];
-
           if (filterRule.allow === true) {
-            for (let m = 0; Object.keys(universe).length > 0 && m < filterRule.tags.length; m++) {
+            for (
+              let m = 0;
+              Object.keys(universe).length > 0 && m < filterRule.tags.length;
+              m++
+            ) {
               tag = filterRule.tags[m];
-
               if (universe.hasOwnProperty(tag)) {
                 universe[tag].tag = true;
                 deleteFromUniverseIfAllowed(universe, tag);
@@ -198,17 +512,43 @@
           }
         }
 
-        for (let i = 0; Object.keys(universe).length > 0 && i < filterStatus.rules.length; i++) {
+        // Check if a property value of a tag in the universe is allowed.
+        // For all filter rules…
+        for (
+          let i = 0;
+          Object.keys(universe).length > 0 && i < filterStatus.rules.length;
+          i++
+        ) {
           filterRule = filterStatus.rules[i];
-
-          if (filterRule.restrictedTags.tags.length && !emptyProperties(filterRule.restrictedTags.allowed)) {
-            for (let j = 0; Object.keys(universe).length > 0 && j < filterRule.restrictedTags.tags.length; j++) {
+          // … if there are tags with restricted property values …
+          if (
+            filterRule.restrictedTags.tags.length &&
+            !emptyProperties(filterRule.restrictedTags.allowed)
+          ) {
+            // … for all those tags …
+            for (
+              let j = 0;
+              Object.keys(universe).length > 0 &&
+              j < filterRule.restrictedTags.tags.length;
+              j++
+            ) {
               tag = filterRule.restrictedTags.tags[j];
-
+              // … then iterate over all properties …
               for (let k = 0; k < properties.length; k++) {
                 const property = properties[k];
-
-                if (findPropertyValuesOnTag(universe, tag, property, filterRule.restrictedTags.allowed[property], true)) {
+                // … and try to delete this tag from the universe if just one
+                // of the allowed property values for this tag and property is
+                // listed in the universe. (Because everything might be allowed
+                // now.)
+                if (
+                  findPropertyValuesOnTag(
+                    universe,
+                    tag,
+                    property,
+                    filterRule.restrictedTags.allowed[property],
+                    true,
+                  )
+                ) {
                   deleteFromUniverseIfAllowed(universe, tag);
                 }
               }
@@ -217,116 +557,371 @@
         }
       }
 
+      /**
+       * Checks whether the current status of a filter allows a specific feature
+       * by building the universe of potential values from the feature's
+       * requirements and then checking whether anything in the filter prevents
+       * that.
+       *
+       * @param {object} filterStatus
+       *   The filter status in question.
+       * @param {object} feature
+       *   The feature requested.
+       *
+       * @return {bool}
+       *   Whether the current status of the filter allows specified feature.
+       *
+       * @see generateUniverseFromFeatureRequirements()
+       */
       function filterStatusAllowsFeature(filterStatus, feature) {
+        // An inactive filter by definition allows the feature.
         if (!filterStatus.active) {
           return true;
         }
 
+        // A feature that specifies no rules has no HTML requirements and is
+        // hence allowed by definition.
         if (feature.rules.length === 0) {
           return true;
         }
 
+        // Analogously for a filter that specifies no rules.
         if (filterStatus.rules.length === 0) {
           return true;
         }
 
+        // Generate the universe U of possible values that can result from the
+        // feature's rules' requirements.
         const universe = generateUniverseFromFeatureRequirements(feature);
 
+        // If anything that is in the universe (and is thus required by the
+        // feature) is forbidden by any of the filter's rules, then this filter
+        // does not allow this feature.
         if (anyForbiddenFilterRuleMatches(universe, filterStatus)) {
           return false;
         }
 
+        // Mark anything in the universe that is allowed by any of the filter's
+        // rules as allowed. If everything is explicitly allowed, then the
+        // universe will become empty.
         markAllowedTagsAndPropertyValues(universe, filterStatus);
 
-        if (filterStatus.rules.some(_ref => {
-          let {
-            allow
-          } = _ref;
-          return allow;
-        })) {
+        // If there was at least one filter rule allowing tags, then everything
+        // in the universe must be allowed for this feature to be allowed, and
+        // thus by now it must be empty. However, it is still possible that the
+        // filter allows the feature, due to no rules for allowing tag property
+        // values and/or rules for forbidding tag property values. For details:
+        // see the comments below.
+        // @see generateUniverseFromFeatureRequirements()
+        if (filterStatus.rules.some(({ allow }) => allow)) {
+          // If the universe is empty, then everything was explicitly allowed
+          // and our job is done: this filter allows this feature!
           if (Object.keys(universe).length === 0) {
             return true;
           }
+          // Otherwise, it is still possible that this feature is allowed.
 
-          if (!Object.keys(universe).every(tagName => universe[tagName].tag)) {
+          // Every tag must be explicitly allowed if there are filter rules
+          // doing tag whitelisting.
+          if (
+            !Object.keys(universe).every((tagName) => universe[tagName].tag)
+          ) {
             return false;
           }
+          // Every tag was explicitly allowed, but since the universe is not
+          // empty, one or more tag properties are disallowed. However, if
+          // only blacklisting of tag properties was applied to these tags,
+          // and no whitelisting was ever applied, then it's still fine:
+          // since none of the tag properties were blacklisted, we got to
+          // this point, and since no whitelisting was applied, it doesn't
+          // matter that the properties: this could never have happened
+          // anyway. It's only this late that we can know this for certain.
 
           const tags = Object.keys(universe);
-
+          // Figure out if there was any rule applying whitelisting tag
+          // restrictions to each of the remaining tags.
           for (let i = 0; i < tags.length; i++) {
             const tag = tags[i];
-
             if (universe.hasOwnProperty(tag)) {
               if (universe[tag].touchedByAllowedPropertyRule === false) {
                 delete universe[tag];
               }
             }
           }
-
           return Object.keys(universe).length === 0;
         }
+        // Otherwise, if all filter rules were doing blacklisting, then the sole
+        // fact that we got to this point indicates that this filter allows for
+        // everything that is required for this feature.
 
         return true;
       }
 
+      // If any filter's current status forbids the editor feature, return
+      // false.
       Drupal.filterConfiguration.update();
-      return Object.keys(Drupal.filterConfiguration.statuses).every(filterID => filterStatusAllowsFeature(Drupal.filterConfiguration.statuses[filterID], feature));
-    }
-
+      return Object.keys(Drupal.filterConfiguration.statuses).every(
+        (filterID) =>
+          filterStatusAllowsFeature(
+            Drupal.filterConfiguration.statuses[filterID],
+            feature,
+          ),
+      );
+    },
   };
 
+  /**
+   * Constructor for an editor feature HTML rule.
+   *
+   * Intended to be used in combination with {@link Drupal.EditorFeature}.
+   *
+   * A text editor feature rule object describes both:
+   *  - required HTML tags, attributes, styles and classes: without these, the
+   *    text editor feature is unable to function. It's possible that a
+   *  - allowed HTML tags, attributes, styles and classes: these are optional
+   *    in the strictest sense, but it is possible that the feature generates
+   *    them.
+   *
+   * The structure can be very clearly seen below: there's a "required" and an
+   * "allowed" key. For each of those, there are objects with the "tags",
+   * "attributes", "styles" and "classes" keys. For all these keys the values
+   * are initialized to the empty array. List each possible value as an array
+   * value. Besides the "required" and "allowed" keys, there's an optional
+   * "raw" key: it allows text editor implementations to optionally pass in
+   * their raw representation instead of the Drupal-defined representation for
+   * HTML rules.
+   *
+   * @example
+   * tags: ['<a>']
+   * attributes: ['href', 'alt']
+   * styles: ['color', 'text-decoration']
+   * classes: ['external', 'internal']
+   *
+   * @constructor
+   *
+   * @see Drupal.EditorFeature
+   */
   Drupal.EditorFeatureHTMLRule = function () {
+    /**
+     *
+     * @type {Object}
+     *
+     * @prop {Array} tags
+     * @prop {Array} attributes
+     * @prop {Array} styles
+     * @prop {Array} classes
+     */
     this.required = {
       tags: [],
       attributes: [],
       styles: [],
-      classes: []
+      classes: [],
     };
+
+    /**
+     *
+     * @type {Object}
+     *
+     * @prop {Array} tags
+     * @prop {Array} attributes
+     * @prop {Array} styles
+     * @prop {Array} classes
+     */
     this.allowed = {
       tags: [],
       attributes: [],
       styles: [],
-      classes: []
+      classes: [],
     };
+
+    /**
+     *
+     * @type {null}
+     */
     this.raw = null;
   };
 
+  /**
+   * A text editor feature object. Initialized with the feature name.
+   *
+   * Contains a set of HTML rules ({@link Drupal.EditorFeatureHTMLRule} objects)
+   * that describe which HTML tags, attributes, styles and classes are required
+   * (i.e. essential for the feature to function at all) and which are allowed
+   * (i.e. the feature may generate this, but they're not essential).
+   *
+   * It is necessary to allow for multiple HTML rules per feature: with just
+   * one HTML rule per feature, there is not enough expressiveness to describe
+   * certain cases. For example: a "table" feature would probably require the
+   * `<table>` tag, and might allow e.g. the "summary" attribute on that tag.
+   * However, the table feature would also require the `<tr>` and `<td>` tags,
+   * but it doesn't make sense to allow for a "summary" attribute on these tags.
+   * Hence these would need to be split in two separate rules.
+   *
+   * HTML rules must be added with the `addHTMLRule()` method. A feature that
+   * has zero HTML rules does not create or modify HTML.
+   *
+   * @constructor
+   *
+   * @param {string} name
+   *   The name of the feature.
+   *
+   * @see Drupal.EditorFeatureHTMLRule
+   */
   Drupal.EditorFeature = function (name) {
     this.name = name;
     this.rules = [];
   };
 
+  /**
+   * Adds an HTML rule to the list of HTML rules for this feature.
+   *
+   * @param {Drupal.EditorFeatureHTMLRule} rule
+   *   A text editor feature HTML rule.
+   */
   Drupal.EditorFeature.prototype.addHTMLRule = function (rule) {
     this.rules.push(rule);
   };
 
+  /**
+   * Text filter status object. Initialized with the filter ID.
+   *
+   * Indicates whether the text filter is currently active (enabled) or not.
+   *
+   * Contains a set of HTML rules ({@link Drupal.FilterHTMLRule} objects) that
+   * describe which HTML tags are allowed or forbidden. They can also describe
+   * for a set of tags (or all tags) which attributes, styles and classes are
+   * allowed and which are forbidden.
+   *
+   * It is necessary to allow for multiple HTML rules per feature, for
+   * analogous reasons as {@link Drupal.EditorFeature}.
+   *
+   * HTML rules must be added with the `addHTMLRule()` method. A filter that has
+   * zero HTML rules does not disallow any HTML.
+   *
+   * @constructor
+   *
+   * @param {string} name
+   *   The name of the feature.
+   *
+   * @see Drupal.FilterHTMLRule
+   */
   Drupal.FilterStatus = function (name) {
+    /**
+     *
+     * @type {string}
+     */
     this.name = name;
+
+    /**
+     *
+     * @type {bool}
+     */
     this.active = false;
+
+    /**
+     *
+     * @type {Array.<Drupal.FilterHTMLRule>}
+     */
     this.rules = [];
   };
 
+  /**
+   * Adds an HTML rule to the list of HTML rules for this filter.
+   *
+   * @param {Drupal.FilterHTMLRule} rule
+   *   A text filter HTML rule.
+   */
   Drupal.FilterStatus.prototype.addHTMLRule = function (rule) {
     this.rules.push(rule);
   };
 
+  /**
+   * A text filter HTML rule object.
+   *
+   * Intended to be used in combination with {@link Drupal.FilterStatus}.
+   *
+   * A text filter rule object describes:
+   *  1. allowed or forbidden tags: (optional) whitelist or blacklist HTML tags
+   *  2. restricted tag properties: (optional) whitelist or blacklist
+   *     attributes, styles and classes on a set of HTML tags.
+   *
+   * Typically, each text filter rule object does either 1 or 2, not both.
+   *
+   * The structure can be very clearly seen below:
+   *  1. use the "tags" key to list HTML tags, and set the "allow" key to
+   *     either true (to allow these HTML tags) or false (to forbid these HTML
+   *     tags). If you leave the "tags" key's default value (the empty array),
+   *     no restrictions are applied.
+   *  2. all nested within the "restrictedTags" key: use the "tags" subkey to
+   *     list HTML tags to which you want to apply property restrictions, then
+   *     use the "allowed" subkey to whitelist specific property values, and
+   *     similarly use the "forbidden" subkey to blacklist specific property
+   *     values.
+   *
+   * @example
+   * <caption>Whitelist the "p", "strong" and "a" HTML tags.</caption>
+   * {
+   *   tags: ['p', 'strong', 'a'],
+   *   allow: true,
+   *   restrictedTags: {
+   *     tags: [],
+   *     allowed: { attributes: [], styles: [], classes: [] },
+   *     forbidden: { attributes: [], styles: [], classes: [] }
+   *   }
+   * }
+   * @example
+   * <caption>For the "a" HTML tag, only allow the "href" attribute
+   * and the "external" class and disallow the "target" attribute.</caption>
+   * {
+   *   tags: [],
+   *   allow: null,
+   *   restrictedTags: {
+   *     tags: ['a'],
+   *     allowed: { attributes: ['href'], styles: [], classes: ['external'] },
+   *     forbidden: { attributes: ['target'], styles: [], classes: [] }
+   *   }
+   * }
+   * @example
+   * <caption>For all tags, allow the "data-*" attribute (that is, any
+   * attribute that begins with "data-").</caption>
+   * {
+   *   tags: [],
+   *   allow: null,
+   *   restrictedTags: {
+   *     tags: ['*'],
+   *     allowed: { attributes: ['data-*'], styles: [], classes: [] },
+   *     forbidden: { attributes: [], styles: [], classes: [] }
+   *   }
+   * }
+   *
+   * @return {object}
+   *   An object with the following structure:
+   * ```
+   * {
+   *   tags: Array,
+   *   allow: null,
+   *   restrictedTags: {
+   *     tags: Array,
+   *     allowed: {attributes: Array, styles: Array, classes: Array},
+   *     forbidden: {attributes: Array, styles: Array, classes: Array}
+   *   }
+   * }
+   * ```
+   *
+   * @see Drupal.FilterStatus
+   */
   Drupal.FilterHTMLRule = function () {
+    // Allow or forbid tags.
     this.tags = [];
     this.allow = null;
+
+    // Apply restrictions to properties set on tags.
     this.restrictedTags = {
       tags: [],
-      allowed: {
-        attributes: [],
-        styles: [],
-        classes: []
-      },
-      forbidden: {
-        attributes: [],
-        styles: [],
-        classes: []
-      }
+      allowed: { attributes: [], styles: [], classes: [] },
+      forbidden: { attributes: [], styles: [], classes: [] },
     };
+
     return this;
   };
 
@@ -335,39 +930,108 @@
     clone.tags = this.tags.slice(0);
     clone.allow = this.allow;
     clone.restrictedTags.tags = this.restrictedTags.tags.slice(0);
-    clone.restrictedTags.allowed.attributes = this.restrictedTags.allowed.attributes.slice(0);
-    clone.restrictedTags.allowed.styles = this.restrictedTags.allowed.styles.slice(0);
-    clone.restrictedTags.allowed.classes = this.restrictedTags.allowed.classes.slice(0);
-    clone.restrictedTags.forbidden.attributes = this.restrictedTags.forbidden.attributes.slice(0);
-    clone.restrictedTags.forbidden.styles = this.restrictedTags.forbidden.styles.slice(0);
-    clone.restrictedTags.forbidden.classes = this.restrictedTags.forbidden.classes.slice(0);
+    clone.restrictedTags.allowed.attributes =
+      this.restrictedTags.allowed.attributes.slice(0);
+    clone.restrictedTags.allowed.styles =
+      this.restrictedTags.allowed.styles.slice(0);
+    clone.restrictedTags.allowed.classes =
+      this.restrictedTags.allowed.classes.slice(0);
+    clone.restrictedTags.forbidden.attributes =
+      this.restrictedTags.forbidden.attributes.slice(0);
+    clone.restrictedTags.forbidden.styles =
+      this.restrictedTags.forbidden.styles.slice(0);
+    clone.restrictedTags.forbidden.classes =
+      this.restrictedTags.forbidden.classes.slice(0);
     return clone;
   };
 
+  /**
+   * Tracks the configuration of all text filters in {@link Drupal.FilterStatus}
+   * objects for {@link Drupal.editorConfiguration.featureIsAllowedByFilters}.
+   *
+   * @namespace
+   */
   Drupal.filterConfiguration = {
+    /**
+     * Drupal.FilterStatus objects, keyed by filter ID.
+     *
+     * @type {Object.<string, Drupal.FilterStatus>}
+     */
     statuses: {},
+
+    /**
+     * Live filter setting parsers.
+     *
+     * Object keyed by filter ID, for those filters that implement it.
+     *
+     * Filters should load the implementing JavaScript on the filter
+     * configuration form and implement
+     * `Drupal.filterSettings[filterID].getRules()`, which should return an
+     * array of {@link Drupal.FilterHTMLRule} objects.
+     *
+     * @namespace
+     */
     liveSettingParsers: {},
 
+    /**
+     * Updates all {@link Drupal.FilterStatus} objects to reflect current state.
+     *
+     * Automatically checks whether a filter is currently enabled or not. To
+     * support more fine-grained.
+     *
+     * If a filter implements a live setting parser, then that will be used to
+     * keep the HTML rules for the {@link Drupal.FilterStatus} object
+     * up-to-date.
+     */
     update() {
-      Object.keys(Drupal.filterConfiguration.statuses || {}).forEach(filterID => {
-        Drupal.filterConfiguration.statuses[filterID].active = $(`[name="filters[${filterID}][status]"]`).is(':checked');
-
-        if (Drupal.filterConfiguration.liveSettingParsers[filterID]) {
-          Drupal.filterConfiguration.statuses[filterID].rules = Drupal.filterConfiguration.liveSettingParsers[filterID].getRules();
-        }
-      });
-    }
-
+      Object.keys(Drupal.filterConfiguration.statuses || {}).forEach(
+        (filterID) => {
+          // Update status.
+          Drupal.filterConfiguration.statuses[filterID].active = $(
+            `[name="filters[${filterID}][status]"]`,
+          ).is(':checked');
+
+          // Update current rules.
+          if (Drupal.filterConfiguration.liveSettingParsers[filterID]) {
+            Drupal.filterConfiguration.statuses[filterID].rules =
+              Drupal.filterConfiguration.liveSettingParsers[
+                filterID
+              ].getRules();
+          }
+        },
+      );
+    },
   };
+
+  /**
+   * Initializes {@link Drupal.filterConfiguration}.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Gets filter configuration from filter form input.
+   */
   Drupal.behaviors.initializeFilterConfiguration = {
     attach(context, settings) {
-      once('filter-editor-status', '#filters-status-wrapper input.form-checkbox', context).forEach(checkbox => {
+      once(
+        'filter-editor-status',
+        '#filters-status-wrapper input.form-checkbox',
+        context,
+      ).forEach((checkbox) => {
         const $checkbox = $(checkbox);
         const nameAttribute = $checkbox.attr('name');
+
+        // The filter's checkbox has a name attribute of the form
+        // "filters[<name of filter>][status]", parse "<name of filter>" from
+        // it.
         const filterID = nameAttribute.substring(8, nameAttribute.indexOf(']'));
-        Drupal.filterConfiguration.statuses[filterID] = new Drupal.FilterStatus(filterID);
-      });
-    }
 
+        // Create a Drupal.FilterStatus object to track the state (whether it's
+        // active or not and its current settings, if any) of each filter.
+        Drupal.filterConfiguration.statuses[filterID] = new Drupal.FilterStatus(
+          filterID,
+        );
+      });
+    },
   };
-})(jQuery, Drupal, document);
\ No newline at end of file
+})(jQuery, Drupal, document);
diff --git a/core/modules/editor/js/editor.dialog.es6.js b/core/modules/editor/js/editor.dialog.es6.js
deleted file mode 100644
index 5cd37960da55..000000000000
--- a/core/modules/editor/js/editor.dialog.es6.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * @file
- * AJAX commands used by Editor module.
- */
-
-(function ($, Drupal) {
-  /**
-   * Command to save the contents of an editor-provided modal.
-   *
-   * This command does not close the open modal. It should be followed by a
-   * call to `Drupal.AjaxCommands.prototype.closeDialog`. Editors that are
-   * integrated with dialogs must independently listen for an
-   * `editor:dialogsave` event to save the changes into the contents of their
-   * interface.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   The Drupal.Ajax object.
-   * @param {object} response
-   *   The server response from the ajax request.
-   * @param {Array} response.values
-   *   The values that were saved.
-   * @param {number} [status]
-   *   The status code from the ajax request.
-   *
-   * @fires event:editor:dialogsave
-   */
-  Drupal.AjaxCommands.prototype.editorDialogSave = function (
-    ajax,
-    response,
-    status,
-  ) {
-    $(window).trigger('editor:dialogsave', [response.values]);
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/editor/js/editor.dialog.js b/core/modules/editor/js/editor.dialog.js
index 1c6412ceec80..5cd37960da55 100644
--- a/core/modules/editor/js/editor.dialog.js
+++ b/core/modules/editor/js/editor.dialog.js
@@ -1,12 +1,34 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * AJAX commands used by Editor module.
+ */
 
 (function ($, Drupal) {
-  Drupal.AjaxCommands.prototype.editorDialogSave = function (ajax, response, status) {
+  /**
+   * Command to save the contents of an editor-provided modal.
+   *
+   * This command does not close the open modal. It should be followed by a
+   * call to `Drupal.AjaxCommands.prototype.closeDialog`. Editors that are
+   * integrated with dialogs must independently listen for an
+   * `editor:dialogsave` event to save the changes into the contents of their
+   * interface.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   The Drupal.Ajax object.
+   * @param {object} response
+   *   The server response from the ajax request.
+   * @param {Array} response.values
+   *   The values that were saved.
+   * @param {number} [status]
+   *   The status code from the ajax request.
+   *
+   * @fires event:editor:dialogsave
+   */
+  Drupal.AjaxCommands.prototype.editorDialogSave = function (
+    ajax,
+    response,
+    status,
+  ) {
     $(window).trigger('editor:dialogsave', [response.values]);
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/editor/js/editor.es6.js b/core/modules/editor/js/editor.es6.js
deleted file mode 100644
index 9aa751574865..000000000000
--- a/core/modules/editor/js/editor.es6.js
+++ /dev/null
@@ -1,335 +0,0 @@
-/**
- * @file
- * Attaches behavior for the Editor module.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Finds the text area field associated with the given text format selector.
-   *
-   * @param {jQuery} $formatSelector
-   *   A text format selector DOM element.
-   *
-   * @return {HTMLElement}
-   *   The text area DOM element, if it was found.
-   */
-  function findFieldForFormatSelector($formatSelector) {
-    const fieldId = $formatSelector.attr('data-editor-for');
-    // This selector will only find text areas in the top-level document. We do
-    // not support attaching editors on text areas within iframes.
-    return $(`#${fieldId}`).get(0);
-  }
-
-  /**
-   * Filter away XSS attack vectors when switching text formats.
-   *
-   * @param {HTMLElement} field
-   *   The textarea DOM element.
-   * @param {object} format
-   *   The text format that's being activated, from
-   *   drupalSettings.editor.formats.
-   * @param {string} originalFormatID
-   *   The text format ID of the original text format.
-   * @param {function} callback
-   *   A callback to be called (with no parameters) after the field's value has
-   *   been XSS filtered.
-   */
-  function filterXssWhenSwitching(field, format, originalFormatID, callback) {
-    // A text editor that already is XSS-safe needs no additional measures.
-    if (format.editor.isXssSafe) {
-      callback(field, format);
-    }
-    // Otherwise, ensure XSS safety: let the server XSS filter this value.
-    else {
-      $.ajax({
-        url: Drupal.url(`editor/filter_xss/${format.format}`),
-        type: 'POST',
-        data: {
-          value: field.value,
-          original_format_id: originalFormatID,
-        },
-        dataType: 'json',
-        success(xssFilteredValue) {
-          // If the server returns false, then no XSS filtering is needed.
-          if (xssFilteredValue !== false) {
-            field.value = xssFilteredValue;
-          }
-          callback(field, format);
-        },
-      });
-    }
-  }
-
-  /**
-   * Changes the text editor on a text area.
-   *
-   * @param {HTMLElement} field
-   *   The text area DOM element.
-   * @param {string} newFormatID
-   *   The text format we're changing to; the text editor for the currently
-   *   active text format will be detached, and the text editor for the new text
-   *   format will be attached.
-   */
-  function changeTextEditor(field, newFormatID) {
-    const previousFormatID = field.getAttribute(
-      'data-editor-active-text-format',
-    );
-
-    // Detach the current editor (if any) and attach a new editor.
-    if (drupalSettings.editor.formats[previousFormatID]) {
-      Drupal.editorDetach(
-        field,
-        drupalSettings.editor.formats[previousFormatID],
-      );
-    }
-    // When no text editor is currently active, stop tracking changes.
-    else {
-      $(field).off('.editor');
-    }
-
-    // Attach the new text editor (if any).
-    if (drupalSettings.editor.formats[newFormatID]) {
-      const format = drupalSettings.editor.formats[newFormatID];
-      filterXssWhenSwitching(
-        field,
-        format,
-        previousFormatID,
-        Drupal.editorAttach,
-      );
-    }
-
-    // Store the new active format.
-    field.setAttribute('data-editor-active-text-format', newFormatID);
-  }
-
-  /**
-   * Handles changes in text format.
-   *
-   * @param {jQuery.Event} event
-   *   The text format change event.
-   */
-  function onTextFormatChange(event) {
-    const select = event.target;
-    const field = event.data.field;
-    const activeFormatID = field.getAttribute('data-editor-active-text-format');
-    const newFormatID = select.value;
-
-    // Prevent double-attaching if the change event is triggered manually.
-    if (newFormatID === activeFormatID) {
-      return;
-    }
-
-    // When changing to a text format that has a text editor associated
-    // with it that supports content filtering, then first ask for
-    // confirmation, because switching text formats might cause certain
-    // markup to be stripped away.
-    const supportContentFiltering =
-      drupalSettings.editor.formats[newFormatID] &&
-      drupalSettings.editor.formats[newFormatID].editorSupportsContentFiltering;
-    // If there is no content yet, it's always safe to change the text format.
-    const hasContent = field.value !== '';
-    if (hasContent && supportContentFiltering) {
-      const message = Drupal.t(
-        'Changing the text format to %text_format will permanently remove content that is not allowed in that text format.<br><br>Save your changes before switching the text format to avoid losing data.',
-        {
-          '%text_format': $(select).find('option:selected')[0].textContent,
-        },
-      );
-      const confirmationDialog = Drupal.dialog(`<div>${message}</div>`, {
-        title: Drupal.t('Change text format?'),
-        dialogClass: 'editor-change-text-format-modal',
-        resizable: false,
-        buttons: [
-          {
-            text: Drupal.t('Continue'),
-            class: 'button button--primary',
-            click() {
-              changeTextEditor(field, newFormatID);
-              confirmationDialog.close();
-            },
-          },
-          {
-            text: Drupal.t('Cancel'),
-            class: 'button',
-            click() {
-              // Restore the active format ID: cancel changing text format. We
-              // cannot simply call event.preventDefault() because jQuery's
-              // change event is only triggered after the change has already
-              // been accepted.
-              select.value = activeFormatID;
-              confirmationDialog.close();
-            },
-          },
-        ],
-        // Prevent this modal from being closed without the user making a choice
-        // as per http://stackoverflow.com/a/5438771.
-        closeOnEscape: false,
-        create() {
-          $(this).parent().find('.ui-dialog-titlebar-close').remove();
-        },
-        beforeClose: false,
-        close(event) {
-          // Automatically destroy the DOM element that was used for the dialog.
-          $(event.target).remove();
-        },
-      });
-
-      confirmationDialog.showModal();
-    } else {
-      changeTextEditor(field, newFormatID);
-    }
-  }
-
-  /**
-   * Initialize an empty object for editors to place their attachment code.
-   *
-   * @namespace
-   */
-  Drupal.editors = {};
-
-  /**
-   * Enables editors on text_format elements.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches an editor to an input element.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detaches an editor from an input element.
-   */
-  Drupal.behaviors.editor = {
-    attach(context, settings) {
-      // If there are no editor settings, there are no editors to enable.
-      if (!settings.editor) {
-        return;
-      }
-
-      once('editor', '[data-editor-for]', context).forEach((editor) => {
-        const $this = $(editor);
-        const field = findFieldForFormatSelector($this);
-
-        // Opt-out if no supported text area was found.
-        if (!field) {
-          return;
-        }
-
-        // Store the current active format.
-        const activeFormatID = editor.value;
-        field.setAttribute('data-editor-active-text-format', activeFormatID);
-
-        // Directly attach this text editor, if the text format is enabled.
-        if (settings.editor.formats[activeFormatID]) {
-          // XSS protection for the current text format/editor is performed on
-          // the server side, so we don't need to do anything special here.
-          Drupal.editorAttach(field, settings.editor.formats[activeFormatID]);
-        }
-        // When there is no text editor for this text format, still track
-        // changes, because the user has the ability to switch to some text
-        // editor, otherwise this code would not be executed.
-        $(field).on('change.editor keypress.editor', () => {
-          field.setAttribute('data-editor-value-is-changed', 'true');
-          // Just knowing that the value was changed is enough, stop tracking.
-          $(field).off('.editor');
-        });
-
-        // Attach onChange handler to text format selector element.
-        if ($this.is('select')) {
-          $this.on('change.editorAttach', { field }, onTextFormatChange);
-        }
-        // Detach any editor when the containing form is submitted.
-        $this.parents('form').on('submit', (event) => {
-          // Do not detach if the event was canceled.
-          if (event.isDefaultPrevented()) {
-            return;
-          }
-          // Detach the current editor (if any).
-          if (settings.editor.formats[activeFormatID]) {
-            Drupal.editorDetach(
-              field,
-              settings.editor.formats[activeFormatID],
-              'serialize',
-            );
-          }
-        });
-      });
-    },
-
-    detach(context, settings, trigger) {
-      let editors;
-      // The 'serialize' trigger indicates that we should simply update the
-      // underlying element with the new text, without destroying the editor.
-      if (trigger === 'serialize') {
-        // Removing the editor-processed class guarantees that the editor will
-        // be reattached. Only do this if we're planning to destroy the editor.
-        editors = once.filter('editor', '[data-editor-for]', context);
-      } else {
-        editors = once.remove('editor', '[data-editor-for]', context);
-      }
-
-      editors.forEach((editor) => {
-        const $this = $(editor);
-        const activeFormatID = editor.value;
-        const field = findFieldForFormatSelector($this);
-        if (field && activeFormatID in settings.editor.formats) {
-          Drupal.editorDetach(
-            field,
-            settings.editor.formats[activeFormatID],
-            trigger,
-          );
-        }
-      });
-    },
-  };
-
-  /**
-   * Attaches editor behaviors to the field.
-   *
-   * @param {HTMLElement} field
-   *   The textarea DOM element.
-   * @param {object} format
-   *   The text format that's being activated, from
-   *   drupalSettings.editor.formats.
-   *
-   * @listens event:change
-   *
-   * @fires event:formUpdated
-   */
-  Drupal.editorAttach = function (field, format) {
-    if (format.editor) {
-      // Attach the text editor.
-      Drupal.editors[format.editor].attach(field, format);
-
-      // Ensures form.js' 'formUpdated' event is triggered even for changes that
-      // happen within the text editor.
-      Drupal.editors[format.editor].onChange(field, () => {
-        $(field).trigger('formUpdated');
-
-        // Keep track of changes, so we know what to do when switching text
-        // formats and guaranteeing XSS protection.
-        field.setAttribute('data-editor-value-is-changed', 'true');
-      });
-    }
-  };
-
-  /**
-   * Detaches editor behaviors from the field.
-   *
-   * @param {HTMLElement} field
-   *   The textarea DOM element.
-   * @param {object} format
-   *   The text format that's being activated, from
-   *   drupalSettings.editor.formats.
-   * @param {string} trigger
-   *   Trigger value from the detach behavior.
-   */
-  Drupal.editorDetach = function (field, format, trigger) {
-    if (format.editor) {
-      Drupal.editors[format.editor].detach(field, format, trigger);
-
-      // Restore the original value if the user didn't make any changes yet.
-      if (field.getAttribute('data-editor-value-is-changed') === 'false') {
-        field.value = field.getAttribute('data-editor-value-original');
-      }
-    }
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/editor/js/editor.js b/core/modules/editor/js/editor.js
index 2ebcf7a528e3..9aa751574865 100644
--- a/core/modules/editor/js/editor.js
+++ b/core/modules/editor/js/editor.js
@@ -1,157 +1,254 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches behavior for the Editor module.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * Finds the text area field associated with the given text format selector.
+   *
+   * @param {jQuery} $formatSelector
+   *   A text format selector DOM element.
+   *
+   * @return {HTMLElement}
+   *   The text area DOM element, if it was found.
+   */
   function findFieldForFormatSelector($formatSelector) {
     const fieldId = $formatSelector.attr('data-editor-for');
+    // This selector will only find text areas in the top-level document. We do
+    // not support attaching editors on text areas within iframes.
     return $(`#${fieldId}`).get(0);
   }
 
+  /**
+   * Filter away XSS attack vectors when switching text formats.
+   *
+   * @param {HTMLElement} field
+   *   The textarea DOM element.
+   * @param {object} format
+   *   The text format that's being activated, from
+   *   drupalSettings.editor.formats.
+   * @param {string} originalFormatID
+   *   The text format ID of the original text format.
+   * @param {function} callback
+   *   A callback to be called (with no parameters) after the field's value has
+   *   been XSS filtered.
+   */
   function filterXssWhenSwitching(field, format, originalFormatID, callback) {
+    // A text editor that already is XSS-safe needs no additional measures.
     if (format.editor.isXssSafe) {
       callback(field, format);
-    } else {
+    }
+    // Otherwise, ensure XSS safety: let the server XSS filter this value.
+    else {
       $.ajax({
         url: Drupal.url(`editor/filter_xss/${format.format}`),
         type: 'POST',
         data: {
           value: field.value,
-          original_format_id: originalFormatID
+          original_format_id: originalFormatID,
         },
         dataType: 'json',
-
         success(xssFilteredValue) {
+          // If the server returns false, then no XSS filtering is needed.
           if (xssFilteredValue !== false) {
             field.value = xssFilteredValue;
           }
-
           callback(field, format);
-        }
-
+        },
       });
     }
   }
 
+  /**
+   * Changes the text editor on a text area.
+   *
+   * @param {HTMLElement} field
+   *   The text area DOM element.
+   * @param {string} newFormatID
+   *   The text format we're changing to; the text editor for the currently
+   *   active text format will be detached, and the text editor for the new text
+   *   format will be attached.
+   */
   function changeTextEditor(field, newFormatID) {
-    const previousFormatID = field.getAttribute('data-editor-active-text-format');
+    const previousFormatID = field.getAttribute(
+      'data-editor-active-text-format',
+    );
 
+    // Detach the current editor (if any) and attach a new editor.
     if (drupalSettings.editor.formats[previousFormatID]) {
-      Drupal.editorDetach(field, drupalSettings.editor.formats[previousFormatID]);
-    } else {
+      Drupal.editorDetach(
+        field,
+        drupalSettings.editor.formats[previousFormatID],
+      );
+    }
+    // When no text editor is currently active, stop tracking changes.
+    else {
       $(field).off('.editor');
     }
 
+    // Attach the new text editor (if any).
     if (drupalSettings.editor.formats[newFormatID]) {
       const format = drupalSettings.editor.formats[newFormatID];
-      filterXssWhenSwitching(field, format, previousFormatID, Drupal.editorAttach);
+      filterXssWhenSwitching(
+        field,
+        format,
+        previousFormatID,
+        Drupal.editorAttach,
+      );
     }
 
+    // Store the new active format.
     field.setAttribute('data-editor-active-text-format', newFormatID);
   }
 
+  /**
+   * Handles changes in text format.
+   *
+   * @param {jQuery.Event} event
+   *   The text format change event.
+   */
   function onTextFormatChange(event) {
     const select = event.target;
     const field = event.data.field;
     const activeFormatID = field.getAttribute('data-editor-active-text-format');
     const newFormatID = select.value;
 
+    // Prevent double-attaching if the change event is triggered manually.
     if (newFormatID === activeFormatID) {
       return;
     }
 
-    const supportContentFiltering = drupalSettings.editor.formats[newFormatID] && drupalSettings.editor.formats[newFormatID].editorSupportsContentFiltering;
+    // When changing to a text format that has a text editor associated
+    // with it that supports content filtering, then first ask for
+    // confirmation, because switching text formats might cause certain
+    // markup to be stripped away.
+    const supportContentFiltering =
+      drupalSettings.editor.formats[newFormatID] &&
+      drupalSettings.editor.formats[newFormatID].editorSupportsContentFiltering;
+    // If there is no content yet, it's always safe to change the text format.
     const hasContent = field.value !== '';
-
     if (hasContent && supportContentFiltering) {
-      const message = Drupal.t('Changing the text format to %text_format will permanently remove content that is not allowed in that text format.<br><br>Save your changes before switching the text format to avoid losing data.', {
-        '%text_format': $(select).find('option:selected')[0].textContent
-      });
+      const message = Drupal.t(
+        'Changing the text format to %text_format will permanently remove content that is not allowed in that text format.<br><br>Save your changes before switching the text format to avoid losing data.',
+        {
+          '%text_format': $(select).find('option:selected')[0].textContent,
+        },
+      );
       const confirmationDialog = Drupal.dialog(`<div>${message}</div>`, {
         title: Drupal.t('Change text format?'),
         dialogClass: 'editor-change-text-format-modal',
         resizable: false,
-        buttons: [{
-          text: Drupal.t('Continue'),
-          class: 'button button--primary',
-
-          click() {
-            changeTextEditor(field, newFormatID);
-            confirmationDialog.close();
-          }
-
-        }, {
-          text: Drupal.t('Cancel'),
-          class: 'button',
-
-          click() {
-            select.value = activeFormatID;
-            confirmationDialog.close();
-          }
-
-        }],
+        buttons: [
+          {
+            text: Drupal.t('Continue'),
+            class: 'button button--primary',
+            click() {
+              changeTextEditor(field, newFormatID);
+              confirmationDialog.close();
+            },
+          },
+          {
+            text: Drupal.t('Cancel'),
+            class: 'button',
+            click() {
+              // Restore the active format ID: cancel changing text format. We
+              // cannot simply call event.preventDefault() because jQuery's
+              // change event is only triggered after the change has already
+              // been accepted.
+              select.value = activeFormatID;
+              confirmationDialog.close();
+            },
+          },
+        ],
+        // Prevent this modal from being closed without the user making a choice
+        // as per http://stackoverflow.com/a/5438771.
         closeOnEscape: false,
-
         create() {
           $(this).parent().find('.ui-dialog-titlebar-close').remove();
         },
-
         beforeClose: false,
-
         close(event) {
+          // Automatically destroy the DOM element that was used for the dialog.
           $(event.target).remove();
-        }
-
+        },
       });
+
       confirmationDialog.showModal();
     } else {
       changeTextEditor(field, newFormatID);
     }
   }
 
+  /**
+   * Initialize an empty object for editors to place their attachment code.
+   *
+   * @namespace
+   */
   Drupal.editors = {};
+
+  /**
+   * Enables editors on text_format elements.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches an editor to an input element.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches an editor from an input element.
+   */
   Drupal.behaviors.editor = {
     attach(context, settings) {
+      // If there are no editor settings, there are no editors to enable.
       if (!settings.editor) {
         return;
       }
 
-      once('editor', '[data-editor-for]', context).forEach(editor => {
+      once('editor', '[data-editor-for]', context).forEach((editor) => {
         const $this = $(editor);
         const field = findFieldForFormatSelector($this);
 
+        // Opt-out if no supported text area was found.
         if (!field) {
           return;
         }
 
+        // Store the current active format.
         const activeFormatID = editor.value;
         field.setAttribute('data-editor-active-text-format', activeFormatID);
 
+        // Directly attach this text editor, if the text format is enabled.
         if (settings.editor.formats[activeFormatID]) {
+          // XSS protection for the current text format/editor is performed on
+          // the server side, so we don't need to do anything special here.
           Drupal.editorAttach(field, settings.editor.formats[activeFormatID]);
         }
-
+        // When there is no text editor for this text format, still track
+        // changes, because the user has the ability to switch to some text
+        // editor, otherwise this code would not be executed.
         $(field).on('change.editor keypress.editor', () => {
           field.setAttribute('data-editor-value-is-changed', 'true');
+          // Just knowing that the value was changed is enough, stop tracking.
           $(field).off('.editor');
         });
 
+        // Attach onChange handler to text format selector element.
         if ($this.is('select')) {
-          $this.on('change.editorAttach', {
-            field
-          }, onTextFormatChange);
+          $this.on('change.editorAttach', { field }, onTextFormatChange);
         }
-
-        $this.parents('form').on('submit', event => {
+        // Detach any editor when the containing form is submitted.
+        $this.parents('form').on('submit', (event) => {
+          // Do not detach if the event was canceled.
           if (event.isDefaultPrevented()) {
             return;
           }
-
+          // Detach the current editor (if any).
           if (settings.editor.formats[activeFormatID]) {
-            Drupal.editorDetach(field, settings.editor.formats[activeFormatID], 'serialize');
+            Drupal.editorDetach(
+              field,
+              settings.editor.formats[activeFormatID],
+              'serialize',
+            );
           }
         });
       });
@@ -159,43 +256,80 @@
 
     detach(context, settings, trigger) {
       let editors;
-
+      // The 'serialize' trigger indicates that we should simply update the
+      // underlying element with the new text, without destroying the editor.
       if (trigger === 'serialize') {
+        // Removing the editor-processed class guarantees that the editor will
+        // be reattached. Only do this if we're planning to destroy the editor.
         editors = once.filter('editor', '[data-editor-for]', context);
       } else {
         editors = once.remove('editor', '[data-editor-for]', context);
       }
 
-      editors.forEach(editor => {
+      editors.forEach((editor) => {
         const $this = $(editor);
         const activeFormatID = editor.value;
         const field = findFieldForFormatSelector($this);
-
         if (field && activeFormatID in settings.editor.formats) {
-          Drupal.editorDetach(field, settings.editor.formats[activeFormatID], trigger);
+          Drupal.editorDetach(
+            field,
+            settings.editor.formats[activeFormatID],
+            trigger,
+          );
         }
       });
-    }
-
+    },
   };
 
+  /**
+   * Attaches editor behaviors to the field.
+   *
+   * @param {HTMLElement} field
+   *   The textarea DOM element.
+   * @param {object} format
+   *   The text format that's being activated, from
+   *   drupalSettings.editor.formats.
+   *
+   * @listens event:change
+   *
+   * @fires event:formUpdated
+   */
   Drupal.editorAttach = function (field, format) {
     if (format.editor) {
+      // Attach the text editor.
       Drupal.editors[format.editor].attach(field, format);
+
+      // Ensures form.js' 'formUpdated' event is triggered even for changes that
+      // happen within the text editor.
       Drupal.editors[format.editor].onChange(field, () => {
         $(field).trigger('formUpdated');
+
+        // Keep track of changes, so we know what to do when switching text
+        // formats and guaranteeing XSS protection.
         field.setAttribute('data-editor-value-is-changed', 'true');
       });
     }
   };
 
+  /**
+   * Detaches editor behaviors from the field.
+   *
+   * @param {HTMLElement} field
+   *   The textarea DOM element.
+   * @param {object} format
+   *   The text format that's being activated, from
+   *   drupalSettings.editor.formats.
+   * @param {string} trigger
+   *   Trigger value from the detach behavior.
+   */
   Drupal.editorDetach = function (field, format, trigger) {
     if (format.editor) {
       Drupal.editors[format.editor].detach(field, format, trigger);
 
+      // Restore the original value if the user didn't make any changes yet.
       if (field.getAttribute('data-editor-value-is-changed') === 'false') {
         field.value = field.getAttribute('data-editor-value-original');
       }
     }
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/field_ui/field_ui.es6.js b/core/modules/field_ui/field_ui.es6.js
deleted file mode 100644
index 950df384ca7c..000000000000
--- a/core/modules/field_ui/field_ui.es6.js
+++ /dev/null
@@ -1,386 +0,0 @@
-/**
- * @file
- * Attaches the behaviors for the Field UI module.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Adds behaviors to the field storage add form.
-   */
-  Drupal.behaviors.fieldUIFieldStorageAddForm = {
-    attach(context) {
-      const form = once(
-        'field_ui_add',
-        '[data-drupal-selector="field-ui-field-storage-add-form"]',
-        context,
-      );
-      if (form.length) {
-        const $form = $(form);
-        // Add a few 'js-form-required' and 'form-required' css classes here.
-        // We can not use the Form API '#required' property because both label
-        // elements for "add new" and "re-use existing" can never be filled and
-        // submitted at the same time. The actual validation will happen
-        // server-side.
-        $form
-          .find(
-            '.js-form-item-label label,' +
-              '.js-form-item-field-name label,' +
-              '.js-form-item-existing-storage-label label',
-          )
-          .addClass('js-form-required form-required');
-
-        const $newFieldType = $form.find('select[name="new_storage_type"]');
-        const $existingStorageName = $form.find(
-          'select[name="existing_storage_name"]',
-        );
-        const $existingStorageLabel = $form.find(
-          'input[name="existing_storage_label"]',
-        );
-
-        // When the user selects a new field type, clear the "existing field"
-        // selection.
-        $newFieldType.on('change', function () {
-          if (this.value !== '') {
-            // Reset the "existing storage name" selection.
-            if ($existingStorageName.length) {
-              $existingStorageName[0].value = '';
-              $existingStorageName.trigger('change');
-            }
-          }
-        });
-
-        // When the user selects an existing storage name, clear the "new field
-        // type" selection and populate the 'existing_storage_label' element.
-        $existingStorageName.on('change', function () {
-          const { value } = this;
-          if (value !== '') {
-            if ($newFieldType.length) {
-              // Reset the "new field type" selection.
-              $newFieldType[0].value = '';
-              $newFieldType.trigger('change');
-            }
-
-            // Pre-populate the "existing storage label" element.
-            if (
-              typeof drupalSettings.existingFieldLabels[value] !== 'undefined'
-            ) {
-              $existingStorageLabel[0].value =
-                drupalSettings.existingFieldLabels[value];
-            }
-          }
-        });
-      }
-    },
-  };
-
-  /**
-   * Attaches the fieldUIOverview behavior.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the fieldUIOverview behavior.
-   *
-   * @see Drupal.fieldUIOverview.attach
-   */
-  Drupal.behaviors.fieldUIDisplayOverview = {
-    attach(context, settings) {
-      once(
-        'field-display-overview',
-        'table#field-display-overview',
-        context,
-      ).forEach((overview) => {
-        Drupal.fieldUIOverview.attach(
-          overview,
-          settings.fieldUIRowsData,
-          Drupal.fieldUIDisplayOverview,
-        );
-      });
-    },
-  };
-
-  /**
-   * Namespace for the field UI overview.
-   *
-   * @namespace
-   */
-  Drupal.fieldUIOverview = {
-    /**
-     * Attaches the fieldUIOverview behavior.
-     *
-     * @param {HTMLTableElement} table
-     *   The table element for the overview.
-     * @param {object} rowsData
-     *   The data of the rows in the table.
-     * @param {object} rowHandlers
-     *   Handlers to be added to the rows.
-     */
-    attach(table, rowsData, rowHandlers) {
-      const tableDrag = Drupal.tableDrag[table.id];
-
-      // Add custom tabledrag callbacks.
-      tableDrag.onDrop = this.onDrop;
-      tableDrag.row.prototype.onSwap = this.onSwap;
-
-      // Create row handlers.
-      $(table)
-        .find('tr.draggable')
-        .each(function () {
-          // Extract server-side data for the row.
-          const row = this;
-          if (row.id in rowsData) {
-            const data = rowsData[row.id];
-            data.tableDrag = tableDrag;
-
-            // Create the row handler, make it accessible from the DOM row
-            // element.
-            const rowHandler = new rowHandlers[data.rowHandler](row, data);
-            $(row).data('fieldUIRowHandler', rowHandler);
-          }
-        });
-    },
-
-    /**
-     * Event handler to be attached to form inputs triggering a region change.
-     */
-    onChange() {
-      const $trigger = $(this);
-      const $row = $trigger.closest('tr');
-      const rowHandler = $row.data('fieldUIRowHandler');
-
-      const refreshRows = {};
-      refreshRows[rowHandler.name] = $trigger.get(0);
-
-      // Handle region change.
-      const region = rowHandler.getRegion();
-      if (region !== rowHandler.region) {
-        const $fieldParent = $row.find('select.js-field-parent');
-        if ($fieldParent.length) {
-          // Remove parenting.
-          $fieldParent[0].value = '';
-        }
-        // Let the row handler deal with the region change.
-        $.extend(refreshRows, rowHandler.regionChange(region));
-        // Update the row region.
-        rowHandler.region = region;
-      }
-
-      // Ajax-update the rows.
-      Drupal.fieldUIOverview.AJAXRefreshRows(refreshRows);
-    },
-
-    /**
-     * Lets row handlers react when a row is dropped into a new region.
-     */
-    onDrop() {
-      const dragObject = this;
-      const row = dragObject.rowObject.element;
-      const $row = $(row);
-      const rowHandler = $row.data('fieldUIRowHandler');
-      if (typeof rowHandler !== 'undefined') {
-        const regionRow = $row.prevAll('tr.region-message').get(0);
-        const region = regionRow.className.replace(
-          /([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/,
-          '$2',
-        );
-
-        if (region !== rowHandler.region) {
-          // Let the row handler deal with the region change.
-          const refreshRows = rowHandler.regionChange(region);
-          // Update the row region.
-          rowHandler.region = region;
-          // Ajax-update the rows.
-          Drupal.fieldUIOverview.AJAXRefreshRows(refreshRows);
-        }
-      }
-    },
-
-    /**
-     * Refreshes placeholder rows in empty regions while a row is being dragged.
-     *
-     * Copied from block.js.
-     *
-     * @param {HTMLElement} draggedRow
-     *   The tableDrag rowObject for the row being dragged.
-     */
-    onSwap(draggedRow) {
-      const rowObject = this;
-      $(rowObject.table)
-        .find('tr.region-message')
-        .each(function () {
-          const $this = $(this);
-          // If the dragged row is in this region, but above the message row, swap
-          // it down one space.
-          if (
-            $this.prev('tr').get(0) ===
-            rowObject.group[rowObject.group.length - 1]
-          ) {
-            // Prevent a recursion problem when using the keyboard to move rows
-            // up.
-            if (
-              rowObject.method !== 'keyboard' ||
-              rowObject.direction === 'down'
-            ) {
-              rowObject.swap('after', this);
-            }
-          }
-          // This region has become empty.
-          if (
-            $this.next('tr').is(':not(.draggable)') ||
-            $this.next('tr').length === 0
-          ) {
-            $this.removeClass('region-populated').addClass('region-empty');
-          }
-          // This region has become populated.
-          else if ($this.is('.region-empty')) {
-            $this.removeClass('region-empty').addClass('region-populated');
-          }
-        });
-    },
-
-    /**
-     * Triggers Ajax refresh of selected rows.
-     *
-     * The 'format type' selects can trigger a series of changes in child rows.
-     * The #ajax behavior is therefore not attached directly to the selects, but
-     * triggered manually through a hidden #ajax 'Refresh' button.
-     *
-     * @param {object} rows
-     *   A hash object, whose keys are the names of the rows to refresh (they
-     *   will receive the 'ajax-new-content' effect on the server side), and
-     *   whose values are the DOM element in the row that should get an Ajax
-     *   throbber.
-     */
-    AJAXRefreshRows(rows) {
-      // Separate keys and values.
-      const rowNames = [];
-      const ajaxElements = [];
-      Object.keys(rows || {}).forEach((rowName) => {
-        rowNames.push(rowName);
-        ajaxElements.push(rows[rowName]);
-      });
-
-      if (rowNames.length) {
-        // Add a throbber next each of the ajaxElements.
-        $(ajaxElements).after(Drupal.theme.ajaxProgressThrobber());
-        const $refreshRows = $('input[name=refresh_rows]');
-        if ($refreshRows.length) {
-          // Fire the Ajax update.
-          $refreshRows[0].value = rowNames.join(' ');
-        }
-        $('input[data-drupal-selector="edit-refresh"]').trigger('mousedown');
-
-        // Disabled elements do not appear in POST ajax data, so we mark the
-        // elements disabled only after firing the request.
-        $(ajaxElements).prop('disabled', true);
-      }
-    },
-  };
-
-  /**
-   * Row handlers for the 'Manage display' screen.
-   *
-   * @namespace
-   */
-  Drupal.fieldUIDisplayOverview = {};
-
-  /**
-   * Constructor for a 'field' row handler.
-   *
-   * This handler is used for both fields and 'extra fields' rows.
-   *
-   * @constructor
-   *
-   * @param {HTMLTableRowElement} row
-   *   The row DOM element.
-   * @param {object} data
-   *   Additional data to be populated in the constructed object.
-   *
-   * @return {Drupal.fieldUIDisplayOverview.field}
-   *   The field row handler constructed.
-   */
-  Drupal.fieldUIDisplayOverview.field = function (row, data) {
-    this.row = row;
-    this.name = data.name;
-    this.region = data.region;
-    this.tableDrag = data.tableDrag;
-    this.defaultPlugin = data.defaultPlugin;
-
-    // Attach change listener to the 'plugin type' select.
-    this.$pluginSelect = $(row).find('.field-plugin-type');
-    this.$pluginSelect.on('change', Drupal.fieldUIOverview.onChange);
-
-    // Attach change listener to the 'region' select.
-    this.$regionSelect = $(row).find('select.field-region');
-    this.$regionSelect.on('change', Drupal.fieldUIOverview.onChange);
-
-    return this;
-  };
-
-  Drupal.fieldUIDisplayOverview.field.prototype = {
-    /**
-     * Returns the region corresponding to the current form values of the row.
-     *
-     * @return {string}
-     *   Either 'hidden' or 'content'.
-     */
-    getRegion() {
-      if (this.$regionSelect.length) {
-        return this.$regionSelect[0].value;
-      }
-    },
-
-    /**
-     * Reacts to a row being changed regions.
-     *
-     * This function is called when the row is moved to a different region, as
-     * a
-     * result of either :
-     * - a drag-and-drop action (the row's form elements then probably need to
-     * be updated accordingly)
-     * - user input in one of the form elements watched by the
-     *   {@link Drupal.fieldUIOverview.onChange} change listener.
-     *
-     * @param {string} region
-     *   The name of the new region for the row.
-     *
-     * @return {object}
-     *   A hash object indicating which rows should be Ajax-updated as a result
-     *   of the change, in the format expected by
-     *   {@link Drupal.fieldUIOverview.AJAXRefreshRows}.
-     */
-    regionChange(region) {
-      // Replace dashes with underscores.
-      region = region.replace(/-/g, '_');
-
-      if (this.$regionSelect.length) {
-        // Set the region of the select list.
-        this.$regionSelect[0].value = region;
-      }
-
-      // Restore the formatter back to the default formatter only if it was
-      // disabled previously. Pseudo-fields do not have default formatters,
-      // we just return to 'visible' for those.
-      if (this.region === 'hidden') {
-        const value =
-          typeof this.defaultPlugin !== 'undefined'
-            ? this.defaultPlugin
-            : this.$pluginSelect.find('option')[0].value;
-
-        if (typeof value !== 'undefined') {
-          if (this.$pluginSelect.length) {
-            this.$pluginSelect[0].value = value;
-          }
-        }
-      }
-
-      const refreshRows = {};
-      refreshRows[this.name] = this.$pluginSelect.get(0);
-
-      return refreshRows;
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/field_ui/field_ui.js b/core/modules/field_ui/field_ui.js
index f90a0ff64fd2..950df384ca7c 100644
--- a/core/modules/field_ui/field_ui.js
+++ b/core/modules/field_ui/field_ui.js
@@ -1,186 +1,374 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches the behaviors for the Field UI module.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Adds behaviors to the field storage add form.
+   */
   Drupal.behaviors.fieldUIFieldStorageAddForm = {
     attach(context) {
-      const form = once('field_ui_add', '[data-drupal-selector="field-ui-field-storage-add-form"]', context);
-
+      const form = once(
+        'field_ui_add',
+        '[data-drupal-selector="field-ui-field-storage-add-form"]',
+        context,
+      );
       if (form.length) {
         const $form = $(form);
-        $form.find('.js-form-item-label label,' + '.js-form-item-field-name label,' + '.js-form-item-existing-storage-label label').addClass('js-form-required form-required');
+        // Add a few 'js-form-required' and 'form-required' css classes here.
+        // We can not use the Form API '#required' property because both label
+        // elements for "add new" and "re-use existing" can never be filled and
+        // submitted at the same time. The actual validation will happen
+        // server-side.
+        $form
+          .find(
+            '.js-form-item-label label,' +
+              '.js-form-item-field-name label,' +
+              '.js-form-item-existing-storage-label label',
+          )
+          .addClass('js-form-required form-required');
+
         const $newFieldType = $form.find('select[name="new_storage_type"]');
-        const $existingStorageName = $form.find('select[name="existing_storage_name"]');
-        const $existingStorageLabel = $form.find('input[name="existing_storage_label"]');
+        const $existingStorageName = $form.find(
+          'select[name="existing_storage_name"]',
+        );
+        const $existingStorageLabel = $form.find(
+          'input[name="existing_storage_label"]',
+        );
+
+        // When the user selects a new field type, clear the "existing field"
+        // selection.
         $newFieldType.on('change', function () {
           if (this.value !== '') {
+            // Reset the "existing storage name" selection.
             if ($existingStorageName.length) {
               $existingStorageName[0].value = '';
               $existingStorageName.trigger('change');
             }
           }
         });
-        $existingStorageName.on('change', function () {
-          const {
-            value
-          } = this;
 
+        // When the user selects an existing storage name, clear the "new field
+        // type" selection and populate the 'existing_storage_label' element.
+        $existingStorageName.on('change', function () {
+          const { value } = this;
           if (value !== '') {
             if ($newFieldType.length) {
+              // Reset the "new field type" selection.
               $newFieldType[0].value = '';
               $newFieldType.trigger('change');
             }
 
-            if (typeof drupalSettings.existingFieldLabels[value] !== 'undefined') {
-              $existingStorageLabel[0].value = drupalSettings.existingFieldLabels[value];
+            // Pre-populate the "existing storage label" element.
+            if (
+              typeof drupalSettings.existingFieldLabels[value] !== 'undefined'
+            ) {
+              $existingStorageLabel[0].value =
+                drupalSettings.existingFieldLabels[value];
             }
           }
         });
       }
-    }
-
+    },
   };
+
+  /**
+   * Attaches the fieldUIOverview behavior.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the fieldUIOverview behavior.
+   *
+   * @see Drupal.fieldUIOverview.attach
+   */
   Drupal.behaviors.fieldUIDisplayOverview = {
     attach(context, settings) {
-      once('field-display-overview', 'table#field-display-overview', context).forEach(overview => {
-        Drupal.fieldUIOverview.attach(overview, settings.fieldUIRowsData, Drupal.fieldUIDisplayOverview);
+      once(
+        'field-display-overview',
+        'table#field-display-overview',
+        context,
+      ).forEach((overview) => {
+        Drupal.fieldUIOverview.attach(
+          overview,
+          settings.fieldUIRowsData,
+          Drupal.fieldUIDisplayOverview,
+        );
       });
-    }
-
+    },
   };
+
+  /**
+   * Namespace for the field UI overview.
+   *
+   * @namespace
+   */
   Drupal.fieldUIOverview = {
+    /**
+     * Attaches the fieldUIOverview behavior.
+     *
+     * @param {HTMLTableElement} table
+     *   The table element for the overview.
+     * @param {object} rowsData
+     *   The data of the rows in the table.
+     * @param {object} rowHandlers
+     *   Handlers to be added to the rows.
+     */
     attach(table, rowsData, rowHandlers) {
       const tableDrag = Drupal.tableDrag[table.id];
+
+      // Add custom tabledrag callbacks.
       tableDrag.onDrop = this.onDrop;
       tableDrag.row.prototype.onSwap = this.onSwap;
-      $(table).find('tr.draggable').each(function () {
-        const row = this;
-
-        if (row.id in rowsData) {
-          const data = rowsData[row.id];
-          data.tableDrag = tableDrag;
-          const rowHandler = new rowHandlers[data.rowHandler](row, data);
-          $(row).data('fieldUIRowHandler', rowHandler);
-        }
-      });
+
+      // Create row handlers.
+      $(table)
+        .find('tr.draggable')
+        .each(function () {
+          // Extract server-side data for the row.
+          const row = this;
+          if (row.id in rowsData) {
+            const data = rowsData[row.id];
+            data.tableDrag = tableDrag;
+
+            // Create the row handler, make it accessible from the DOM row
+            // element.
+            const rowHandler = new rowHandlers[data.rowHandler](row, data);
+            $(row).data('fieldUIRowHandler', rowHandler);
+          }
+        });
     },
 
+    /**
+     * Event handler to be attached to form inputs triggering a region change.
+     */
     onChange() {
       const $trigger = $(this);
       const $row = $trigger.closest('tr');
       const rowHandler = $row.data('fieldUIRowHandler');
+
       const refreshRows = {};
       refreshRows[rowHandler.name] = $trigger.get(0);
-      const region = rowHandler.getRegion();
 
+      // Handle region change.
+      const region = rowHandler.getRegion();
       if (region !== rowHandler.region) {
         const $fieldParent = $row.find('select.js-field-parent');
-
         if ($fieldParent.length) {
+          // Remove parenting.
           $fieldParent[0].value = '';
         }
-
+        // Let the row handler deal with the region change.
         $.extend(refreshRows, rowHandler.regionChange(region));
+        // Update the row region.
         rowHandler.region = region;
       }
 
+      // Ajax-update the rows.
       Drupal.fieldUIOverview.AJAXRefreshRows(refreshRows);
     },
 
+    /**
+     * Lets row handlers react when a row is dropped into a new region.
+     */
     onDrop() {
       const dragObject = this;
       const row = dragObject.rowObject.element;
       const $row = $(row);
       const rowHandler = $row.data('fieldUIRowHandler');
-
       if (typeof rowHandler !== 'undefined') {
         const regionRow = $row.prevAll('tr.region-message').get(0);
-        const region = regionRow.className.replace(/([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
+        const region = regionRow.className.replace(
+          /([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/,
+          '$2',
+        );
 
         if (region !== rowHandler.region) {
+          // Let the row handler deal with the region change.
           const refreshRows = rowHandler.regionChange(region);
+          // Update the row region.
           rowHandler.region = region;
+          // Ajax-update the rows.
           Drupal.fieldUIOverview.AJAXRefreshRows(refreshRows);
         }
       }
     },
 
+    /**
+     * Refreshes placeholder rows in empty regions while a row is being dragged.
+     *
+     * Copied from block.js.
+     *
+     * @param {HTMLElement} draggedRow
+     *   The tableDrag rowObject for the row being dragged.
+     */
     onSwap(draggedRow) {
       const rowObject = this;
-      $(rowObject.table).find('tr.region-message').each(function () {
-        const $this = $(this);
-
-        if ($this.prev('tr').get(0) === rowObject.group[rowObject.group.length - 1]) {
-          if (rowObject.method !== 'keyboard' || rowObject.direction === 'down') {
-            rowObject.swap('after', this);
+      $(rowObject.table)
+        .find('tr.region-message')
+        .each(function () {
+          const $this = $(this);
+          // If the dragged row is in this region, but above the message row, swap
+          // it down one space.
+          if (
+            $this.prev('tr').get(0) ===
+            rowObject.group[rowObject.group.length - 1]
+          ) {
+            // Prevent a recursion problem when using the keyboard to move rows
+            // up.
+            if (
+              rowObject.method !== 'keyboard' ||
+              rowObject.direction === 'down'
+            ) {
+              rowObject.swap('after', this);
+            }
           }
-        }
-
-        if ($this.next('tr').is(':not(.draggable)') || $this.next('tr').length === 0) {
-          $this.removeClass('region-populated').addClass('region-empty');
-        } else if ($this.is('.region-empty')) {
-          $this.removeClass('region-empty').addClass('region-populated');
-        }
-      });
+          // This region has become empty.
+          if (
+            $this.next('tr').is(':not(.draggable)') ||
+            $this.next('tr').length === 0
+          ) {
+            $this.removeClass('region-populated').addClass('region-empty');
+          }
+          // This region has become populated.
+          else if ($this.is('.region-empty')) {
+            $this.removeClass('region-empty').addClass('region-populated');
+          }
+        });
     },
 
+    /**
+     * Triggers Ajax refresh of selected rows.
+     *
+     * The 'format type' selects can trigger a series of changes in child rows.
+     * The #ajax behavior is therefore not attached directly to the selects, but
+     * triggered manually through a hidden #ajax 'Refresh' button.
+     *
+     * @param {object} rows
+     *   A hash object, whose keys are the names of the rows to refresh (they
+     *   will receive the 'ajax-new-content' effect on the server side), and
+     *   whose values are the DOM element in the row that should get an Ajax
+     *   throbber.
+     */
     AJAXRefreshRows(rows) {
+      // Separate keys and values.
       const rowNames = [];
       const ajaxElements = [];
-      Object.keys(rows || {}).forEach(rowName => {
+      Object.keys(rows || {}).forEach((rowName) => {
         rowNames.push(rowName);
         ajaxElements.push(rows[rowName]);
       });
 
       if (rowNames.length) {
+        // Add a throbber next each of the ajaxElements.
         $(ajaxElements).after(Drupal.theme.ajaxProgressThrobber());
         const $refreshRows = $('input[name=refresh_rows]');
-
         if ($refreshRows.length) {
+          // Fire the Ajax update.
           $refreshRows[0].value = rowNames.join(' ');
         }
-
         $('input[data-drupal-selector="edit-refresh"]').trigger('mousedown');
+
+        // Disabled elements do not appear in POST ajax data, so we mark the
+        // elements disabled only after firing the request.
         $(ajaxElements).prop('disabled', true);
       }
-    }
-
+    },
   };
+
+  /**
+   * Row handlers for the 'Manage display' screen.
+   *
+   * @namespace
+   */
   Drupal.fieldUIDisplayOverview = {};
 
+  /**
+   * Constructor for a 'field' row handler.
+   *
+   * This handler is used for both fields and 'extra fields' rows.
+   *
+   * @constructor
+   *
+   * @param {HTMLTableRowElement} row
+   *   The row DOM element.
+   * @param {object} data
+   *   Additional data to be populated in the constructed object.
+   *
+   * @return {Drupal.fieldUIDisplayOverview.field}
+   *   The field row handler constructed.
+   */
   Drupal.fieldUIDisplayOverview.field = function (row, data) {
     this.row = row;
     this.name = data.name;
     this.region = data.region;
     this.tableDrag = data.tableDrag;
     this.defaultPlugin = data.defaultPlugin;
+
+    // Attach change listener to the 'plugin type' select.
     this.$pluginSelect = $(row).find('.field-plugin-type');
     this.$pluginSelect.on('change', Drupal.fieldUIOverview.onChange);
+
+    // Attach change listener to the 'region' select.
     this.$regionSelect = $(row).find('select.field-region');
     this.$regionSelect.on('change', Drupal.fieldUIOverview.onChange);
+
     return this;
   };
 
   Drupal.fieldUIDisplayOverview.field.prototype = {
+    /**
+     * Returns the region corresponding to the current form values of the row.
+     *
+     * @return {string}
+     *   Either 'hidden' or 'content'.
+     */
     getRegion() {
       if (this.$regionSelect.length) {
         return this.$regionSelect[0].value;
       }
     },
 
+    /**
+     * Reacts to a row being changed regions.
+     *
+     * This function is called when the row is moved to a different region, as
+     * a
+     * result of either :
+     * - a drag-and-drop action (the row's form elements then probably need to
+     * be updated accordingly)
+     * - user input in one of the form elements watched by the
+     *   {@link Drupal.fieldUIOverview.onChange} change listener.
+     *
+     * @param {string} region
+     *   The name of the new region for the row.
+     *
+     * @return {object}
+     *   A hash object indicating which rows should be Ajax-updated as a result
+     *   of the change, in the format expected by
+     *   {@link Drupal.fieldUIOverview.AJAXRefreshRows}.
+     */
     regionChange(region) {
+      // Replace dashes with underscores.
       region = region.replace(/-/g, '_');
 
       if (this.$regionSelect.length) {
+        // Set the region of the select list.
         this.$regionSelect[0].value = region;
       }
 
+      // Restore the formatter back to the default formatter only if it was
+      // disabled previously. Pseudo-fields do not have default formatters,
+      // we just return to 'visible' for those.
       if (this.region === 'hidden') {
-        const value = typeof this.defaultPlugin !== 'undefined' ? this.defaultPlugin : this.$pluginSelect.find('option')[0].value;
+        const value =
+          typeof this.defaultPlugin !== 'undefined'
+            ? this.defaultPlugin
+            : this.$pluginSelect.find('option')[0].value;
 
         if (typeof value !== 'undefined') {
           if (this.$pluginSelect.length) {
@@ -191,8 +379,8 @@
 
       const refreshRows = {};
       refreshRows[this.name] = this.$pluginSelect.get(0);
-      return refreshRows;
-    }
 
+      return refreshRows;
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/file/file.es6.js b/core/modules/file/file.es6.js
deleted file mode 100644
index 3c6d19a4c388..000000000000
--- a/core/modules/file/file.es6.js
+++ /dev/null
@@ -1,299 +0,0 @@
-/**
- * @file
- * Provides JavaScript additions to the managed file field type.
- *
- * This file provides progress bar support (if available), popup windows for
- * file previews, and disabling of other file fields during Ajax uploads (which
- * prevents separate file fields from accidentally uploading files).
- */
-
-(function ($, Drupal) {
-  /**
-   * Attach behaviors to the file fields passed in the settings.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches validation for file extensions.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detaches validation for file extensions.
-   */
-  Drupal.behaviors.fileValidateAutoAttach = {
-    attach(context, settings) {
-      const $context = $(context);
-      let elements;
-
-      function initFileValidation(selector) {
-        $(once('fileValidate', $context.find(selector))).on(
-          'change.fileValidate',
-          { extensions: elements[selector] },
-          Drupal.file.validateExtension,
-        );
-      }
-
-      if (settings.file && settings.file.elements) {
-        elements = settings.file.elements;
-        Object.keys(elements).forEach(initFileValidation);
-      }
-    },
-    detach(context, settings, trigger) {
-      const $context = $(context);
-      let elements;
-
-      function removeFileValidation(selector) {
-        $(once.remove('fileValidate', $context.find(selector))).off(
-          'change.fileValidate',
-          Drupal.file.validateExtension,
-        );
-      }
-
-      if (trigger === 'unload' && settings.file && settings.file.elements) {
-        elements = settings.file.elements;
-        Object.keys(elements).forEach(removeFileValidation);
-      }
-    },
-  };
-
-  /**
-   * Attach behaviors to file element auto upload.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches triggers for the upload button.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detaches auto file upload trigger.
-   */
-  Drupal.behaviors.fileAutoUpload = {
-    attach(context) {
-      $(once('auto-file-upload', 'input[type="file"]', context)).on(
-        'change.autoFileUpload',
-        Drupal.file.triggerUploadButton,
-      );
-    },
-    detach(context, settings, trigger) {
-      if (trigger === 'unload') {
-        $(once.remove('auto-file-upload', 'input[type="file"]', context)).off(
-          '.autoFileUpload',
-        );
-      }
-    },
-  };
-
-  /**
-   * Attach behaviors to the file upload and remove buttons.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches form submit events.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detaches form submit events.
-   */
-  Drupal.behaviors.fileButtons = {
-    attach(context) {
-      const $context = $(context);
-      $context
-        .find('.js-form-submit')
-        .on('mousedown', Drupal.file.disableFields);
-      $context
-        .find('.js-form-managed-file .js-form-submit')
-        .on('mousedown', Drupal.file.progressBar);
-    },
-    detach(context, settings, trigger) {
-      if (trigger === 'unload') {
-        const $context = $(context);
-        $context
-          .find('.js-form-submit')
-          .off('mousedown', Drupal.file.disableFields);
-        $context
-          .find('.js-form-managed-file .js-form-submit')
-          .off('mousedown', Drupal.file.progressBar);
-      }
-    },
-  };
-
-  /**
-   * Attach behaviors to links within managed file elements for preview windows.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches triggers.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detaches triggers.
-   */
-  Drupal.behaviors.filePreviewLinks = {
-    attach(context) {
-      $(context)
-        .find('div.js-form-managed-file .file a')
-        .on('click', Drupal.file.openInNewWindow);
-    },
-    detach(context) {
-      $(context)
-        .find('div.js-form-managed-file .file a')
-        .off('click', Drupal.file.openInNewWindow);
-    },
-  };
-
-  /**
-   * File upload utility functions.
-   *
-   * @namespace
-   */
-  Drupal.file = Drupal.file || {
-    /**
-     * Client-side file input validation of file extensions.
-     *
-     * @name Drupal.file.validateExtension
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered. For example `change.fileValidate`.
-     */
-    validateExtension(event) {
-      event.preventDefault();
-      // Remove any previous errors.
-      $('.file-upload-js-error').remove();
-
-      // Add client side validation for the input[type=file].
-      const extensionPattern = event.data.extensions.replace(/,\s*/g, '|');
-      if (extensionPattern.length > 1 && this.value.length > 0) {
-        const acceptableMatch = new RegExp(`\\.(${extensionPattern})$`, 'gi');
-        if (!acceptableMatch.test(this.value)) {
-          const error = Drupal.t(
-            'The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.',
-            {
-              // According to the specifications of HTML5, a file upload control
-              // should not reveal the real local path to the file that a user
-              // has selected. Some web browsers implement this restriction by
-              // replacing the local path with "C:\fakepath\", which can cause
-              // confusion by leaving the user thinking perhaps Drupal could not
-              // find the file because it messed up the file path. To avoid this
-              // confusion, therefore, we strip out the bogus fakepath string.
-              '%filename': this.value.replace('C:\\fakepath\\', ''),
-              '%extensions': extensionPattern.replace(/\|/g, ', '),
-            },
-          );
-          $(this)
-            .closest('div.js-form-managed-file')
-            .prepend(
-              `<div class="messages messages--error file-upload-js-error" aria-live="polite">${error}</div>`,
-            );
-          this.value = '';
-          // Cancel all other change event handlers.
-          event.stopImmediatePropagation();
-        }
-      }
-    },
-
-    /**
-     * Trigger the upload_button mouse event to auto-upload as a managed file.
-     *
-     * @name Drupal.file.triggerUploadButton
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered. For example `change.autoFileUpload`.
-     */
-    triggerUploadButton(event) {
-      $(event.target)
-        .closest('.js-form-managed-file')
-        .find('.js-form-submit[data-drupal-selector$="upload-button"]')
-        .trigger('mousedown');
-    },
-
-    /**
-     * Prevent file uploads when using buttons not intended to upload.
-     *
-     * @name Drupal.file.disableFields
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered, most likely a `mousedown` event.
-     */
-    disableFields(event) {
-      const $clickedButton = $(this);
-      $clickedButton.trigger('formUpdated');
-
-      // Check if we're working with an "Upload" button.
-      let $enabledFields = [];
-      if ($clickedButton.closest('div.js-form-managed-file').length > 0) {
-        $enabledFields = $clickedButton
-          .closest('div.js-form-managed-file')
-          .find('input.js-form-file');
-      }
-
-      // Temporarily disable upload fields other than the one we're currently
-      // working with. Filter out fields that are already disabled so that they
-      // do not get enabled when we re-enable these fields at the end of
-      // behavior processing. Re-enable in a setTimeout set to a relatively
-      // short amount of time (1 second). All the other mousedown handlers
-      // (like Drupal's Ajax behaviors) are executed before any timeout
-      // functions are called, so we don't have to worry about the fields being
-      // re-enabled too soon. @todo If the previous sentence is true, why not
-      // set the timeout to 0?
-      const $fieldsToTemporarilyDisable = $(
-        'div.js-form-managed-file input.js-form-file',
-      )
-        .not($enabledFields)
-        .not(':disabled');
-      $fieldsToTemporarilyDisable.prop('disabled', true);
-      setTimeout(() => {
-        $fieldsToTemporarilyDisable.prop('disabled', false);
-      }, 1000);
-    },
-
-    /**
-     * Add progress bar support if possible.
-     *
-     * @name Drupal.file.progressBar
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered, most likely a `mousedown` event.
-     */
-    progressBar(event) {
-      const $clickedButton = $(this);
-      const $progressId = $clickedButton
-        .closest('div.js-form-managed-file')
-        .find('input.file-progress');
-      if ($progressId.length) {
-        const originalName = $progressId.attr('name');
-
-        // Replace the name with the required identifier.
-        $progressId.attr(
-          'name',
-          originalName.match(/APC_UPLOAD_PROGRESS|UPLOAD_IDENTIFIER/)[0],
-        );
-
-        // Restore the original name after the upload begins.
-        setTimeout(() => {
-          $progressId.attr('name', originalName);
-        }, 1000);
-      }
-      // Show the progress bar if the upload takes longer than half a second.
-      setTimeout(() => {
-        $clickedButton
-          .closest('div.js-form-managed-file')
-          .find('div.ajax-progress-bar')
-          .slideDown();
-      }, 500);
-      $clickedButton.trigger('fileUpload');
-    },
-
-    /**
-     * Open links to files within forms in a new window.
-     *
-     * @name Drupal.file.openInNewWindow
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered, most likely a `click` event.
-     */
-    openInNewWindow(event) {
-      event.preventDefault();
-      $(this).attr('target', '_blank');
-      window.open(
-        this.href,
-        'filePreview',
-        'toolbar=0,scrollbars=1,location=1,statusbar=1,menubar=0,resizable=1,width=500,height=550',
-      );
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/file/file.js b/core/modules/file/file.js
index 56d48e8f2e27..3c6d19a4c388 100644
--- a/core/modules/file/file.js
+++ b/core/modules/file/file.js
@@ -1,20 +1,34 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Provides JavaScript additions to the managed file field type.
+ *
+ * This file provides progress bar support (if available), popup windows for
+ * file previews, and disabling of other file fields during Ajax uploads (which
+ * prevents separate file fields from accidentally uploading files).
+ */
 
 (function ($, Drupal) {
+  /**
+   * Attach behaviors to the file fields passed in the settings.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches validation for file extensions.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches validation for file extensions.
+   */
   Drupal.behaviors.fileValidateAutoAttach = {
     attach(context, settings) {
       const $context = $(context);
       let elements;
 
       function initFileValidation(selector) {
-        $(once('fileValidate', $context.find(selector))).on('change.fileValidate', {
-          extensions: elements[selector]
-        }, Drupal.file.validateExtension);
+        $(once('fileValidate', $context.find(selector))).on(
+          'change.fileValidate',
+          { extensions: elements[selector] },
+          Drupal.file.validateExtension,
+        );
       }
 
       if (settings.file && settings.file.elements) {
@@ -22,124 +36,264 @@
         Object.keys(elements).forEach(initFileValidation);
       }
     },
-
     detach(context, settings, trigger) {
       const $context = $(context);
       let elements;
 
       function removeFileValidation(selector) {
-        $(once.remove('fileValidate', $context.find(selector))).off('change.fileValidate', Drupal.file.validateExtension);
+        $(once.remove('fileValidate', $context.find(selector))).off(
+          'change.fileValidate',
+          Drupal.file.validateExtension,
+        );
       }
 
       if (trigger === 'unload' && settings.file && settings.file.elements) {
         elements = settings.file.elements;
         Object.keys(elements).forEach(removeFileValidation);
       }
-    }
-
+    },
   };
+
+  /**
+   * Attach behaviors to file element auto upload.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches triggers for the upload button.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches auto file upload trigger.
+   */
   Drupal.behaviors.fileAutoUpload = {
     attach(context) {
-      $(once('auto-file-upload', 'input[type="file"]', context)).on('change.autoFileUpload', Drupal.file.triggerUploadButton);
+      $(once('auto-file-upload', 'input[type="file"]', context)).on(
+        'change.autoFileUpload',
+        Drupal.file.triggerUploadButton,
+      );
     },
-
     detach(context, settings, trigger) {
       if (trigger === 'unload') {
-        $(once.remove('auto-file-upload', 'input[type="file"]', context)).off('.autoFileUpload');
+        $(once.remove('auto-file-upload', 'input[type="file"]', context)).off(
+          '.autoFileUpload',
+        );
       }
-    }
-
+    },
   };
+
+  /**
+   * Attach behaviors to the file upload and remove buttons.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches form submit events.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches form submit events.
+   */
   Drupal.behaviors.fileButtons = {
     attach(context) {
       const $context = $(context);
-      $context.find('.js-form-submit').on('mousedown', Drupal.file.disableFields);
-      $context.find('.js-form-managed-file .js-form-submit').on('mousedown', Drupal.file.progressBar);
+      $context
+        .find('.js-form-submit')
+        .on('mousedown', Drupal.file.disableFields);
+      $context
+        .find('.js-form-managed-file .js-form-submit')
+        .on('mousedown', Drupal.file.progressBar);
     },
-
     detach(context, settings, trigger) {
       if (trigger === 'unload') {
         const $context = $(context);
-        $context.find('.js-form-submit').off('mousedown', Drupal.file.disableFields);
-        $context.find('.js-form-managed-file .js-form-submit').off('mousedown', Drupal.file.progressBar);
+        $context
+          .find('.js-form-submit')
+          .off('mousedown', Drupal.file.disableFields);
+        $context
+          .find('.js-form-managed-file .js-form-submit')
+          .off('mousedown', Drupal.file.progressBar);
       }
-    }
-
+    },
   };
+
+  /**
+   * Attach behaviors to links within managed file elements for preview windows.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches triggers.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches triggers.
+   */
   Drupal.behaviors.filePreviewLinks = {
     attach(context) {
-      $(context).find('div.js-form-managed-file .file a').on('click', Drupal.file.openInNewWindow);
+      $(context)
+        .find('div.js-form-managed-file .file a')
+        .on('click', Drupal.file.openInNewWindow);
     },
-
     detach(context) {
-      $(context).find('div.js-form-managed-file .file a').off('click', Drupal.file.openInNewWindow);
-    }
-
+      $(context)
+        .find('div.js-form-managed-file .file a')
+        .off('click', Drupal.file.openInNewWindow);
+    },
   };
+
+  /**
+   * File upload utility functions.
+   *
+   * @namespace
+   */
   Drupal.file = Drupal.file || {
+    /**
+     * Client-side file input validation of file extensions.
+     *
+     * @name Drupal.file.validateExtension
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered. For example `change.fileValidate`.
+     */
     validateExtension(event) {
       event.preventDefault();
+      // Remove any previous errors.
       $('.file-upload-js-error').remove();
-      const extensionPattern = event.data.extensions.replace(/,\s*/g, '|');
 
+      // Add client side validation for the input[type=file].
+      const extensionPattern = event.data.extensions.replace(/,\s*/g, '|');
       if (extensionPattern.length > 1 && this.value.length > 0) {
         const acceptableMatch = new RegExp(`\\.(${extensionPattern})$`, 'gi');
-
         if (!acceptableMatch.test(this.value)) {
-          const error = Drupal.t('The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.', {
-            '%filename': this.value.replace('C:\\fakepath\\', ''),
-            '%extensions': extensionPattern.replace(/\|/g, ', ')
-          });
-          $(this).closest('div.js-form-managed-file').prepend(`<div class="messages messages--error file-upload-js-error" aria-live="polite">${error}</div>`);
+          const error = Drupal.t(
+            'The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.',
+            {
+              // According to the specifications of HTML5, a file upload control
+              // should not reveal the real local path to the file that a user
+              // has selected. Some web browsers implement this restriction by
+              // replacing the local path with "C:\fakepath\", which can cause
+              // confusion by leaving the user thinking perhaps Drupal could not
+              // find the file because it messed up the file path. To avoid this
+              // confusion, therefore, we strip out the bogus fakepath string.
+              '%filename': this.value.replace('C:\\fakepath\\', ''),
+              '%extensions': extensionPattern.replace(/\|/g, ', '),
+            },
+          );
+          $(this)
+            .closest('div.js-form-managed-file')
+            .prepend(
+              `<div class="messages messages--error file-upload-js-error" aria-live="polite">${error}</div>`,
+            );
           this.value = '';
+          // Cancel all other change event handlers.
           event.stopImmediatePropagation();
         }
       }
     },
 
+    /**
+     * Trigger the upload_button mouse event to auto-upload as a managed file.
+     *
+     * @name Drupal.file.triggerUploadButton
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered. For example `change.autoFileUpload`.
+     */
     triggerUploadButton(event) {
-      $(event.target).closest('.js-form-managed-file').find('.js-form-submit[data-drupal-selector$="upload-button"]').trigger('mousedown');
+      $(event.target)
+        .closest('.js-form-managed-file')
+        .find('.js-form-submit[data-drupal-selector$="upload-button"]')
+        .trigger('mousedown');
     },
 
+    /**
+     * Prevent file uploads when using buttons not intended to upload.
+     *
+     * @name Drupal.file.disableFields
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered, most likely a `mousedown` event.
+     */
     disableFields(event) {
       const $clickedButton = $(this);
       $clickedButton.trigger('formUpdated');
-      let $enabledFields = [];
 
+      // Check if we're working with an "Upload" button.
+      let $enabledFields = [];
       if ($clickedButton.closest('div.js-form-managed-file').length > 0) {
-        $enabledFields = $clickedButton.closest('div.js-form-managed-file').find('input.js-form-file');
+        $enabledFields = $clickedButton
+          .closest('div.js-form-managed-file')
+          .find('input.js-form-file');
       }
 
-      const $fieldsToTemporarilyDisable = $('div.js-form-managed-file input.js-form-file').not($enabledFields).not(':disabled');
+      // Temporarily disable upload fields other than the one we're currently
+      // working with. Filter out fields that are already disabled so that they
+      // do not get enabled when we re-enable these fields at the end of
+      // behavior processing. Re-enable in a setTimeout set to a relatively
+      // short amount of time (1 second). All the other mousedown handlers
+      // (like Drupal's Ajax behaviors) are executed before any timeout
+      // functions are called, so we don't have to worry about the fields being
+      // re-enabled too soon. @todo If the previous sentence is true, why not
+      // set the timeout to 0?
+      const $fieldsToTemporarilyDisable = $(
+        'div.js-form-managed-file input.js-form-file',
+      )
+        .not($enabledFields)
+        .not(':disabled');
       $fieldsToTemporarilyDisable.prop('disabled', true);
       setTimeout(() => {
         $fieldsToTemporarilyDisable.prop('disabled', false);
       }, 1000);
     },
 
+    /**
+     * Add progress bar support if possible.
+     *
+     * @name Drupal.file.progressBar
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered, most likely a `mousedown` event.
+     */
     progressBar(event) {
       const $clickedButton = $(this);
-      const $progressId = $clickedButton.closest('div.js-form-managed-file').find('input.file-progress');
-
+      const $progressId = $clickedButton
+        .closest('div.js-form-managed-file')
+        .find('input.file-progress');
       if ($progressId.length) {
         const originalName = $progressId.attr('name');
-        $progressId.attr('name', originalName.match(/APC_UPLOAD_PROGRESS|UPLOAD_IDENTIFIER/)[0]);
+
+        // Replace the name with the required identifier.
+        $progressId.attr(
+          'name',
+          originalName.match(/APC_UPLOAD_PROGRESS|UPLOAD_IDENTIFIER/)[0],
+        );
+
+        // Restore the original name after the upload begins.
         setTimeout(() => {
           $progressId.attr('name', originalName);
         }, 1000);
       }
-
+      // Show the progress bar if the upload takes longer than half a second.
       setTimeout(() => {
-        $clickedButton.closest('div.js-form-managed-file').find('div.ajax-progress-bar').slideDown();
+        $clickedButton
+          .closest('div.js-form-managed-file')
+          .find('div.ajax-progress-bar')
+          .slideDown();
       }, 500);
       $clickedButton.trigger('fileUpload');
     },
 
+    /**
+     * Open links to files within forms in a new window.
+     *
+     * @name Drupal.file.openInNewWindow
+     *
+     * @param {jQuery.Event} event
+     *   The event triggered, most likely a `click` event.
+     */
     openInNewWindow(event) {
       event.preventDefault();
       $(this).attr('target', '_blank');
-      window.open(this.href, 'filePreview', 'toolbar=0,scrollbars=1,location=1,statusbar=1,menubar=0,resizable=1,width=500,height=550');
-    }
-
+      window.open(
+        this.href,
+        'filePreview',
+        'toolbar=0,scrollbars=1,location=1,statusbar=1,menubar=0,resizable=1,width=500,height=550',
+      );
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/filter/filter.admin.es6.js b/core/modules/filter/filter.admin.es6.js
deleted file mode 100644
index 731ed5b7a45b..000000000000
--- a/core/modules/filter/filter.admin.es6.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * @file
- * Attaches administration-specific behavior for the Filter module.
- */
-
-(function ($, Drupal) {
-  /**
-   * Displays and updates the status of filters on the admin page.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behaviors to the filter admin view.
-   */
-  Drupal.behaviors.filterStatus = {
-    attach(context, settings) {
-      const $context = $(context);
-      once(
-        'filter-status',
-        '#filters-status-wrapper input.form-checkbox',
-        context,
-      ).forEach((checkbox) => {
-        const $checkbox = $(checkbox);
-        // Retrieve the tabledrag row belonging to this filter.
-        const $row = $context
-          .find(`#${$checkbox.attr('id').replace(/-status$/, '-weight')}`)
-          .closest('tr');
-        // Retrieve the vertical tab belonging to this filter.
-        const $filterSettings = $context.find(
-          `[data-drupal-selector='${$checkbox
-            .attr('id')
-            .replace(/-status$/, '-settings')}']`,
-        );
-        const filterSettingsTab = $filterSettings.data('verticalTab');
-
-        // Bind click handler to this checkbox to conditionally show and hide
-        // the filter's tableDrag row and vertical tab pane.
-        $checkbox.on('click.filterUpdate', () => {
-          if ($checkbox.is(':checked')) {
-            $row.show();
-            if (filterSettingsTab) {
-              filterSettingsTab.tabShow().updateSummary();
-            } else {
-              // On very narrow viewports, Vertical Tabs are disabled.
-              $filterSettings.show();
-            }
-          } else {
-            $row.hide();
-            if (filterSettingsTab) {
-              filterSettingsTab.tabHide().updateSummary();
-            } else {
-              // On very narrow viewports, Vertical Tabs are disabled.
-              $filterSettings.hide();
-            }
-          }
-          // Restripe table after toggling visibility of table row.
-          Drupal.tableDrag['filter-order'].restripeTable();
-        });
-
-        // Attach summary for configurable filters (only for screen readers).
-        if (filterSettingsTab) {
-          filterSettingsTab.details.drupalSetSummary(() =>
-            $checkbox.is(':checked')
-              ? Drupal.t('Enabled')
-              : Drupal.t('Disabled'),
-          );
-        }
-
-        // Trigger our bound click handler to update elements to initial state.
-        $checkbox.triggerHandler('click.filterUpdate');
-      });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/filter/filter.admin.js b/core/modules/filter/filter.admin.js
index 848006dcaf90..731ed5b7a45b 100644
--- a/core/modules/filter/filter.admin.js
+++ b/core/modules/filter/filter.admin.js
@@ -1,48 +1,74 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches administration-specific behavior for the Filter module.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Displays and updates the status of filters on the admin page.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behaviors to the filter admin view.
+   */
   Drupal.behaviors.filterStatus = {
     attach(context, settings) {
       const $context = $(context);
-      once('filter-status', '#filters-status-wrapper input.form-checkbox', context).forEach(checkbox => {
+      once(
+        'filter-status',
+        '#filters-status-wrapper input.form-checkbox',
+        context,
+      ).forEach((checkbox) => {
         const $checkbox = $(checkbox);
-        const $row = $context.find(`#${$checkbox.attr('id').replace(/-status$/, '-weight')}`).closest('tr');
-        const $filterSettings = $context.find(`[data-drupal-selector='${$checkbox.attr('id').replace(/-status$/, '-settings')}']`);
+        // Retrieve the tabledrag row belonging to this filter.
+        const $row = $context
+          .find(`#${$checkbox.attr('id').replace(/-status$/, '-weight')}`)
+          .closest('tr');
+        // Retrieve the vertical tab belonging to this filter.
+        const $filterSettings = $context.find(
+          `[data-drupal-selector='${$checkbox
+            .attr('id')
+            .replace(/-status$/, '-settings')}']`,
+        );
         const filterSettingsTab = $filterSettings.data('verticalTab');
+
+        // Bind click handler to this checkbox to conditionally show and hide
+        // the filter's tableDrag row and vertical tab pane.
         $checkbox.on('click.filterUpdate', () => {
           if ($checkbox.is(':checked')) {
             $row.show();
-
             if (filterSettingsTab) {
               filterSettingsTab.tabShow().updateSummary();
             } else {
+              // On very narrow viewports, Vertical Tabs are disabled.
               $filterSettings.show();
             }
           } else {
             $row.hide();
-
             if (filterSettingsTab) {
               filterSettingsTab.tabHide().updateSummary();
             } else {
+              // On very narrow viewports, Vertical Tabs are disabled.
               $filterSettings.hide();
             }
           }
-
+          // Restripe table after toggling visibility of table row.
           Drupal.tableDrag['filter-order'].restripeTable();
         });
 
+        // Attach summary for configurable filters (only for screen readers).
         if (filterSettingsTab) {
-          filterSettingsTab.details.drupalSetSummary(() => $checkbox.is(':checked') ? Drupal.t('Enabled') : Drupal.t('Disabled'));
+          filterSettingsTab.details.drupalSetSummary(() =>
+            $checkbox.is(':checked')
+              ? Drupal.t('Enabled')
+              : Drupal.t('Disabled'),
+          );
         }
 
+        // Trigger our bound click handler to update elements to initial state.
         $checkbox.triggerHandler('click.filterUpdate');
       });
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/filter/filter.es6.js b/core/modules/filter/filter.es6.js
deleted file mode 100644
index 733dc93f3c9c..000000000000
--- a/core/modules/filter/filter.es6.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * @file
- * Attaches behavior for the Filter module.
- */
-
-(function ($, Drupal) {
-  /**
-   * Displays the guidelines of the selected text format automatically.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior for updating filter guidelines.
-   */
-  Drupal.behaviors.filterGuidelines = {
-    attach(context) {
-      function updateFilterGuidelines(event) {
-        const $this = $(event.target);
-        const { value } = event.target;
-        $this
-          .closest('.js-filter-wrapper')
-          .find('[data-drupal-format-id]')
-          .hide()
-          .filter(`[data-drupal-format-id="${value}"]`)
-          .show();
-      }
-
-      $(once('filter-guidelines', '.js-filter-guidelines', context))
-        .find(':header')
-        .hide()
-        .closest('.js-filter-wrapper')
-        .find('select.js-filter-list')
-        .on('change.filterGuidelines', updateFilterGuidelines)
-        // Need to trigger the namespaced event to avoid triggering formUpdated
-        // when initializing the select.
-        .trigger('change.filterGuidelines');
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/filter/filter.filter_html.admin.es6.js b/core/modules/filter/filter.filter_html.admin.es6.js
deleted file mode 100644
index 260f98ce70f3..000000000000
--- a/core/modules/filter/filter.filter_html.admin.es6.js
+++ /dev/null
@@ -1,393 +0,0 @@
-/**
- * @file
- * Attaches behavior for updating filter_html's settings automatically.
- */
-
-(function ($, Drupal, document) {
-  if (Drupal.filterConfiguration) {
-    /**
-     * Implement a live setting parser to prevent text editors from automatically
-     * enabling buttons that are not allowed by this filter's configuration.
-     *
-     * @namespace
-     */
-    Drupal.filterConfiguration.liveSettingParsers.filter_html = {
-      /**
-       * @return {Array}
-       *   An array of filter rules.
-       */
-      getRules() {
-        const currentValue = document.querySelector(
-          '#edit-filters-filter-html-settings-allowed-html',
-        ).value;
-        const rules =
-          Drupal.behaviors.filterFilterHtmlUpdating._parseSetting(currentValue);
-
-        // Build a FilterHTMLRule that reflects the hard-coded behavior that
-        // strips all "style" attribute and all "on*" attributes.
-        const rule = new Drupal.FilterHTMLRule();
-        rule.restrictedTags.tags = ['*'];
-        rule.restrictedTags.forbidden.attributes = ['style', 'on*'];
-        rules.push(rule);
-
-        return rules;
-      },
-    };
-  }
-
-  /**
-   * Gets the values that are present in one array but not another.
-   *
-   * @param {Array[]} args
-   *   The list of arrays to process.
-   *
-   * @return {Array}
-   *   Returns the first array without the values present in other arrays.
-   */
-  function difference(...args) {
-    return args.reduce((mainData, otherData) =>
-      mainData.filter((data) => !otherData.includes(data)),
-    );
-  }
-
-  /**
-   * Displays and updates what HTML tags are allowed to use in a filter.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @todo Remove everything but 'attach' and 'detach' and make a proper object.
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior for updating allowed HTML tags.
-   */
-  Drupal.behaviors.filterFilterHtmlUpdating = {
-    // The form item contains the "Allowed HTML tags" setting.
-    $allowedHTMLFormItem: null,
-
-    // The description for the "Allowed HTML tags" field.
-    $allowedHTMLDescription: null,
-
-    /**
-     * The parsed, user-entered tag list of $allowedHTMLFormItem
-     *
-     * @var {Object.<string, Drupal.FilterHTMLRule>}
-     */
-    userTags: {},
-
-    // The auto-created tag list thus far added.
-    autoTags: null,
-
-    // Track which new features have been added to the text editor.
-    newFeatures: {},
-
-    attach(context, settings) {
-      const that = this;
-      once(
-        'filter-filter_html-updating',
-        '[name="filters[filter_html][settings][allowed_html]"]',
-        context,
-      ).forEach((formItem) => {
-        that.$allowedHTMLFormItem = $(formItem);
-        that.$allowedHTMLDescription = that.$allowedHTMLFormItem
-          .closest('.js-form-item')
-          .find('#edit-filters-filter-html-settings-allowed-html--description');
-        that.userTags = that._parseSetting(formItem.value);
-
-        // Update the new allowed tags based on added text editor features.
-        $(document)
-          .on('drupalEditorFeatureAdded', (e, feature) => {
-            that.newFeatures[feature.name] = feature.rules;
-            that._updateAllowedTags();
-          })
-          .on('drupalEditorFeatureModified', (e, feature) => {
-            if (that.newFeatures.hasOwnProperty(feature.name)) {
-              that.newFeatures[feature.name] = feature.rules;
-              that._updateAllowedTags();
-            }
-          })
-          .on('drupalEditorFeatureRemoved', (e, feature) => {
-            if (that.newFeatures.hasOwnProperty(feature.name)) {
-              delete that.newFeatures[feature.name];
-              that._updateAllowedTags();
-            }
-          });
-
-        // When the allowed tags list is manually changed, update userTags.
-        that.$allowedHTMLFormItem.on('change.updateUserTags', function () {
-          that.userTags = difference(
-            Object.values(that._parseSetting(this.value)),
-            Object.values(that.autoTags),
-          );
-        });
-      });
-    },
-
-    /**
-     * Updates the "Allowed HTML tags" setting and shows an informative message.
-     */
-    _updateAllowedTags() {
-      // Update the list of auto-created tags.
-      this.autoTags = this._calculateAutoAllowedTags(
-        this.userTags,
-        this.newFeatures,
-      );
-
-      // Remove any previous auto-created tag message.
-      this.$allowedHTMLDescription.find('.editor-update-message').remove();
-
-      // If any auto-created tags: insert message and update form item.
-      if (Object.keys(this.autoTags).length > 0) {
-        this.$allowedHTMLDescription.append(
-          Drupal.theme('filterFilterHTMLUpdateMessage', this.autoTags),
-        );
-
-        const userTagsWithoutOverrides = {};
-        Object.keys(this.userTags)
-          .filter((tag) => !this.autoTags.hasOwnProperty(tag))
-          .forEach((tag) => {
-            userTagsWithoutOverrides[tag] = this.userTags[tag];
-          });
-
-        this.$allowedHTMLFormItem.val(
-          `${this._generateSetting(
-            userTagsWithoutOverrides,
-          )} ${this._generateSetting(this.autoTags)}`,
-        );
-      }
-      // Restore to original state.
-      else {
-        this.$allowedHTMLFormItem.val(this._generateSetting(this.userTags));
-      }
-    },
-
-    /**
-     * Calculates which HTML tags the added text editor buttons need to work.
-     *
-     * The filter_html filter is only concerned with the required tags, not with
-     * any properties, nor with each feature's "allowed" tags.
-     *
-     * @param {Array} userAllowedTags
-     *   The list of user-defined allowed tags.
-     * @param {object} newFeatures
-     *   A list of {@link Drupal.EditorFeature} objects' rules, keyed by
-     *   their name.
-     *
-     * @return {Array}
-     *   A list of new allowed tags.
-     */
-    _calculateAutoAllowedTags(userAllowedTags, newFeatures) {
-      const editorRequiredTags = {};
-
-      // Map the newly added Text Editor features to Drupal.FilterHtmlRule
-      // objects (to allow comparing userTags with autoTags).
-      Object.keys(newFeatures || {}).forEach((featureName) => {
-        const feature = newFeatures[featureName];
-        let featureRule;
-        let filterRule;
-        let tag;
-
-        for (let f = 0; f < feature.length; f++) {
-          featureRule = feature[f];
-          for (let t = 0; t < featureRule.required.tags.length; t++) {
-            tag = featureRule.required.tags[t];
-            if (!editorRequiredTags.hasOwnProperty(tag)) {
-              filterRule = new Drupal.FilterHTMLRule();
-              filterRule.restrictedTags.tags = [tag];
-              // @todo Neither Drupal.FilterHtmlRule nor
-              //   Drupal.EditorFeatureHTMLRule allow for generic attribute
-              //   value restrictions, only for the "class" and "style"
-              //   attribute's values to be restricted. The filter_html filter
-              //   always disallows the "style" attribute, so we only need to
-              //   support "class" attribute value restrictions. Fix once
-              //   https://www.drupal.org/node/2567801 lands.
-              filterRule.restrictedTags.allowed.attributes =
-                featureRule.required.attributes.slice(0);
-              filterRule.restrictedTags.allowed.classes =
-                featureRule.required.classes.slice(0);
-              editorRequiredTags[tag] = filterRule;
-            }
-            // The tag is already allowed, add any additionally allowed
-            // attributes.
-            else {
-              filterRule = editorRequiredTags[tag];
-              filterRule.restrictedTags.allowed.attributes = [
-                ...filterRule.restrictedTags.allowed.attributes,
-                ...featureRule.required.attributes,
-              ];
-              filterRule.restrictedTags.allowed.classes = [
-                ...filterRule.restrictedTags.allowed.classes,
-                ...featureRule.required.classes,
-              ];
-            }
-          }
-        }
-      });
-
-      // Now compare userAllowedTags with editorRequiredTags, and build
-      // autoAllowedTags, which contains:
-      // - any tags in editorRequiredTags but not in userAllowedTags (i.e. tags
-      //   that are additionally going to be allowed)
-      // - any tags in editorRequiredTags that already exists in userAllowedTags
-      //   but does not allow all attributes or attribute values
-      const autoAllowedTags = {};
-      Object.keys(editorRequiredTags).forEach((tag) => {
-        // If userAllowedTags does not contain a rule for this editor-required
-        // tag, then add it to the list of automatically allowed tags.
-        if (!userAllowedTags.hasOwnProperty(tag)) {
-          autoAllowedTags[tag] = editorRequiredTags[tag];
-        }
-        // Otherwise, if userAllowedTags already allows this tag, then check if
-        // additional attributes and classes on this tag are required by the
-        // editor.
-        else {
-          const requiredAttributes =
-            editorRequiredTags[tag].restrictedTags.allowed.attributes;
-          const allowedAttributes =
-            userAllowedTags[tag].restrictedTags.allowed.attributes;
-          const needsAdditionalAttributes =
-            requiredAttributes.length &&
-            difference(requiredAttributes, allowedAttributes).length;
-          const requiredClasses =
-            editorRequiredTags[tag].restrictedTags.allowed.classes;
-          const allowedClasses =
-            userAllowedTags[tag].restrictedTags.allowed.classes;
-          const needsAdditionalClasses =
-            requiredClasses.length &&
-            difference(requiredClasses, allowedClasses).length;
-          if (needsAdditionalAttributes || needsAdditionalClasses) {
-            autoAllowedTags[tag] = userAllowedTags[tag].clone();
-          }
-          if (needsAdditionalAttributes) {
-            autoAllowedTags[tag].restrictedTags.allowed.attributes = [
-              ...allowedAttributes,
-              ...requiredAttributes,
-            ];
-          }
-          if (needsAdditionalClasses) {
-            autoAllowedTags[tag].restrictedTags.allowed.classes = [
-              ...allowedClasses,
-              ...requiredClasses,
-            ];
-          }
-        }
-      });
-
-      return autoAllowedTags;
-    },
-
-    /**
-     * Parses the value of this.$allowedHTMLFormItem.
-     *
-     * @param {string} setting
-     *   The string representation of the setting. For example:
-     *     <p class="callout"> <br> <a href hreflang>
-     *
-     * @return {Object.<string, Drupal.FilterHTMLRule>}
-     *   The corresponding text filter HTML rule objects, one per tag, keyed by
-     *   tag name.
-     */
-    _parseSetting(setting) {
-      let tag;
-      let rule;
-      let attributes;
-      let attribute;
-
-      const allowedTags = setting.match(/(<[^>]+>)/g);
-      const rules = {};
-      for (let t = 0; t < allowedTags.length; t++) {
-        // Create a jQuery object, making it possible to easily retrieve the
-        // tag name of the allowed tag, regardless of what attributes are set or
-        // what its required parent elements are.
-        const $tagObject = $(allowedTags[t]);
-
-        // Parse the tag name from the jQuery object.
-        tag = $tagObject.prop('tagName').toLowerCase();
-
-        // Build the Drupal.FilterHtmlRule object.
-        rule = new Drupal.FilterHTMLRule();
-        // We create one rule per allowed tag, so always one tag.
-        rule.restrictedTags.tags = [tag];
-
-        // Add the attribute restrictions.
-        attributes = $tagObject.prop('attributes');
-        for (let i = 0; i < attributes.length; i++) {
-          attribute = attributes.item(i);
-          const attributeName = attribute.nodeName;
-          // @todo Drupal.FilterHtmlRule does not allow for generic attribute
-          //   value restrictions, only for the "class" and "style" attribute's
-          //   values. The filter_html filter always disallows the "style"
-          //   attribute, so we only need to support "class" attribute value
-          //   restrictions. Fix once https://www.drupal.org/node/2567801 lands.
-          if (attributeName === 'class') {
-            const attributeValue = attribute.textContent;
-            rule.restrictedTags.allowed.classes = attributeValue.split(' ');
-          } else {
-            rule.restrictedTags.allowed.attributes.push(attributeName);
-          }
-        }
-
-        rules[tag] = rule;
-      }
-      return rules;
-    },
-
-    /**
-     * Generates the value of this.$allowedHTMLFormItem.
-     *
-     * @param {Object.<string, Drupal.FilterHTMLRule>} tags
-     *   The parsed representation of the setting.
-     *
-     * @return {Array}
-     *   The string representation of the setting. e.g. "<p> <br> <a>"
-     */
-    _generateSetting(tags) {
-      return Object.keys(tags).reduce((setting, tag) => {
-        const rule = tags[tag];
-
-        if (setting.length) {
-          setting += ' ';
-        }
-
-        setting += `<${tag}`;
-        if (rule.restrictedTags.allowed.attributes.length) {
-          setting += ` ${rule.restrictedTags.allowed.attributes.join(' ')}`;
-        }
-        // @todo Drupal.FilterHtmlRule does not allow for generic attribute
-        //   value restrictions, only for the "class" and "style" attribute's
-        //   values. The filter_html filter always disallows the "style"
-        //   attribute, so we only need to support "class" attribute value
-        //   restrictions. Fix once https://www.drupal.org/node/2567801 lands.
-        if (rule.restrictedTags.allowed.classes.length) {
-          setting += ` class="${rule.restrictedTags.allowed.classes.join(
-            ' ',
-          )}"`;
-        }
-
-        setting += '>';
-        return setting;
-      }, '');
-    },
-  };
-
-  /**
-   * Theme function for the filter_html update message.
-   *
-   * @param {Array} tags
-   *   An array of the new tags that are to be allowed.
-   *
-   * @return {string}
-   *   The corresponding HTML.
-   */
-  Drupal.theme.filterFilterHTMLUpdateMessage = function (tags) {
-    let html = '';
-    const tagList =
-      Drupal.behaviors.filterFilterHtmlUpdating._generateSetting(tags);
-    html += '<p class="editor-update-message">';
-    html += Drupal.t(
-      'Based on the text editor configuration, these tags have automatically been added: <strong>@tag-list</strong>.',
-      { '@tag-list': tagList },
-    );
-    html += '</p>';
-    return html;
-  };
-})(jQuery, Drupal, document);
diff --git a/core/modules/filter/filter.filter_html.admin.js b/core/modules/filter/filter.filter_html.admin.js
index 0dc585c7a33a..260f98ce70f3 100644
--- a/core/modules/filter/filter.filter_html.admin.js
+++ b/core/modules/filter/filter.filter_html.admin.js
@@ -1,91 +1,186 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches behavior for updating filter_html's settings automatically.
+ */
 
 (function ($, Drupal, document) {
   if (Drupal.filterConfiguration) {
+    /**
+     * Implement a live setting parser to prevent text editors from automatically
+     * enabling buttons that are not allowed by this filter's configuration.
+     *
+     * @namespace
+     */
     Drupal.filterConfiguration.liveSettingParsers.filter_html = {
+      /**
+       * @return {Array}
+       *   An array of filter rules.
+       */
       getRules() {
-        const currentValue = document.querySelector('#edit-filters-filter-html-settings-allowed-html').value;
-
-        const rules = Drupal.behaviors.filterFilterHtmlUpdating._parseSetting(currentValue);
-
+        const currentValue = document.querySelector(
+          '#edit-filters-filter-html-settings-allowed-html',
+        ).value;
+        const rules =
+          Drupal.behaviors.filterFilterHtmlUpdating._parseSetting(currentValue);
+
+        // Build a FilterHTMLRule that reflects the hard-coded behavior that
+        // strips all "style" attribute and all "on*" attributes.
         const rule = new Drupal.FilterHTMLRule();
         rule.restrictedTags.tags = ['*'];
         rule.restrictedTags.forbidden.attributes = ['style', 'on*'];
         rules.push(rule);
-        return rules;
-      }
 
+        return rules;
+      },
     };
   }
 
-  function difference() {
-    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
-      args[_key] = arguments[_key];
-    }
-
-    return args.reduce((mainData, otherData) => mainData.filter(data => !otherData.includes(data)));
+  /**
+   * Gets the values that are present in one array but not another.
+   *
+   * @param {Array[]} args
+   *   The list of arrays to process.
+   *
+   * @return {Array}
+   *   Returns the first array without the values present in other arrays.
+   */
+  function difference(...args) {
+    return args.reduce((mainData, otherData) =>
+      mainData.filter((data) => !otherData.includes(data)),
+    );
   }
 
+  /**
+   * Displays and updates what HTML tags are allowed to use in a filter.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @todo Remove everything but 'attach' and 'detach' and make a proper object.
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior for updating allowed HTML tags.
+   */
   Drupal.behaviors.filterFilterHtmlUpdating = {
+    // The form item contains the "Allowed HTML tags" setting.
     $allowedHTMLFormItem: null,
+
+    // The description for the "Allowed HTML tags" field.
     $allowedHTMLDescription: null,
+
+    /**
+     * The parsed, user-entered tag list of $allowedHTMLFormItem
+     *
+     * @var {Object.<string, Drupal.FilterHTMLRule>}
+     */
     userTags: {},
+
+    // The auto-created tag list thus far added.
     autoTags: null,
+
+    // Track which new features have been added to the text editor.
     newFeatures: {},
 
     attach(context, settings) {
       const that = this;
-      once('filter-filter_html-updating', '[name="filters[filter_html][settings][allowed_html]"]', context).forEach(formItem => {
+      once(
+        'filter-filter_html-updating',
+        '[name="filters[filter_html][settings][allowed_html]"]',
+        context,
+      ).forEach((formItem) => {
         that.$allowedHTMLFormItem = $(formItem);
-        that.$allowedHTMLDescription = that.$allowedHTMLFormItem.closest('.js-form-item').find('#edit-filters-filter-html-settings-allowed-html--description');
+        that.$allowedHTMLDescription = that.$allowedHTMLFormItem
+          .closest('.js-form-item')
+          .find('#edit-filters-filter-html-settings-allowed-html--description');
         that.userTags = that._parseSetting(formItem.value);
-        $(document).on('drupalEditorFeatureAdded', (e, feature) => {
-          that.newFeatures[feature.name] = feature.rules;
 
-          that._updateAllowedTags();
-        }).on('drupalEditorFeatureModified', (e, feature) => {
-          if (that.newFeatures.hasOwnProperty(feature.name)) {
+        // Update the new allowed tags based on added text editor features.
+        $(document)
+          .on('drupalEditorFeatureAdded', (e, feature) => {
             that.newFeatures[feature.name] = feature.rules;
-
             that._updateAllowedTags();
-          }
-        }).on('drupalEditorFeatureRemoved', (e, feature) => {
-          if (that.newFeatures.hasOwnProperty(feature.name)) {
-            delete that.newFeatures[feature.name];
+          })
+          .on('drupalEditorFeatureModified', (e, feature) => {
+            if (that.newFeatures.hasOwnProperty(feature.name)) {
+              that.newFeatures[feature.name] = feature.rules;
+              that._updateAllowedTags();
+            }
+          })
+          .on('drupalEditorFeatureRemoved', (e, feature) => {
+            if (that.newFeatures.hasOwnProperty(feature.name)) {
+              delete that.newFeatures[feature.name];
+              that._updateAllowedTags();
+            }
+          });
 
-            that._updateAllowedTags();
-          }
-        });
+        // When the allowed tags list is manually changed, update userTags.
         that.$allowedHTMLFormItem.on('change.updateUserTags', function () {
-          that.userTags = difference(Object.values(that._parseSetting(this.value)), Object.values(that.autoTags));
+          that.userTags = difference(
+            Object.values(that._parseSetting(this.value)),
+            Object.values(that.autoTags),
+          );
         });
       });
     },
 
+    /**
+     * Updates the "Allowed HTML tags" setting and shows an informative message.
+     */
     _updateAllowedTags() {
-      this.autoTags = this._calculateAutoAllowedTags(this.userTags, this.newFeatures);
+      // Update the list of auto-created tags.
+      this.autoTags = this._calculateAutoAllowedTags(
+        this.userTags,
+        this.newFeatures,
+      );
+
+      // Remove any previous auto-created tag message.
       this.$allowedHTMLDescription.find('.editor-update-message').remove();
 
+      // If any auto-created tags: insert message and update form item.
       if (Object.keys(this.autoTags).length > 0) {
-        this.$allowedHTMLDescription.append(Drupal.theme('filterFilterHTMLUpdateMessage', this.autoTags));
+        this.$allowedHTMLDescription.append(
+          Drupal.theme('filterFilterHTMLUpdateMessage', this.autoTags),
+        );
+
         const userTagsWithoutOverrides = {};
-        Object.keys(this.userTags).filter(tag => !this.autoTags.hasOwnProperty(tag)).forEach(tag => {
-          userTagsWithoutOverrides[tag] = this.userTags[tag];
-        });
-        this.$allowedHTMLFormItem.val(`${this._generateSetting(userTagsWithoutOverrides)} ${this._generateSetting(this.autoTags)}`);
-      } else {
+        Object.keys(this.userTags)
+          .filter((tag) => !this.autoTags.hasOwnProperty(tag))
+          .forEach((tag) => {
+            userTagsWithoutOverrides[tag] = this.userTags[tag];
+          });
+
+        this.$allowedHTMLFormItem.val(
+          `${this._generateSetting(
+            userTagsWithoutOverrides,
+          )} ${this._generateSetting(this.autoTags)}`,
+        );
+      }
+      // Restore to original state.
+      else {
         this.$allowedHTMLFormItem.val(this._generateSetting(this.userTags));
       }
     },
 
+    /**
+     * Calculates which HTML tags the added text editor buttons need to work.
+     *
+     * The filter_html filter is only concerned with the required tags, not with
+     * any properties, nor with each feature's "allowed" tags.
+     *
+     * @param {Array} userAllowedTags
+     *   The list of user-defined allowed tags.
+     * @param {object} newFeatures
+     *   A list of {@link Drupal.EditorFeature} objects' rules, keyed by
+     *   their name.
+     *
+     * @return {Array}
+     *   A list of new allowed tags.
+     */
     _calculateAutoAllowedTags(userAllowedTags, newFeatures) {
       const editorRequiredTags = {};
-      Object.keys(newFeatures || {}).forEach(featureName => {
+
+      // Map the newly added Text Editor features to Drupal.FilterHtmlRule
+      // objects (to allow comparing userTags with autoTags).
+      Object.keys(newFeatures || {}).forEach((featureName) => {
         const feature = newFeatures[featureName];
         let featureRule;
         let filterRule;
@@ -93,71 +188,136 @@
 
         for (let f = 0; f < feature.length; f++) {
           featureRule = feature[f];
-
           for (let t = 0; t < featureRule.required.tags.length; t++) {
             tag = featureRule.required.tags[t];
-
             if (!editorRequiredTags.hasOwnProperty(tag)) {
               filterRule = new Drupal.FilterHTMLRule();
               filterRule.restrictedTags.tags = [tag];
-              filterRule.restrictedTags.allowed.attributes = featureRule.required.attributes.slice(0);
-              filterRule.restrictedTags.allowed.classes = featureRule.required.classes.slice(0);
+              // @todo Neither Drupal.FilterHtmlRule nor
+              //   Drupal.EditorFeatureHTMLRule allow for generic attribute
+              //   value restrictions, only for the "class" and "style"
+              //   attribute's values to be restricted. The filter_html filter
+              //   always disallows the "style" attribute, so we only need to
+              //   support "class" attribute value restrictions. Fix once
+              //   https://www.drupal.org/node/2567801 lands.
+              filterRule.restrictedTags.allowed.attributes =
+                featureRule.required.attributes.slice(0);
+              filterRule.restrictedTags.allowed.classes =
+                featureRule.required.classes.slice(0);
               editorRequiredTags[tag] = filterRule;
-            } else {
+            }
+            // The tag is already allowed, add any additionally allowed
+            // attributes.
+            else {
               filterRule = editorRequiredTags[tag];
-              filterRule.restrictedTags.allowed.attributes = [...filterRule.restrictedTags.allowed.attributes, ...featureRule.required.attributes];
-              filterRule.restrictedTags.allowed.classes = [...filterRule.restrictedTags.allowed.classes, ...featureRule.required.classes];
+              filterRule.restrictedTags.allowed.attributes = [
+                ...filterRule.restrictedTags.allowed.attributes,
+                ...featureRule.required.attributes,
+              ];
+              filterRule.restrictedTags.allowed.classes = [
+                ...filterRule.restrictedTags.allowed.classes,
+                ...featureRule.required.classes,
+              ];
             }
           }
         }
       });
+
+      // Now compare userAllowedTags with editorRequiredTags, and build
+      // autoAllowedTags, which contains:
+      // - any tags in editorRequiredTags but not in userAllowedTags (i.e. tags
+      //   that are additionally going to be allowed)
+      // - any tags in editorRequiredTags that already exists in userAllowedTags
+      //   but does not allow all attributes or attribute values
       const autoAllowedTags = {};
-      Object.keys(editorRequiredTags).forEach(tag => {
+      Object.keys(editorRequiredTags).forEach((tag) => {
+        // If userAllowedTags does not contain a rule for this editor-required
+        // tag, then add it to the list of automatically allowed tags.
         if (!userAllowedTags.hasOwnProperty(tag)) {
           autoAllowedTags[tag] = editorRequiredTags[tag];
-        } else {
-          const requiredAttributes = editorRequiredTags[tag].restrictedTags.allowed.attributes;
-          const allowedAttributes = userAllowedTags[tag].restrictedTags.allowed.attributes;
-          const needsAdditionalAttributes = requiredAttributes.length && difference(requiredAttributes, allowedAttributes).length;
-          const requiredClasses = editorRequiredTags[tag].restrictedTags.allowed.classes;
-          const allowedClasses = userAllowedTags[tag].restrictedTags.allowed.classes;
-          const needsAdditionalClasses = requiredClasses.length && difference(requiredClasses, allowedClasses).length;
-
+        }
+        // Otherwise, if userAllowedTags already allows this tag, then check if
+        // additional attributes and classes on this tag are required by the
+        // editor.
+        else {
+          const requiredAttributes =
+            editorRequiredTags[tag].restrictedTags.allowed.attributes;
+          const allowedAttributes =
+            userAllowedTags[tag].restrictedTags.allowed.attributes;
+          const needsAdditionalAttributes =
+            requiredAttributes.length &&
+            difference(requiredAttributes, allowedAttributes).length;
+          const requiredClasses =
+            editorRequiredTags[tag].restrictedTags.allowed.classes;
+          const allowedClasses =
+            userAllowedTags[tag].restrictedTags.allowed.classes;
+          const needsAdditionalClasses =
+            requiredClasses.length &&
+            difference(requiredClasses, allowedClasses).length;
           if (needsAdditionalAttributes || needsAdditionalClasses) {
             autoAllowedTags[tag] = userAllowedTags[tag].clone();
           }
-
           if (needsAdditionalAttributes) {
-            autoAllowedTags[tag].restrictedTags.allowed.attributes = [...allowedAttributes, ...requiredAttributes];
+            autoAllowedTags[tag].restrictedTags.allowed.attributes = [
+              ...allowedAttributes,
+              ...requiredAttributes,
+            ];
           }
-
           if (needsAdditionalClasses) {
-            autoAllowedTags[tag].restrictedTags.allowed.classes = [...allowedClasses, ...requiredClasses];
+            autoAllowedTags[tag].restrictedTags.allowed.classes = [
+              ...allowedClasses,
+              ...requiredClasses,
+            ];
           }
         }
       });
+
       return autoAllowedTags;
     },
 
+    /**
+     * Parses the value of this.$allowedHTMLFormItem.
+     *
+     * @param {string} setting
+     *   The string representation of the setting. For example:
+     *     <p class="callout"> <br> <a href hreflang>
+     *
+     * @return {Object.<string, Drupal.FilterHTMLRule>}
+     *   The corresponding text filter HTML rule objects, one per tag, keyed by
+     *   tag name.
+     */
     _parseSetting(setting) {
       let tag;
       let rule;
       let attributes;
       let attribute;
+
       const allowedTags = setting.match(/(<[^>]+>)/g);
       const rules = {};
-
       for (let t = 0; t < allowedTags.length; t++) {
+        // Create a jQuery object, making it possible to easily retrieve the
+        // tag name of the allowed tag, regardless of what attributes are set or
+        // what its required parent elements are.
         const $tagObject = $(allowedTags[t]);
+
+        // Parse the tag name from the jQuery object.
         tag = $tagObject.prop('tagName').toLowerCase();
+
+        // Build the Drupal.FilterHtmlRule object.
         rule = new Drupal.FilterHTMLRule();
+        // We create one rule per allowed tag, so always one tag.
         rule.restrictedTags.tags = [tag];
-        attributes = $tagObject.prop('attributes');
 
+        // Add the attribute restrictions.
+        attributes = $tagObject.prop('attributes');
         for (let i = 0; i < attributes.length; i++) {
           attribute = attributes.item(i);
           const attributeName = attribute.nodeName;
-
+          // @todo Drupal.FilterHtmlRule does not allow for generic attribute
+          //   value restrictions, only for the "class" and "style" attribute's
+          //   values. The filter_html filter always disallows the "style"
+          //   attribute, so we only need to support "class" attribute value
+          //   restrictions. Fix once https://www.drupal.org/node/2567801 lands.
           if (attributeName === 'class') {
             const attributeValue = attribute.textContent;
             rule.restrictedTags.allowed.classes = attributeValue.split(' ');
@@ -168,10 +328,18 @@
 
         rules[tag] = rule;
       }
-
       return rules;
     },
 
+    /**
+     * Generates the value of this.$allowedHTMLFormItem.
+     *
+     * @param {Object.<string, Drupal.FilterHTMLRule>} tags
+     *   The parsed representation of the setting.
+     *
+     * @return {Array}
+     *   The string representation of the setting. e.g. "<p> <br> <a>"
+     */
     _generateSetting(tags) {
       return Object.keys(tags).reduce((setting, tag) => {
         const rule = tags[tag];
@@ -181,32 +349,45 @@
         }
 
         setting += `<${tag}`;
-
         if (rule.restrictedTags.allowed.attributes.length) {
           setting += ` ${rule.restrictedTags.allowed.attributes.join(' ')}`;
         }
-
+        // @todo Drupal.FilterHtmlRule does not allow for generic attribute
+        //   value restrictions, only for the "class" and "style" attribute's
+        //   values. The filter_html filter always disallows the "style"
+        //   attribute, so we only need to support "class" attribute value
+        //   restrictions. Fix once https://www.drupal.org/node/2567801 lands.
         if (rule.restrictedTags.allowed.classes.length) {
-          setting += ` class="${rule.restrictedTags.allowed.classes.join(' ')}"`;
+          setting += ` class="${rule.restrictedTags.allowed.classes.join(
+            ' ',
+          )}"`;
         }
 
         setting += '>';
         return setting;
       }, '');
-    }
-
+    },
   };
 
+  /**
+   * Theme function for the filter_html update message.
+   *
+   * @param {Array} tags
+   *   An array of the new tags that are to be allowed.
+   *
+   * @return {string}
+   *   The corresponding HTML.
+   */
   Drupal.theme.filterFilterHTMLUpdateMessage = function (tags) {
     let html = '';
-
-    const tagList = Drupal.behaviors.filterFilterHtmlUpdating._generateSetting(tags);
-
+    const tagList =
+      Drupal.behaviors.filterFilterHtmlUpdating._generateSetting(tags);
     html += '<p class="editor-update-message">';
-    html += Drupal.t('Based on the text editor configuration, these tags have automatically been added: <strong>@tag-list</strong>.', {
-      '@tag-list': tagList
-    });
+    html += Drupal.t(
+      'Based on the text editor configuration, these tags have automatically been added: <strong>@tag-list</strong>.',
+      { '@tag-list': tagList },
+    );
     html += '</p>';
     return html;
   };
-})(jQuery, Drupal, document);
\ No newline at end of file
+})(jQuery, Drupal, document);
diff --git a/core/modules/filter/filter.js b/core/modules/filter/filter.js
index 529f59ff60f8..733dc93f3c9c 100644
--- a/core/modules/filter/filter.js
+++ b/core/modules/filter/filter.js
@@ -1,23 +1,39 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches behavior for the Filter module.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Displays the guidelines of the selected text format automatically.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior for updating filter guidelines.
+   */
   Drupal.behaviors.filterGuidelines = {
     attach(context) {
       function updateFilterGuidelines(event) {
         const $this = $(event.target);
-        const {
-          value
-        } = event.target;
-        $this.closest('.js-filter-wrapper').find('[data-drupal-format-id]').hide().filter(`[data-drupal-format-id="${value}"]`).show();
+        const { value } = event.target;
+        $this
+          .closest('.js-filter-wrapper')
+          .find('[data-drupal-format-id]')
+          .hide()
+          .filter(`[data-drupal-format-id="${value}"]`)
+          .show();
       }
 
-      $(once('filter-guidelines', '.js-filter-guidelines', context)).find(':header').hide().closest('.js-filter-wrapper').find('select.js-filter-list').on('change.filterGuidelines', updateFilterGuidelines).trigger('change.filterGuidelines');
-    }
-
+      $(once('filter-guidelines', '.js-filter-guidelines', context))
+        .find(':header')
+        .hide()
+        .closest('.js-filter-wrapper')
+        .find('select.js-filter-list')
+        .on('change.filterGuidelines', updateFilterGuidelines)
+        // Need to trigger the namespaced event to avoid triggering formUpdated
+        // when initializing the select.
+        .trigger('change.filterGuidelines');
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index d068ae03acda..4148f5750691 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -362,7 +362,7 @@ function template_preprocess_filter_guidelines(&$variables) {
     '#tips' => _filter_tips($format->id(), FALSE),
   ];
 
-  // Add format id for filter.es6.js.
+  // Add format id for filter.js.
   $variables['attributes']['data-drupal-format-id'] = $format->id();
 }
 
diff --git a/core/modules/filter/src/Plugin/Filter/FilterCaption.php b/core/modules/filter/src/Plugin/Filter/FilterCaption.php
index 817f73b7afb0..7847dbdf7e40 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterCaption.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterCaption.php
@@ -95,7 +95,7 @@ public function process($text, $langcode) {
         // content editor from adding a new caption. To allow for this we treat
         // a raw caption value of ' ' as valid and adding the wrapping figure
         // element.
-        // @see core/modules/media/js/plugins/drupalmedia/plugin.es6.js
+        // @see core/modules/media/js/plugins/drupalmedia/plugin.js
         if (mb_strlen($caption) === 0 && $raw_caption !== ' ') {
           continue;
         }
diff --git a/core/modules/history/js/history.es6.js b/core/modules/history/js/history.es6.js
deleted file mode 100644
index 86af5edd9b67..000000000000
--- a/core/modules/history/js/history.es6.js
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
- * @file
- * JavaScript API for the History module, with client-side caching.
- *
- * May only be loaded for authenticated users, with the History module enabled.
- */
-
-(function ($, Drupal, drupalSettings, storage) {
-  const currentUserID = parseInt(drupalSettings.user.uid, 10);
-
-  // Any comment that is older than 30 days is automatically considered read,
-  // so for these we don't need to perform a request at all!
-  const secondsIn30Days = 2592000;
-  const thirtyDaysAgo =
-    Math.round(new Date().getTime() / 1000) - secondsIn30Days;
-
-  // Use the data embedded in the page, if available.
-  let embeddedLastReadTimestamps = false;
-  if (drupalSettings.history && drupalSettings.history.lastReadTimestamps) {
-    embeddedLastReadTimestamps = drupalSettings.history.lastReadTimestamps;
-  }
-
-  /**
-   * @namespace
-   */
-  Drupal.history = {
-    /**
-     * Fetch "last read" timestamps for the given nodes.
-     *
-     * @param {Array} nodeIDs
-     *   An array of node IDs.
-     * @param {function} callback
-     *   A callback that is called after the requested timestamps were fetched.
-     */
-    fetchTimestamps(nodeIDs, callback) {
-      // Use the data embedded in the page, if available.
-      if (embeddedLastReadTimestamps) {
-        callback();
-        return;
-      }
-
-      $.ajax({
-        url: Drupal.url('history/get_node_read_timestamps'),
-        type: 'POST',
-        data: { 'node_ids[]': nodeIDs },
-        dataType: 'json',
-        success(results) {
-          Object.keys(results || {}).forEach((nodeID) => {
-            storage.setItem(
-              `Drupal.history.${currentUserID}.${nodeID}`,
-              results[nodeID],
-            );
-          });
-          callback();
-        },
-      });
-    },
-
-    /**
-     * Get the last read timestamp for the given node.
-     *
-     * @param {number|string} nodeID
-     *   A node ID.
-     *
-     * @return {number}
-     *   A UNIX timestamp.
-     */
-    getLastRead(nodeID) {
-      // Use the data embedded in the page, if available.
-      if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
-        return parseInt(embeddedLastReadTimestamps[nodeID], 10);
-      }
-      return parseInt(
-        storage.getItem(`Drupal.history.${currentUserID}.${nodeID}`) || 0,
-        10,
-      );
-    },
-
-    /**
-     * Marks a node as read, store the last read timestamp client-side.
-     *
-     * @param {number|string} nodeID
-     *   A node ID.
-     */
-    markAsRead(nodeID) {
-      $.ajax({
-        url: Drupal.url(`history/${nodeID}/read`),
-        type: 'POST',
-        dataType: 'json',
-        success(timestamp) {
-          // If the data is embedded in the page, don't store on the client
-          // side.
-          if (
-            embeddedLastReadTimestamps &&
-            embeddedLastReadTimestamps[nodeID]
-          ) {
-            return;
-          }
-
-          storage.setItem(
-            `Drupal.history.${currentUserID}.${nodeID}`,
-            timestamp,
-          );
-        },
-      });
-    },
-
-    /**
-     * Determines whether a server check is necessary.
-     *
-     * Any content that is >30 days old never gets a "new" or "updated"
-     * indicator. Any content that was published before the oldest known reading
-     * also never gets a "new" or "updated" indicator, because it must've been
-     * read already.
-     *
-     * @param {number|string} nodeID
-     *   A node ID.
-     * @param {number} contentTimestamp
-     *   The time at which some content (e.g. a comment) was published.
-     *
-     * @return {bool}
-     *   Whether a server check is necessary for the given node and its
-     *   timestamp.
-     */
-    needsServerCheck(nodeID, contentTimestamp) {
-      // First check if the content is older than 30 days, then we can bail
-      // early.
-      if (contentTimestamp < thirtyDaysAgo) {
-        return false;
-      }
-
-      // Use the data embedded in the page, if available.
-      if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
-        return (
-          contentTimestamp > parseInt(embeddedLastReadTimestamps[nodeID], 10)
-        );
-      }
-
-      const minLastReadTimestamp = parseInt(
-        storage.getItem(`Drupal.history.${currentUserID}.${nodeID}`) || 0,
-        10,
-      );
-      return contentTimestamp > minLastReadTimestamp;
-    },
-  };
-})(jQuery, Drupal, drupalSettings, window.localStorage);
diff --git a/core/modules/history/js/history.js b/core/modules/history/js/history.js
index 4b2ef8e21ecc..86af5edd9b67 100644
--- a/core/modules/history/js/history.js
+++ b/core/modules/history/js/history.js
@@ -1,22 +1,39 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * JavaScript API for the History module, with client-side caching.
+ *
+ * May only be loaded for authenticated users, with the History module enabled.
+ */
 
 (function ($, Drupal, drupalSettings, storage) {
   const currentUserID = parseInt(drupalSettings.user.uid, 10);
+
+  // Any comment that is older than 30 days is automatically considered read,
+  // so for these we don't need to perform a request at all!
   const secondsIn30Days = 2592000;
-  const thirtyDaysAgo = Math.round(new Date().getTime() / 1000) - secondsIn30Days;
-  let embeddedLastReadTimestamps = false;
+  const thirtyDaysAgo =
+    Math.round(new Date().getTime() / 1000) - secondsIn30Days;
 
+  // Use the data embedded in the page, if available.
+  let embeddedLastReadTimestamps = false;
   if (drupalSettings.history && drupalSettings.history.lastReadTimestamps) {
     embeddedLastReadTimestamps = drupalSettings.history.lastReadTimestamps;
   }
 
+  /**
+   * @namespace
+   */
   Drupal.history = {
+    /**
+     * Fetch "last read" timestamps for the given nodes.
+     *
+     * @param {Array} nodeIDs
+     *   An array of node IDs.
+     * @param {function} callback
+     *   A callback that is called after the requested timestamps were fetched.
+     */
     fetchTimestamps(nodeIDs, callback) {
+      // Use the data embedded in the page, if available.
       if (embeddedLastReadTimestamps) {
         callback();
         return;
@@ -25,58 +42,105 @@
       $.ajax({
         url: Drupal.url('history/get_node_read_timestamps'),
         type: 'POST',
-        data: {
-          'node_ids[]': nodeIDs
-        },
+        data: { 'node_ids[]': nodeIDs },
         dataType: 'json',
-
         success(results) {
-          Object.keys(results || {}).forEach(nodeID => {
-            storage.setItem(`Drupal.history.${currentUserID}.${nodeID}`, results[nodeID]);
+          Object.keys(results || {}).forEach((nodeID) => {
+            storage.setItem(
+              `Drupal.history.${currentUserID}.${nodeID}`,
+              results[nodeID],
+            );
           });
           callback();
-        }
-
+        },
       });
     },
 
+    /**
+     * Get the last read timestamp for the given node.
+     *
+     * @param {number|string} nodeID
+     *   A node ID.
+     *
+     * @return {number}
+     *   A UNIX timestamp.
+     */
     getLastRead(nodeID) {
+      // Use the data embedded in the page, if available.
       if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
         return parseInt(embeddedLastReadTimestamps[nodeID], 10);
       }
-
-      return parseInt(storage.getItem(`Drupal.history.${currentUserID}.${nodeID}`) || 0, 10);
+      return parseInt(
+        storage.getItem(`Drupal.history.${currentUserID}.${nodeID}`) || 0,
+        10,
+      );
     },
 
+    /**
+     * Marks a node as read, store the last read timestamp client-side.
+     *
+     * @param {number|string} nodeID
+     *   A node ID.
+     */
     markAsRead(nodeID) {
       $.ajax({
         url: Drupal.url(`history/${nodeID}/read`),
         type: 'POST',
         dataType: 'json',
-
         success(timestamp) {
-          if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
+          // If the data is embedded in the page, don't store on the client
+          // side.
+          if (
+            embeddedLastReadTimestamps &&
+            embeddedLastReadTimestamps[nodeID]
+          ) {
             return;
           }
 
-          storage.setItem(`Drupal.history.${currentUserID}.${nodeID}`, timestamp);
-        }
-
+          storage.setItem(
+            `Drupal.history.${currentUserID}.${nodeID}`,
+            timestamp,
+          );
+        },
       });
     },
 
+    /**
+     * Determines whether a server check is necessary.
+     *
+     * Any content that is >30 days old never gets a "new" or "updated"
+     * indicator. Any content that was published before the oldest known reading
+     * also never gets a "new" or "updated" indicator, because it must've been
+     * read already.
+     *
+     * @param {number|string} nodeID
+     *   A node ID.
+     * @param {number} contentTimestamp
+     *   The time at which some content (e.g. a comment) was published.
+     *
+     * @return {bool}
+     *   Whether a server check is necessary for the given node and its
+     *   timestamp.
+     */
     needsServerCheck(nodeID, contentTimestamp) {
+      // First check if the content is older than 30 days, then we can bail
+      // early.
       if (contentTimestamp < thirtyDaysAgo) {
         return false;
       }
 
+      // Use the data embedded in the page, if available.
       if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
-        return contentTimestamp > parseInt(embeddedLastReadTimestamps[nodeID], 10);
+        return (
+          contentTimestamp > parseInt(embeddedLastReadTimestamps[nodeID], 10)
+        );
       }
 
-      const minLastReadTimestamp = parseInt(storage.getItem(`Drupal.history.${currentUserID}.${nodeID}`) || 0, 10);
+      const minLastReadTimestamp = parseInt(
+        storage.getItem(`Drupal.history.${currentUserID}.${nodeID}`) || 0,
+        10,
+      );
       return contentTimestamp > minLastReadTimestamp;
-    }
-
+    },
   };
-})(jQuery, Drupal, drupalSettings, window.localStorage);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings, window.localStorage);
diff --git a/core/modules/history/js/mark-as-read.es6.js b/core/modules/history/js/mark-as-read.es6.js
deleted file mode 100644
index f51b84f4eaa1..000000000000
--- a/core/modules/history/js/mark-as-read.es6.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * @file
- * Marks the nodes listed in drupalSettings.history.nodesToMarkAsRead as read.
- *
- * Uses the History module JavaScript API.
- *
- * @see Drupal.history
- */
-
-(function (window, Drupal, drupalSettings) {
-  // When the window's "load" event is triggered, mark all enumerated nodes as
-  // read. This still allows for Drupal behaviors (which are triggered on the
-  // "DOMContentReady" event) to add "new" and "updated" indicators.
-  window.addEventListener('load', () => {
-    if (drupalSettings.history && drupalSettings.history.nodesToMarkAsRead) {
-      Object.keys(drupalSettings.history.nodesToMarkAsRead).forEach(
-        Drupal.history.markAsRead,
-      );
-    }
-  });
-})(window, Drupal, drupalSettings);
diff --git a/core/modules/history/js/mark-as-read.js b/core/modules/history/js/mark-as-read.js
index e42d7c4dddac..f51b84f4eaa1 100644
--- a/core/modules/history/js/mark-as-read.js
+++ b/core/modules/history/js/mark-as-read.js
@@ -1,14 +1,21 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Marks the nodes listed in drupalSettings.history.nodesToMarkAsRead as read.
+ *
+ * Uses the History module JavaScript API.
+ *
+ * @see Drupal.history
+ */
 
 (function (window, Drupal, drupalSettings) {
+  // When the window's "load" event is triggered, mark all enumerated nodes as
+  // read. This still allows for Drupal behaviors (which are triggered on the
+  // "DOMContentReady" event) to add "new" and "updated" indicators.
   window.addEventListener('load', () => {
     if (drupalSettings.history && drupalSettings.history.nodesToMarkAsRead) {
-      Object.keys(drupalSettings.history.nodesToMarkAsRead).forEach(Drupal.history.markAsRead);
+      Object.keys(drupalSettings.history.nodesToMarkAsRead).forEach(
+        Drupal.history.markAsRead,
+      );
     }
   });
-})(window, Drupal, drupalSettings);
\ No newline at end of file
+})(window, Drupal, drupalSettings);
diff --git a/core/modules/language/language.admin.es6.js b/core/modules/language/language.admin.es6.js
deleted file mode 100644
index 62724214afae..000000000000
--- a/core/modules/language/language.admin.es6.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * @file
- * Language admin behavior.
- */
-
-(function ($, Drupal) {
-  /**
-   * Makes language negotiation inherit user interface negotiation.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attach behavior to language negotiation admin user interface.
-   */
-  Drupal.behaviors.negotiationLanguage = {
-    attach() {
-      const $configForm = $('#language-negotiation-configure-form');
-      const inputSelector = 'input[name$="[configurable]"]';
-      // Given a customization checkbox derive the language type being changed.
-      function toggleTable(checkbox) {
-        const $checkbox = $(checkbox);
-        // Get the language detection type such as Interface text language
-        // detection or Content language detection.
-        $checkbox
-          .closest('.table-language-group')
-          .find('table, .tabledrag-toggle-weight')
-          .toggle($checkbox.prop('checked'));
-      }
-
-      // Bind hide/show and rearrange customization checkboxes.
-      $(once('negotiation-language-admin-bind', $configForm)).on(
-        'change',
-        inputSelector,
-        (event) => {
-          toggleTable(event.target);
-        },
-      );
-      // Initially, hide language detection types that are not customized.
-      $configForm
-        .find(`${inputSelector}:not(:checked)`)
-        .each((index, element) => {
-          toggleTable(element);
-        });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/language/language.admin.js b/core/modules/language/language.admin.js
index 373e7193310a..62724214afae 100644
--- a/core/modules/language/language.admin.js
+++ b/core/modules/language/language.admin.js
@@ -1,28 +1,46 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Language admin behavior.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Makes language negotiation inherit user interface negotiation.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach behavior to language negotiation admin user interface.
+   */
   Drupal.behaviors.negotiationLanguage = {
     attach() {
       const $configForm = $('#language-negotiation-configure-form');
       const inputSelector = 'input[name$="[configurable]"]';
-
+      // Given a customization checkbox derive the language type being changed.
       function toggleTable(checkbox) {
         const $checkbox = $(checkbox);
-        $checkbox.closest('.table-language-group').find('table, .tabledrag-toggle-weight').toggle($checkbox.prop('checked'));
+        // Get the language detection type such as Interface text language
+        // detection or Content language detection.
+        $checkbox
+          .closest('.table-language-group')
+          .find('table, .tabledrag-toggle-weight')
+          .toggle($checkbox.prop('checked'));
       }
 
-      $(once('negotiation-language-admin-bind', $configForm)).on('change', inputSelector, event => {
-        toggleTable(event.target);
-      });
-      $configForm.find(`${inputSelector}:not(:checked)`).each((index, element) => {
-        toggleTable(element);
-      });
-    }
-
+      // Bind hide/show and rearrange customization checkboxes.
+      $(once('negotiation-language-admin-bind', $configForm)).on(
+        'change',
+        inputSelector,
+        (event) => {
+          toggleTable(event.target);
+        },
+      );
+      // Initially, hide language detection types that are not customized.
+      $configForm
+        .find(`${inputSelector}:not(:checked)`)
+        .each((index, element) => {
+          toggleTable(element);
+        });
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/layout_builder/js/layout-builder.es6.js b/core/modules/layout_builder/js/layout-builder.es6.js
deleted file mode 100644
index 5a9112717d76..000000000000
--- a/core/modules/layout_builder/js/layout-builder.es6.js
+++ /dev/null
@@ -1,446 +0,0 @@
-/**
- * @file
- * Attaches the behaviors for the Layout Builder module.
- */
-
-(($, Drupal, Sortable) => {
-  const { ajax, behaviors, debounce, announce, formatPlural } = Drupal;
-
-  /*
-   * Boolean that tracks if block listing is currently being filtered. Declared
-   * outside of behaviors so value is retained on rebuild.
-   */
-  let layoutBuilderBlocksFiltered = false;
-
-  /**
-   * Provides the ability to filter the block listing in "Add block" dialog.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attach block filtering behavior to "Add block" dialog.
-   */
-  behaviors.layoutBuilderBlockFilter = {
-    attach(context) {
-      const $categories = $('.js-layout-builder-categories', context);
-      const $filterLinks = $categories.find('.js-layout-builder-block-link');
-
-      /**
-       * Filters the block list.
-       *
-       * @param {jQuery.Event} e
-       *   The jQuery event for the keyup event that triggered the filter.
-       */
-      const filterBlockList = (e) => {
-        const query = e.target.value.toLowerCase();
-
-        /**
-         * Shows or hides the block entry based on the query.
-         *
-         * @param {number} index
-         *   The index in the loop, as provided by `jQuery.each`
-         * @param {HTMLElement} link
-         *   The link to add the block.
-         */
-        const toggleBlockEntry = (index, link) => {
-          const textMatch =
-            link.textContent.toLowerCase().indexOf(query) !== -1;
-          $(link).toggle(textMatch);
-        };
-
-        // Filter if the length of the query is at least 2 characters.
-        if (query.length >= 2) {
-          // Attribute to note which categories are closed before opening all.
-          $categories
-            .find('.js-layout-builder-category:not([open])')
-            .attr('remember-closed', '');
-
-          // Open all categories so every block is available to filtering.
-          $categories.find('.js-layout-builder-category').attr('open', '');
-          // Toggle visibility of links based on query.
-          $filterLinks.each(toggleBlockEntry);
-
-          // Only display categories containing visible links.
-          $categories
-            .find(
-              '.js-layout-builder-category:not(:has(.js-layout-builder-block-link:visible))',
-            )
-            .hide();
-
-          announce(
-            formatPlural(
-              $categories.find('.js-layout-builder-block-link:visible').length,
-              '1 block is available in the modified list.',
-              '@count blocks are available in the modified list.',
-            ),
-          );
-          layoutBuilderBlocksFiltered = true;
-        } else if (layoutBuilderBlocksFiltered) {
-          layoutBuilderBlocksFiltered = false;
-          // Remove "open" attr from categories that were closed pre-filtering.
-          $categories
-            .find('.js-layout-builder-category[remember-closed]')
-            .removeAttr('open')
-            .removeAttr('remember-closed');
-          $categories.find('.js-layout-builder-category').show();
-          $filterLinks.show();
-          announce(Drupal.t('All available blocks are listed.'));
-        }
-      };
-
-      $(
-        once('block-filter-text', 'input.js-layout-builder-filter', context),
-      ).on('keyup', debounce(filterBlockList, 200));
-    },
-  };
-
-  /**
-   * Callback used in {@link Drupal.behaviors.layoutBuilderBlockDrag}.
-   *
-   * @param {HTMLElement} item
-   *   The HTML element representing the repositioned block.
-   * @param {HTMLElement} from
-   *   The HTML element representing the previous parent of item
-   * @param {HTMLElement} to
-   *   The HTML element representing the current parent of item
-   *
-   * @internal This method is a callback for layoutBuilderBlockDrag and is used
-   *  in FunctionalJavascript tests. It may be renamed if the test changes.
-   *  @see https://www.drupal.org/node/3084730
-   */
-  Drupal.layoutBuilderBlockUpdate = function (item, from, to) {
-    const $item = $(item);
-    const $from = $(from);
-
-    // Check if the region from the event and region for the item match.
-    const itemRegion = $item.closest('.js-layout-builder-region');
-    if (to === itemRegion[0]) {
-      // Find the destination delta.
-      const deltaTo = $item.closest('[data-layout-delta]').data('layout-delta');
-      // If the block didn't leave the original delta use the destination.
-      const deltaFrom = $from
-        ? $from.closest('[data-layout-delta]').data('layout-delta')
-        : deltaTo;
-      ajax({
-        url: [
-          $item.closest('[data-layout-update-url]').data('layout-update-url'),
-          deltaFrom,
-          deltaTo,
-          itemRegion.data('region'),
-          $item.data('layout-block-uuid'),
-          $item.prev('[data-layout-block-uuid]').data('layout-block-uuid'),
-        ]
-          .filter((element) => element !== undefined)
-          .join('/'),
-      }).execute();
-    }
-  };
-
-  /**
-   * Provides the ability to drag blocks to new positions in the layout.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attach block drag behavior to the Layout Builder UI.
-   */
-  behaviors.layoutBuilderBlockDrag = {
-    attach(context) {
-      const regionSelector = '.js-layout-builder-region';
-      Array.prototype.forEach.call(
-        context.querySelectorAll(regionSelector),
-        (region) => {
-          Sortable.create(region, {
-            draggable: '.js-layout-builder-block',
-            ghostClass: 'ui-state-drop',
-            group: 'builder-region',
-            onEnd: (event) =>
-              Drupal.layoutBuilderBlockUpdate(event.item, event.from, event.to),
-          });
-        },
-      );
-    },
-  };
-
-  /**
-   * Disables interactive elements in previewed blocks.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attach disabling interactive elements behavior to the Layout Builder UI.
-   */
-  behaviors.layoutBuilderDisableInteractiveElements = {
-    attach() {
-      // Disable interactive elements inside preview blocks.
-      const $blocks = $('#layout-builder [data-layout-block-uuid]');
-      $blocks.find('input, textarea, select').prop('disabled', true);
-      $blocks
-        .find('a')
-        // Don't disable contextual links.
-        // @see \Drupal\contextual\Element\ContextualLinksPlaceholder
-        .not(
-          (index, element) =>
-            $(element).closest('[data-contextual-id]').length > 0,
-        )
-        .on('click mouseup touchstart', (e) => {
-          e.preventDefault();
-          e.stopPropagation();
-        });
-
-      /*
-       * In preview blocks, remove from the tabbing order all input elements
-       * and elements specifically assigned a tab index, other than those
-       * related to contextual links.
-       */
-      $blocks
-        .find(
-          'button, [href], input, select, textarea, iframe, [tabindex]:not([tabindex="-1"]):not(.tabbable)',
-        )
-        .not(
-          (index, element) =>
-            $(element).closest('[data-contextual-id]').length > 0,
-        )
-        .attr('tabindex', -1);
-    },
-  };
-
-  // After a dialog opens, highlight element that the dialog is acting on.
-  $(window).on('dialog:aftercreate', (event, dialog, $element) => {
-    if (Drupal.offCanvas.isOffCanvas($element)) {
-      // Start by removing any existing highlighted elements.
-      $('.is-layout-builder-highlighted').removeClass(
-        'is-layout-builder-highlighted',
-      );
-
-      /*
-       * Every dialog has a single 'data-layout-builder-target-highlight-id'
-       * attribute. Every dialog-opening element has a unique
-       * 'data-layout-builder-highlight-id' attribute.
-       *
-       * When the value of data-layout-builder-target-highlight-id matches
-       * an element's value of data-layout-builder-highlight-id, the class
-       * 'is-layout-builder-highlighted' is added to element.
-       */
-      const id = $element
-        .find('[data-layout-builder-target-highlight-id]')
-        .attr('data-layout-builder-target-highlight-id');
-      if (id) {
-        $(`[data-layout-builder-highlight-id="${id}"]`).addClass(
-          'is-layout-builder-highlighted',
-        );
-      }
-
-      // Remove wrapper class added by move block form.
-      $('#layout-builder').removeClass('layout-builder--move-blocks-active');
-
-      /**
-       * If dialog has a data-add-layout-builder-wrapper attribute, get the
-       * value and add it as a class to the Layout Builder UI wrapper.
-       *
-       * Currently, only the move block form uses
-       * data-add-layout-builder-wrapper, but any dialog can use this attribute
-       * to add a class to the Layout Builder UI while opened.
-       */
-      const layoutBuilderWrapperValue = $element
-        .find('[data-add-layout-builder-wrapper]')
-        .attr('data-add-layout-builder-wrapper');
-      if (layoutBuilderWrapperValue) {
-        $('#layout-builder').addClass(layoutBuilderWrapperValue);
-      }
-    }
-  });
-
-  /*
-   * When a Layout Builder dialog is triggered, the main canvas resizes. After
-   * the resize transition is complete, see if the target element is still
-   * visible in viewport. If not, scroll page so the target element is again
-   * visible.
-   *
-   * @todo Replace this custom solution when a general solution is made
-   *   available with https://www.drupal.org/node/3033410
-   */
-  if (document.querySelector('[data-off-canvas-main-canvas]')) {
-    const mainCanvas = document.querySelector('[data-off-canvas-main-canvas]');
-
-    // This event fires when canvas CSS transitions are complete.
-    mainCanvas.addEventListener('transitionend', () => {
-      const $target = $('.is-layout-builder-highlighted');
-
-      if ($target.length > 0) {
-        // These four variables are used to determine if the element is in the
-        // viewport.
-        const targetTop = $target.offset().top;
-        const targetBottom = targetTop + $target.outerHeight();
-        const viewportTop = $(window).scrollTop();
-        const viewportBottom = viewportTop + $(window).height();
-
-        // If the element is not in the viewport, scroll it into view.
-        if (targetBottom < viewportTop || targetTop > viewportBottom) {
-          const viewportMiddle = (viewportBottom + viewportTop) / 2;
-          const scrollAmount = targetTop - viewportMiddle;
-
-          // Check whether the browser supports scrollBy(options). If it does
-          // not, use scrollBy(x-coord, y-coord) instead.
-          if ('scrollBehavior' in document.documentElement.style) {
-            window.scrollBy({
-              top: scrollAmount,
-              left: 0,
-              behavior: 'smooth',
-            });
-          } else {
-            window.scrollBy(0, scrollAmount);
-          }
-        }
-      }
-    });
-  }
-
-  $(window).on('dialog:afterclose', (event, dialog, $element) => {
-    if (Drupal.offCanvas.isOffCanvas($element)) {
-      // Remove the highlight from all elements.
-      $('.is-layout-builder-highlighted').removeClass(
-        'is-layout-builder-highlighted',
-      );
-
-      // Remove wrapper class added by move block form.
-      $('#layout-builder').removeClass('layout-builder--move-blocks-active');
-    }
-  });
-
-  /**
-   * Toggles content preview in the Layout Builder UI.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attach content preview toggle to the Layout Builder UI.
-   */
-  behaviors.layoutBuilderToggleContentPreview = {
-    attach(context) {
-      const $layoutBuilder = $('#layout-builder');
-
-      // The content preview toggle.
-      const $layoutBuilderContentPreview = $('#layout-builder-content-preview');
-
-      // data-content-preview-id specifies the layout being edited.
-      const contentPreviewId =
-        $layoutBuilderContentPreview.data('content-preview-id');
-
-      /**
-       * Tracks if content preview is enabled for this layout. Defaults to true
-       * if no value has previously been set.
-       */
-      const isContentPreview =
-        JSON.parse(localStorage.getItem(contentPreviewId)) !== false;
-
-      /**
-       * Disables content preview in the Layout Builder UI.
-       *
-       * Disabling content preview hides block content. It is replaced with the
-       * value of the block's data-layout-content-preview-placeholder-label
-       * attribute.
-       *
-       * @todo Revisit in https://www.drupal.org/node/3043215, it may be
-       *   possible to remove all but the first line of this function.
-       */
-      const disableContentPreview = () => {
-        $layoutBuilder.addClass('layout-builder--content-preview-disabled');
-
-        /**
-         * Iterate over all Layout Builder blocks to hide their content and add
-         * placeholder labels.
-         */
-        $('[data-layout-content-preview-placeholder-label]', context).each(
-          (i, element) => {
-            const $element = $(element);
-
-            // Hide everything in block that isn't contextual link related.
-            $element.children(':not([data-contextual-id])').hide(0);
-
-            const contentPreviewPlaceholderText = $element.attr(
-              'data-layout-content-preview-placeholder-label',
-            );
-
-            const contentPreviewPlaceholderLabel = Drupal.theme(
-              'layoutBuilderPrependContentPreviewPlaceholderLabel',
-              contentPreviewPlaceholderText,
-            );
-            $element.prepend(contentPreviewPlaceholderLabel);
-          },
-        );
-      };
-
-      /**
-       * Enables content preview in the Layout Builder UI.
-       *
-       * When content preview is enabled, the Layout Builder UI returns to its
-       * default experience. This is accomplished by removing placeholder
-       * labels and un-hiding block content.
-       *
-       * @todo Revisit in https://www.drupal.org/node/3043215, it may be
-       *   possible to remove all but the first line of this function.
-       */
-      const enableContentPreview = () => {
-        $layoutBuilder.removeClass('layout-builder--content-preview-disabled');
-
-        // Remove all placeholder labels.
-        $('.js-layout-builder-content-preview-placeholder-label').remove();
-
-        // Iterate over all blocks.
-        $('[data-layout-content-preview-placeholder-label]').each(
-          (i, element) => {
-            $(element).children().show();
-          },
-        );
-      };
-
-      $('#layout-builder-content-preview', context).on('change', (event) => {
-        const isChecked = $(event.currentTarget).is(':checked');
-
-        localStorage.setItem(contentPreviewId, JSON.stringify(isChecked));
-
-        if (isChecked) {
-          enableContentPreview();
-          announce(
-            Drupal.t('Block previews are visible. Block labels are hidden.'),
-          );
-        } else {
-          disableContentPreview();
-          announce(
-            Drupal.t('Block previews are hidden. Block labels are visible.'),
-          );
-        }
-      });
-
-      /**
-       * On rebuild, see if content preview has been set to disabled. If yes,
-       * disable content preview in the Layout Builder UI.
-       */
-      if (!isContentPreview) {
-        $layoutBuilderContentPreview.attr('checked', false);
-        disableContentPreview();
-      }
-    },
-  };
-
-  /**
-   * Creates content preview placeholder label markup.
-   *
-   * @param {string} contentPreviewPlaceholderText
-   *   The text content of the placeholder label
-   *
-   * @return {string}
-   *   A HTML string of the placeholder label.
-   */
-  Drupal.theme.layoutBuilderPrependContentPreviewPlaceholderLabel = (
-    contentPreviewPlaceholderText,
-  ) => {
-    const contentPreviewPlaceholderLabel = document.createElement('div');
-    contentPreviewPlaceholderLabel.className =
-      'layout-builder-block__content-preview-placeholder-label js-layout-builder-content-preview-placeholder-label';
-    contentPreviewPlaceholderLabel.innerHTML = contentPreviewPlaceholderText;
-
-    return `<div class="layout-builder-block__content-preview-placeholder-label js-layout-builder-content-preview-placeholder-label">${contentPreviewPlaceholderText}</div>`;
-  };
-})(jQuery, Drupal, Sortable);
diff --git a/core/modules/layout_builder/js/layout-builder.js b/core/modules/layout_builder/js/layout-builder.js
index 4a8af0d29602..5a9112717d76 100644
--- a/core/modules/layout_builder/js/layout-builder.js
+++ b/core/modules/layout_builder/js/layout-builder.js
@@ -1,131 +1,292 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches the behaviors for the Layout Builder module.
+ */
 
 (($, Drupal, Sortable) => {
-  const {
-    ajax,
-    behaviors,
-    debounce,
-    announce,
-    formatPlural
-  } = Drupal;
+  const { ajax, behaviors, debounce, announce, formatPlural } = Drupal;
+
+  /*
+   * Boolean that tracks if block listing is currently being filtered. Declared
+   * outside of behaviors so value is retained on rebuild.
+   */
   let layoutBuilderBlocksFiltered = false;
+
+  /**
+   * Provides the ability to filter the block listing in "Add block" dialog.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach block filtering behavior to "Add block" dialog.
+   */
   behaviors.layoutBuilderBlockFilter = {
     attach(context) {
       const $categories = $('.js-layout-builder-categories', context);
       const $filterLinks = $categories.find('.js-layout-builder-block-link');
 
-      const filterBlockList = e => {
+      /**
+       * Filters the block list.
+       *
+       * @param {jQuery.Event} e
+       *   The jQuery event for the keyup event that triggered the filter.
+       */
+      const filterBlockList = (e) => {
         const query = e.target.value.toLowerCase();
 
+        /**
+         * Shows or hides the block entry based on the query.
+         *
+         * @param {number} index
+         *   The index in the loop, as provided by `jQuery.each`
+         * @param {HTMLElement} link
+         *   The link to add the block.
+         */
         const toggleBlockEntry = (index, link) => {
-          const textMatch = link.textContent.toLowerCase().indexOf(query) !== -1;
+          const textMatch =
+            link.textContent.toLowerCase().indexOf(query) !== -1;
           $(link).toggle(textMatch);
         };
 
+        // Filter if the length of the query is at least 2 characters.
         if (query.length >= 2) {
-          $categories.find('.js-layout-builder-category:not([open])').attr('remember-closed', '');
+          // Attribute to note which categories are closed before opening all.
+          $categories
+            .find('.js-layout-builder-category:not([open])')
+            .attr('remember-closed', '');
+
+          // Open all categories so every block is available to filtering.
           $categories.find('.js-layout-builder-category').attr('open', '');
+          // Toggle visibility of links based on query.
           $filterLinks.each(toggleBlockEntry);
-          $categories.find('.js-layout-builder-category:not(:has(.js-layout-builder-block-link:visible))').hide();
-          announce(formatPlural($categories.find('.js-layout-builder-block-link:visible').length, '1 block is available in the modified list.', '@count blocks are available in the modified list.'));
+
+          // Only display categories containing visible links.
+          $categories
+            .find(
+              '.js-layout-builder-category:not(:has(.js-layout-builder-block-link:visible))',
+            )
+            .hide();
+
+          announce(
+            formatPlural(
+              $categories.find('.js-layout-builder-block-link:visible').length,
+              '1 block is available in the modified list.',
+              '@count blocks are available in the modified list.',
+            ),
+          );
           layoutBuilderBlocksFiltered = true;
         } else if (layoutBuilderBlocksFiltered) {
           layoutBuilderBlocksFiltered = false;
-          $categories.find('.js-layout-builder-category[remember-closed]').removeAttr('open').removeAttr('remember-closed');
+          // Remove "open" attr from categories that were closed pre-filtering.
+          $categories
+            .find('.js-layout-builder-category[remember-closed]')
+            .removeAttr('open')
+            .removeAttr('remember-closed');
           $categories.find('.js-layout-builder-category').show();
           $filterLinks.show();
           announce(Drupal.t('All available blocks are listed.'));
         }
       };
 
-      $(once('block-filter-text', 'input.js-layout-builder-filter', context)).on('keyup', debounce(filterBlockList, 200));
-    }
-
+      $(
+        once('block-filter-text', 'input.js-layout-builder-filter', context),
+      ).on('keyup', debounce(filterBlockList, 200));
+    },
   };
 
+  /**
+   * Callback used in {@link Drupal.behaviors.layoutBuilderBlockDrag}.
+   *
+   * @param {HTMLElement} item
+   *   The HTML element representing the repositioned block.
+   * @param {HTMLElement} from
+   *   The HTML element representing the previous parent of item
+   * @param {HTMLElement} to
+   *   The HTML element representing the current parent of item
+   *
+   * @internal This method is a callback for layoutBuilderBlockDrag and is used
+   *  in FunctionalJavascript tests. It may be renamed if the test changes.
+   *  @see https://www.drupal.org/node/3084730
+   */
   Drupal.layoutBuilderBlockUpdate = function (item, from, to) {
     const $item = $(item);
     const $from = $(from);
-    const itemRegion = $item.closest('.js-layout-builder-region');
 
+    // Check if the region from the event and region for the item match.
+    const itemRegion = $item.closest('.js-layout-builder-region');
     if (to === itemRegion[0]) {
+      // Find the destination delta.
       const deltaTo = $item.closest('[data-layout-delta]').data('layout-delta');
-      const deltaFrom = $from ? $from.closest('[data-layout-delta]').data('layout-delta') : deltaTo;
+      // If the block didn't leave the original delta use the destination.
+      const deltaFrom = $from
+        ? $from.closest('[data-layout-delta]').data('layout-delta')
+        : deltaTo;
       ajax({
-        url: [$item.closest('[data-layout-update-url]').data('layout-update-url'), deltaFrom, deltaTo, itemRegion.data('region'), $item.data('layout-block-uuid'), $item.prev('[data-layout-block-uuid]').data('layout-block-uuid')].filter(element => element !== undefined).join('/')
+        url: [
+          $item.closest('[data-layout-update-url]').data('layout-update-url'),
+          deltaFrom,
+          deltaTo,
+          itemRegion.data('region'),
+          $item.data('layout-block-uuid'),
+          $item.prev('[data-layout-block-uuid]').data('layout-block-uuid'),
+        ]
+          .filter((element) => element !== undefined)
+          .join('/'),
       }).execute();
     }
   };
 
+  /**
+   * Provides the ability to drag blocks to new positions in the layout.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach block drag behavior to the Layout Builder UI.
+   */
   behaviors.layoutBuilderBlockDrag = {
     attach(context) {
       const regionSelector = '.js-layout-builder-region';
-      Array.prototype.forEach.call(context.querySelectorAll(regionSelector), region => {
-        Sortable.create(region, {
-          draggable: '.js-layout-builder-block',
-          ghostClass: 'ui-state-drop',
-          group: 'builder-region',
-          onEnd: event => Drupal.layoutBuilderBlockUpdate(event.item, event.from, event.to)
-        });
-      });
-    }
-
+      Array.prototype.forEach.call(
+        context.querySelectorAll(regionSelector),
+        (region) => {
+          Sortable.create(region, {
+            draggable: '.js-layout-builder-block',
+            ghostClass: 'ui-state-drop',
+            group: 'builder-region',
+            onEnd: (event) =>
+              Drupal.layoutBuilderBlockUpdate(event.item, event.from, event.to),
+          });
+        },
+      );
+    },
   };
+
+  /**
+   * Disables interactive elements in previewed blocks.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach disabling interactive elements behavior to the Layout Builder UI.
+   */
   behaviors.layoutBuilderDisableInteractiveElements = {
     attach() {
+      // Disable interactive elements inside preview blocks.
       const $blocks = $('#layout-builder [data-layout-block-uuid]');
       $blocks.find('input, textarea, select').prop('disabled', true);
-      $blocks.find('a').not((index, element) => $(element).closest('[data-contextual-id]').length > 0).on('click mouseup touchstart', e => {
-        e.preventDefault();
-        e.stopPropagation();
-      });
-      $blocks.find('button, [href], input, select, textarea, iframe, [tabindex]:not([tabindex="-1"]):not(.tabbable)').not((index, element) => $(element).closest('[data-contextual-id]').length > 0).attr('tabindex', -1);
-    }
+      $blocks
+        .find('a')
+        // Don't disable contextual links.
+        // @see \Drupal\contextual\Element\ContextualLinksPlaceholder
+        .not(
+          (index, element) =>
+            $(element).closest('[data-contextual-id]').length > 0,
+        )
+        .on('click mouseup touchstart', (e) => {
+          e.preventDefault();
+          e.stopPropagation();
+        });
 
+      /*
+       * In preview blocks, remove from the tabbing order all input elements
+       * and elements specifically assigned a tab index, other than those
+       * related to contextual links.
+       */
+      $blocks
+        .find(
+          'button, [href], input, select, textarea, iframe, [tabindex]:not([tabindex="-1"]):not(.tabbable)',
+        )
+        .not(
+          (index, element) =>
+            $(element).closest('[data-contextual-id]').length > 0,
+        )
+        .attr('tabindex', -1);
+    },
   };
+
+  // After a dialog opens, highlight element that the dialog is acting on.
   $(window).on('dialog:aftercreate', (event, dialog, $element) => {
     if (Drupal.offCanvas.isOffCanvas($element)) {
-      $('.is-layout-builder-highlighted').removeClass('is-layout-builder-highlighted');
-      const id = $element.find('[data-layout-builder-target-highlight-id]').attr('data-layout-builder-target-highlight-id');
+      // Start by removing any existing highlighted elements.
+      $('.is-layout-builder-highlighted').removeClass(
+        'is-layout-builder-highlighted',
+      );
 
+      /*
+       * Every dialog has a single 'data-layout-builder-target-highlight-id'
+       * attribute. Every dialog-opening element has a unique
+       * 'data-layout-builder-highlight-id' attribute.
+       *
+       * When the value of data-layout-builder-target-highlight-id matches
+       * an element's value of data-layout-builder-highlight-id, the class
+       * 'is-layout-builder-highlighted' is added to element.
+       */
+      const id = $element
+        .find('[data-layout-builder-target-highlight-id]')
+        .attr('data-layout-builder-target-highlight-id');
       if (id) {
-        $(`[data-layout-builder-highlight-id="${id}"]`).addClass('is-layout-builder-highlighted');
+        $(`[data-layout-builder-highlight-id="${id}"]`).addClass(
+          'is-layout-builder-highlighted',
+        );
       }
 
+      // Remove wrapper class added by move block form.
       $('#layout-builder').removeClass('layout-builder--move-blocks-active');
-      const layoutBuilderWrapperValue = $element.find('[data-add-layout-builder-wrapper]').attr('data-add-layout-builder-wrapper');
 
+      /**
+       * If dialog has a data-add-layout-builder-wrapper attribute, get the
+       * value and add it as a class to the Layout Builder UI wrapper.
+       *
+       * Currently, only the move block form uses
+       * data-add-layout-builder-wrapper, but any dialog can use this attribute
+       * to add a class to the Layout Builder UI while opened.
+       */
+      const layoutBuilderWrapperValue = $element
+        .find('[data-add-layout-builder-wrapper]')
+        .attr('data-add-layout-builder-wrapper');
       if (layoutBuilderWrapperValue) {
         $('#layout-builder').addClass(layoutBuilderWrapperValue);
       }
     }
   });
 
+  /*
+   * When a Layout Builder dialog is triggered, the main canvas resizes. After
+   * the resize transition is complete, see if the target element is still
+   * visible in viewport. If not, scroll page so the target element is again
+   * visible.
+   *
+   * @todo Replace this custom solution when a general solution is made
+   *   available with https://www.drupal.org/node/3033410
+   */
   if (document.querySelector('[data-off-canvas-main-canvas]')) {
     const mainCanvas = document.querySelector('[data-off-canvas-main-canvas]');
+
+    // This event fires when canvas CSS transitions are complete.
     mainCanvas.addEventListener('transitionend', () => {
       const $target = $('.is-layout-builder-highlighted');
 
       if ($target.length > 0) {
+        // These four variables are used to determine if the element is in the
+        // viewport.
         const targetTop = $target.offset().top;
         const targetBottom = targetTop + $target.outerHeight();
         const viewportTop = $(window).scrollTop();
         const viewportBottom = viewportTop + $(window).height();
 
+        // If the element is not in the viewport, scroll it into view.
         if (targetBottom < viewportTop || targetTop > viewportBottom) {
           const viewportMiddle = (viewportBottom + viewportTop) / 2;
           const scrollAmount = targetTop - viewportMiddle;
 
+          // Check whether the browser supports scrollBy(options). If it does
+          // not, use scrollBy(x-coord, y-coord) instead.
           if ('scrollBehavior' in document.documentElement.style) {
             window.scrollBy({
               top: scrollAmount,
               left: 0,
-              behavior: 'smooth'
+              behavior: 'smooth',
             });
           } else {
             window.scrollBy(0, scrollAmount);
@@ -137,61 +298,149 @@
 
   $(window).on('dialog:afterclose', (event, dialog, $element) => {
     if (Drupal.offCanvas.isOffCanvas($element)) {
-      $('.is-layout-builder-highlighted').removeClass('is-layout-builder-highlighted');
+      // Remove the highlight from all elements.
+      $('.is-layout-builder-highlighted').removeClass(
+        'is-layout-builder-highlighted',
+      );
+
+      // Remove wrapper class added by move block form.
       $('#layout-builder').removeClass('layout-builder--move-blocks-active');
     }
   });
+
+  /**
+   * Toggles content preview in the Layout Builder UI.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach content preview toggle to the Layout Builder UI.
+   */
   behaviors.layoutBuilderToggleContentPreview = {
     attach(context) {
       const $layoutBuilder = $('#layout-builder');
+
+      // The content preview toggle.
       const $layoutBuilderContentPreview = $('#layout-builder-content-preview');
-      const contentPreviewId = $layoutBuilderContentPreview.data('content-preview-id');
-      const isContentPreview = JSON.parse(localStorage.getItem(contentPreviewId)) !== false;
 
+      // data-content-preview-id specifies the layout being edited.
+      const contentPreviewId =
+        $layoutBuilderContentPreview.data('content-preview-id');
+
+      /**
+       * Tracks if content preview is enabled for this layout. Defaults to true
+       * if no value has previously been set.
+       */
+      const isContentPreview =
+        JSON.parse(localStorage.getItem(contentPreviewId)) !== false;
+
+      /**
+       * Disables content preview in the Layout Builder UI.
+       *
+       * Disabling content preview hides block content. It is replaced with the
+       * value of the block's data-layout-content-preview-placeholder-label
+       * attribute.
+       *
+       * @todo Revisit in https://www.drupal.org/node/3043215, it may be
+       *   possible to remove all but the first line of this function.
+       */
       const disableContentPreview = () => {
         $layoutBuilder.addClass('layout-builder--content-preview-disabled');
-        $('[data-layout-content-preview-placeholder-label]', context).each((i, element) => {
-          const $element = $(element);
-          $element.children(':not([data-contextual-id])').hide(0);
-          const contentPreviewPlaceholderText = $element.attr('data-layout-content-preview-placeholder-label');
-          const contentPreviewPlaceholderLabel = Drupal.theme('layoutBuilderPrependContentPreviewPlaceholderLabel', contentPreviewPlaceholderText);
-          $element.prepend(contentPreviewPlaceholderLabel);
-        });
+
+        /**
+         * Iterate over all Layout Builder blocks to hide their content and add
+         * placeholder labels.
+         */
+        $('[data-layout-content-preview-placeholder-label]', context).each(
+          (i, element) => {
+            const $element = $(element);
+
+            // Hide everything in block that isn't contextual link related.
+            $element.children(':not([data-contextual-id])').hide(0);
+
+            const contentPreviewPlaceholderText = $element.attr(
+              'data-layout-content-preview-placeholder-label',
+            );
+
+            const contentPreviewPlaceholderLabel = Drupal.theme(
+              'layoutBuilderPrependContentPreviewPlaceholderLabel',
+              contentPreviewPlaceholderText,
+            );
+            $element.prepend(contentPreviewPlaceholderLabel);
+          },
+        );
       };
 
+      /**
+       * Enables content preview in the Layout Builder UI.
+       *
+       * When content preview is enabled, the Layout Builder UI returns to its
+       * default experience. This is accomplished by removing placeholder
+       * labels and un-hiding block content.
+       *
+       * @todo Revisit in https://www.drupal.org/node/3043215, it may be
+       *   possible to remove all but the first line of this function.
+       */
       const enableContentPreview = () => {
         $layoutBuilder.removeClass('layout-builder--content-preview-disabled');
+
+        // Remove all placeholder labels.
         $('.js-layout-builder-content-preview-placeholder-label').remove();
-        $('[data-layout-content-preview-placeholder-label]').each((i, element) => {
-          $(element).children().show();
-        });
+
+        // Iterate over all blocks.
+        $('[data-layout-content-preview-placeholder-label]').each(
+          (i, element) => {
+            $(element).children().show();
+          },
+        );
       };
 
-      $('#layout-builder-content-preview', context).on('change', event => {
+      $('#layout-builder-content-preview', context).on('change', (event) => {
         const isChecked = $(event.currentTarget).is(':checked');
+
         localStorage.setItem(contentPreviewId, JSON.stringify(isChecked));
 
         if (isChecked) {
           enableContentPreview();
-          announce(Drupal.t('Block previews are visible. Block labels are hidden.'));
+          announce(
+            Drupal.t('Block previews are visible. Block labels are hidden.'),
+          );
         } else {
           disableContentPreview();
-          announce(Drupal.t('Block previews are hidden. Block labels are visible.'));
+          announce(
+            Drupal.t('Block previews are hidden. Block labels are visible.'),
+          );
         }
       });
 
+      /**
+       * On rebuild, see if content preview has been set to disabled. If yes,
+       * disable content preview in the Layout Builder UI.
+       */
       if (!isContentPreview) {
         $layoutBuilderContentPreview.attr('checked', false);
         disableContentPreview();
       }
-    }
-
+    },
   };
 
-  Drupal.theme.layoutBuilderPrependContentPreviewPlaceholderLabel = contentPreviewPlaceholderText => {
+  /**
+   * Creates content preview placeholder label markup.
+   *
+   * @param {string} contentPreviewPlaceholderText
+   *   The text content of the placeholder label
+   *
+   * @return {string}
+   *   A HTML string of the placeholder label.
+   */
+  Drupal.theme.layoutBuilderPrependContentPreviewPlaceholderLabel = (
+    contentPreviewPlaceholderText,
+  ) => {
     const contentPreviewPlaceholderLabel = document.createElement('div');
-    contentPreviewPlaceholderLabel.className = 'layout-builder-block__content-preview-placeholder-label js-layout-builder-content-preview-placeholder-label';
+    contentPreviewPlaceholderLabel.className =
+      'layout-builder-block__content-preview-placeholder-label js-layout-builder-content-preview-placeholder-label';
     contentPreviewPlaceholderLabel.innerHTML = contentPreviewPlaceholderText;
+
     return `<div class="layout-builder-block__content-preview-placeholder-label js-layout-builder-content-preview-placeholder-label">${contentPreviewPlaceholderText}</div>`;
   };
-})(jQuery, Drupal, Sortable);
\ No newline at end of file
+})(jQuery, Drupal, Sortable);
diff --git a/core/modules/locale/locale.admin.es6.js b/core/modules/locale/locale.admin.es6.js
deleted file mode 100644
index a0a26e2d856d..000000000000
--- a/core/modules/locale/locale.admin.es6.js
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * @file
- * Locale admin behavior.
- */
-
-(function ($, Drupal) {
-  /**
-   * Marks changes of translations.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to show the user if translations has changed.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detach behavior to show the user if translations has changed.
-   */
-  Drupal.behaviors.localeTranslateDirty = {
-    attach() {
-      const form = once('localetranslatedirty', '#locale-translate-edit-form');
-      if (form.length) {
-        const $form = $(form);
-        // Display a notice if any row changed.
-        $form.one('formUpdated.localeTranslateDirty', 'table', function () {
-          const $marker = $(
-            Drupal.theme('localeTranslateChangedWarning'),
-          ).hide();
-          $(this).addClass('changed').before($marker);
-          $marker.fadeIn('slow');
-        });
-        // Highlight changed row.
-        $form.on('formUpdated.localeTranslateDirty', 'tr', function () {
-          const $row = $(this);
-          const rowToMark = once('localemark', $row);
-          const marker = Drupal.theme('localeTranslateChangedMarker');
-
-          $row.addClass('changed');
-          // Add an asterisk only once if row changed.
-          if (rowToMark.length) {
-            $(rowToMark).find('td:first-child .js-form-item').append(marker);
-          }
-        });
-      }
-    },
-    detach(context, settings, trigger) {
-      if (trigger === 'unload') {
-        const form = once.remove(
-          'localetranslatedirty',
-          '#locale-translate-edit-form',
-        );
-        if (form.length) {
-          $(form).off('formUpdated.localeTranslateDirty');
-        }
-      }
-    },
-  };
-
-  /**
-   * Show/hide the description details on Available translation updates page.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior for toggling details on the translation update page.
-   */
-  Drupal.behaviors.hideUpdateInformation = {
-    attach(context, settings) {
-      const table = once('expand-updates', '#locale-translation-status-form');
-      if (table.length) {
-        const $table = $(table);
-        const $tbodies = $table.find('tbody');
-
-        // Open/close the description details by toggling a tr class.
-        $tbodies.on('click keydown', '.description', function (e) {
-          if (e.keyCode && e.keyCode !== 13 && e.keyCode !== 32) {
-            return;
-          }
-          e.preventDefault();
-          const $tr = $(this).closest('tr');
-
-          $tr.toggleClass('expanded');
-
-          const $localePrefix = $tr.find('.locale-translation-update__prefix');
-          if ($localePrefix.length) {
-            // Change screen reader text.
-            $localePrefix[0].textContent = $tr.hasClass('expanded')
-              ? Drupal.t('Hide description')
-              : Drupal.t('Show description');
-          }
-        });
-        $table.find('.requirements, .links').hide();
-      }
-    },
-  };
-
-  $.extend(
-    Drupal.theme,
-    /** @lends Drupal.theme */ {
-      /**
-       * Creates markup for a changed translation marker.
-       *
-       * @return {string}
-       *   Markup for the marker.
-       */
-      localeTranslateChangedMarker() {
-        return `<abbr class="warning ajax-changed" title="${Drupal.t(
-          'Changed',
-        )}">*</abbr>`;
-      },
-
-      /**
-       * Creates markup for the translation changed warning.
-       *
-       * @return {string}
-       *   Markup for the warning.
-       */
-      localeTranslateChangedWarning() {
-        return `<div class="clearfix messages messages--warning">${Drupal.theme(
-          'localeTranslateChangedMarker',
-        )} ${Drupal.t(
-          'Changes made in this table will not be saved until the form is submitted.',
-        )}</div>`;
-      },
-    },
-  );
-})(jQuery, Drupal);
diff --git a/core/modules/locale/locale.admin.js b/core/modules/locale/locale.admin.js
index 9dfaa5223816..a0a26e2d856d 100644
--- a/core/modules/locale/locale.admin.js
+++ b/core/modules/locale/locale.admin.js
@@ -1,80 +1,125 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Locale admin behavior.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Marks changes of translations.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to show the user if translations has changed.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detach behavior to show the user if translations has changed.
+   */
   Drupal.behaviors.localeTranslateDirty = {
     attach() {
       const form = once('localetranslatedirty', '#locale-translate-edit-form');
-
       if (form.length) {
         const $form = $(form);
+        // Display a notice if any row changed.
         $form.one('formUpdated.localeTranslateDirty', 'table', function () {
-          const $marker = $(Drupal.theme('localeTranslateChangedWarning')).hide();
+          const $marker = $(
+            Drupal.theme('localeTranslateChangedWarning'),
+          ).hide();
           $(this).addClass('changed').before($marker);
           $marker.fadeIn('slow');
         });
+        // Highlight changed row.
         $form.on('formUpdated.localeTranslateDirty', 'tr', function () {
           const $row = $(this);
           const rowToMark = once('localemark', $row);
           const marker = Drupal.theme('localeTranslateChangedMarker');
-          $row.addClass('changed');
 
+          $row.addClass('changed');
+          // Add an asterisk only once if row changed.
           if (rowToMark.length) {
             $(rowToMark).find('td:first-child .js-form-item').append(marker);
           }
         });
       }
     },
-
     detach(context, settings, trigger) {
       if (trigger === 'unload') {
-        const form = once.remove('localetranslatedirty', '#locale-translate-edit-form');
-
+        const form = once.remove(
+          'localetranslatedirty',
+          '#locale-translate-edit-form',
+        );
         if (form.length) {
           $(form).off('formUpdated.localeTranslateDirty');
         }
       }
-    }
-
+    },
   };
+
+  /**
+   * Show/hide the description details on Available translation updates page.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior for toggling details on the translation update page.
+   */
   Drupal.behaviors.hideUpdateInformation = {
     attach(context, settings) {
       const table = once('expand-updates', '#locale-translation-status-form');
-
       if (table.length) {
         const $table = $(table);
         const $tbodies = $table.find('tbody');
+
+        // Open/close the description details by toggling a tr class.
         $tbodies.on('click keydown', '.description', function (e) {
           if (e.keyCode && e.keyCode !== 13 && e.keyCode !== 32) {
             return;
           }
-
           e.preventDefault();
           const $tr = $(this).closest('tr');
+
           $tr.toggleClass('expanded');
-          const $localePrefix = $tr.find('.locale-translation-update__prefix');
 
+          const $localePrefix = $tr.find('.locale-translation-update__prefix');
           if ($localePrefix.length) {
-            $localePrefix[0].textContent = $tr.hasClass('expanded') ? Drupal.t('Hide description') : Drupal.t('Show description');
+            // Change screen reader text.
+            $localePrefix[0].textContent = $tr.hasClass('expanded')
+              ? Drupal.t('Hide description')
+              : Drupal.t('Show description');
           }
         });
         $table.find('.requirements, .links').hide();
       }
-    }
-
-  };
-  $.extend(Drupal.theme, {
-    localeTranslateChangedMarker() {
-      return `<abbr class="warning ajax-changed" title="${Drupal.t('Changed')}">*</abbr>`;
     },
+  };
 
-    localeTranslateChangedWarning() {
-      return `<div class="clearfix messages messages--warning">${Drupal.theme('localeTranslateChangedMarker')} ${Drupal.t('Changes made in this table will not be saved until the form is submitted.')}</div>`;
-    }
+  $.extend(
+    Drupal.theme,
+    /** @lends Drupal.theme */ {
+      /**
+       * Creates markup for a changed translation marker.
+       *
+       * @return {string}
+       *   Markup for the marker.
+       */
+      localeTranslateChangedMarker() {
+        return `<abbr class="warning ajax-changed" title="${Drupal.t(
+          'Changed',
+        )}">*</abbr>`;
+      },
 
-  });
-})(jQuery, Drupal);
\ No newline at end of file
+      /**
+       * Creates markup for the translation changed warning.
+       *
+       * @return {string}
+       *   Markup for the warning.
+       */
+      localeTranslateChangedWarning() {
+        return `<div class="clearfix messages messages--warning">${Drupal.theme(
+          'localeTranslateChangedMarker',
+        )} ${Drupal.t(
+          'Changes made in this table will not be saved until the form is submitted.',
+        )}</div>`;
+      },
+    },
+  );
+})(jQuery, Drupal);
diff --git a/core/modules/locale/locale.bulk.es6.js b/core/modules/locale/locale.bulk.es6.js
deleted file mode 100644
index 1b7d0ff2e556..000000000000
--- a/core/modules/locale/locale.bulk.es6.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * @file
- * Locale behavior.
- */
-
-(function ($, Drupal) {
-  /**
-   * Select the language code of an imported file based on its filename.
-   *
-   * This only works if the file name ends with "LANGCODE.po".
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior for preselecting language code based on filename.
-   */
-  Drupal.behaviors.importLanguageCodeSelector = {
-    attach(context, settings) {
-      const form = once('autodetect-lang', '#locale-translate-import-form');
-      if (form.length) {
-        const $form = $(form);
-        const $langcode = $form.find('.langcode-input');
-        $form.find('.file-import-input').on('change', function () {
-          // If the filename is fully the language code or the filename
-          // ends with a language code, pre-select that one.
-          const matches = this.value.match(/([^.][.]*)([\w-]+)\.po$/);
-          if (
-            matches &&
-            $langcode.find(`option[value="${matches[2]}"]`).length
-          ) {
-            $langcode[0].value = matches[2];
-          }
-        });
-      }
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/locale/locale.bulk.js b/core/modules/locale/locale.bulk.js
index 5d6c08f95054..1b7d0ff2e556 100644
--- a/core/modules/locale/locale.bulk.js
+++ b/core/modules/locale/locale.bulk.js
@@ -1,27 +1,37 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Locale behavior.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Select the language code of an imported file based on its filename.
+   *
+   * This only works if the file name ends with "LANGCODE.po".
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior for preselecting language code based on filename.
+   */
   Drupal.behaviors.importLanguageCodeSelector = {
     attach(context, settings) {
       const form = once('autodetect-lang', '#locale-translate-import-form');
-
       if (form.length) {
         const $form = $(form);
         const $langcode = $form.find('.langcode-input');
         $form.find('.file-import-input').on('change', function () {
+          // If the filename is fully the language code or the filename
+          // ends with a language code, pre-select that one.
           const matches = this.value.match(/([^.][.]*)([\w-]+)\.po$/);
-
-          if (matches && $langcode.find(`option[value="${matches[2]}"]`).length) {
+          if (
+            matches &&
+            $langcode.find(`option[value="${matches[2]}"]`).length
+          ) {
             $langcode[0].value = matches[2];
           }
         });
       }
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/locale/tests/locale_test.es6.js b/core/modules/locale/tests/locale_test.es6.js
deleted file mode 100644
index 1f266c62390b..000000000000
--- a/core/modules/locale/tests/locale_test.es6.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * @file
- * JavaScript for locale_test.module.
- *
- * @ignore
- */
-
-Drupal.t("Standard Call t");
-Drupal
-  .
-  t
-  (
-    "Whitespace Call t"
-  )
-;
-
-Drupal.t('Single Quote t');
-Drupal.t('Single Quote \'Escaped\' t');
-Drupal.t('Single Quote ' + 'Concat ' + 'strings ' + 't');
-
-Drupal.t("Double Quote t");
-Drupal.t("Double Quote \"Escaped\" t");
-Drupal.t("Double Quote " + "Concat " + "strings " + "t");
-
-Drupal.t("Context Unquoted t", {}, {context: "Context string unquoted"});
-Drupal.t("Context Single Quoted t", {}, {'context': "Context string single quoted"});
-Drupal.t("Context Double Quoted t", {}, {"context": "Context string double quoted"});
-
-Drupal.t("Context !key Args t", {'!key': 'value'}, {context: "Context string"});
-
-Drupal.formatPlural(1, "Standard Call plural", "Standard Call @count plural");
-Drupal
-  .
-  formatPlural
-  (
-    1,
-    "Whitespace Call plural",
-    "Whitespace Call @count plural"
-  )
-;
-
-Drupal.formatPlural(1, 'Single Quote plural', 'Single Quote @count plural');
-Drupal.formatPlural(1, 'Single Quote \'Escaped\' plural', 'Single Quote \'Escaped\' @count plural');
-
-Drupal.formatPlural(1, "Double Quote plural", "Double Quote @count plural");
-Drupal.formatPlural(1, "Double Quote \"Escaped\" plural", "Double Quote \"Escaped\" @count plural");
-
-Drupal.formatPlural(1, "Context Unquoted plural", "Context Unquoted @count plural", {}, {context: "Context string unquoted"});
-Drupal.formatPlural(1, "Context Single Quoted plural", "Context Single Quoted @count plural", {}, {'context': "Context string single quoted"});
-Drupal.formatPlural(1, "Context Double Quoted plural", "Context Double Quoted @count plural", {}, {"context": "Context string double quoted"});
-
-Drupal.formatPlural(1, "Context !key Args plural", "Context !key Args @count plural", {'!key': 'value'}, {context: "Context string"});
-
-Drupal.formatPlural(1, "No count argument plural - singular", "No count argument plural - plural");
diff --git a/core/modules/locale/tests/locale_test.js b/core/modules/locale/tests/locale_test.js
index 8c5ca7258c3b..1f266c62390b 100644
--- a/core/modules/locale/tests/locale_test.js
+++ b/core/modules/locale/tests/locale_test.js
@@ -1,50 +1,54 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * JavaScript for locale_test.module.
+ *
+ * @ignore
+ */
 
 Drupal.t("Standard Call t");
-Drupal.t("Whitespace Call t");
+Drupal
+  .
+  t
+  (
+    "Whitespace Call t"
+  )
+;
+
 Drupal.t('Single Quote t');
 Drupal.t('Single Quote \'Escaped\' t');
 Drupal.t('Single Quote ' + 'Concat ' + 'strings ' + 't');
+
 Drupal.t("Double Quote t");
 Drupal.t("Double Quote \"Escaped\" t");
 Drupal.t("Double Quote " + "Concat " + "strings " + "t");
-Drupal.t("Context Unquoted t", {}, {
-  context: "Context string unquoted"
-});
-Drupal.t("Context Single Quoted t", {}, {
-  'context': "Context string single quoted"
-});
-Drupal.t("Context Double Quoted t", {}, {
-  "context": "Context string double quoted"
-});
-Drupal.t("Context !key Args t", {
-  '!key': 'value'
-}, {
-  context: "Context string"
-});
+
+Drupal.t("Context Unquoted t", {}, {context: "Context string unquoted"});
+Drupal.t("Context Single Quoted t", {}, {'context': "Context string single quoted"});
+Drupal.t("Context Double Quoted t", {}, {"context": "Context string double quoted"});
+
+Drupal.t("Context !key Args t", {'!key': 'value'}, {context: "Context string"});
+
 Drupal.formatPlural(1, "Standard Call plural", "Standard Call @count plural");
-Drupal.formatPlural(1, "Whitespace Call plural", "Whitespace Call @count plural");
+Drupal
+  .
+  formatPlural
+  (
+    1,
+    "Whitespace Call plural",
+    "Whitespace Call @count plural"
+  )
+;
+
 Drupal.formatPlural(1, 'Single Quote plural', 'Single Quote @count plural');
 Drupal.formatPlural(1, 'Single Quote \'Escaped\' plural', 'Single Quote \'Escaped\' @count plural');
+
 Drupal.formatPlural(1, "Double Quote plural", "Double Quote @count plural");
 Drupal.formatPlural(1, "Double Quote \"Escaped\" plural", "Double Quote \"Escaped\" @count plural");
-Drupal.formatPlural(1, "Context Unquoted plural", "Context Unquoted @count plural", {}, {
-  context: "Context string unquoted"
-});
-Drupal.formatPlural(1, "Context Single Quoted plural", "Context Single Quoted @count plural", {}, {
-  'context': "Context string single quoted"
-});
-Drupal.formatPlural(1, "Context Double Quoted plural", "Context Double Quoted @count plural", {}, {
-  "context": "Context string double quoted"
-});
-Drupal.formatPlural(1, "Context !key Args plural", "Context !key Args @count plural", {
-  '!key': 'value'
-}, {
-  context: "Context string"
-});
-Drupal.formatPlural(1, "No count argument plural - singular", "No count argument plural - plural");
\ No newline at end of file
+
+Drupal.formatPlural(1, "Context Unquoted plural", "Context Unquoted @count plural", {}, {context: "Context string unquoted"});
+Drupal.formatPlural(1, "Context Single Quoted plural", "Context Single Quoted @count plural", {}, {'context': "Context string single quoted"});
+Drupal.formatPlural(1, "Context Double Quoted plural", "Context Double Quoted @count plural", {}, {"context": "Context string double quoted"});
+
+Drupal.formatPlural(1, "Context !key Args plural", "Context !key Args @count plural", {'!key': 'value'}, {context: "Context string"});
+
+Drupal.formatPlural(1, "No count argument plural - singular", "No count argument plural - plural");
diff --git a/core/modules/locale/tests/src/Functional/LocaleJavascriptTranslationTest.php b/core/modules/locale/tests/src/Functional/LocaleJavascriptTranslationTest.php
index 2b1cfd8d7261..6236d2730e89 100644
--- a/core/modules/locale/tests/src/Functional/LocaleJavascriptTranslationTest.php
+++ b/core/modules/locale/tests/src/Functional/LocaleJavascriptTranslationTest.php
@@ -32,12 +32,8 @@ public function testFileParsing() {
     // _locale_parse_js_file() finds translatable source strings in all valid
     // JavaScript syntax regardless of the coding style used, especially with
     // respect to optional whitespace, line breaks, etc.
-    // - We test locale_test.es6.js, because that is the one that contains a
+    // - We test locale_test.js, because that is the one that contains a
     //   variety of whitespace styles.
-    // - We also test the transpiled locale_test.js as an extra double-check
-    //   that JavaScript transpilation doesn't change what
-    //   _locale_parse_js_file() finds.
-    $files[] = __DIR__ . '/../../locale_test.es6.js';
     $files[] = __DIR__ . '/../../locale_test.js';
 
     foreach ($files as $filename) {
diff --git a/core/modules/media/js/form.es6.js b/core/modules/media/js/form.es6.js
deleted file mode 100644
index e7ac049cb87e..000000000000
--- a/core/modules/media/js/form.es6.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * @file
- * Defines JavaScript behaviors for the media form.
- */
-
-(function ($, Drupal) {
-  /**
-   * Behaviors for summaries for tabs in the media edit form.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches summary behavior for tabs in the media edit form.
-   */
-  Drupal.behaviors.mediaFormSummaries = {
-    attach(context) {
-      $(context)
-        .find('.media-form-author')
-        .drupalSetSummary((context) => {
-          const nameInput = context.querySelector('.field--name-uid input');
-          const name = nameInput && nameInput.value;
-          const dateInput = context.querySelector('.field--name-created input');
-          const date = dateInput && dateInput.value;
-
-          if (name && date) {
-            return Drupal.t('By @name on @date', {
-              '@name': name,
-              '@date': date,
-            });
-          }
-          if (name) {
-            return Drupal.t('By @name', { '@name': name });
-          }
-          if (date) {
-            return Drupal.t('Authored on @date', { '@date': date });
-          }
-        });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/media/js/form.js b/core/modules/media/js/form.js
index 397769fb0253..e7ac049cb87e 100644
--- a/core/modules/media/js/form.js
+++ b/core/modules/media/js/form.js
@@ -1,39 +1,40 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Defines JavaScript behaviors for the media form.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Behaviors for summaries for tabs in the media edit form.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches summary behavior for tabs in the media edit form.
+   */
   Drupal.behaviors.mediaFormSummaries = {
     attach(context) {
-      $(context).find('.media-form-author').drupalSetSummary(context => {
-        const nameInput = context.querySelector('.field--name-uid input');
-        const name = nameInput && nameInput.value;
-        const dateInput = context.querySelector('.field--name-created input');
-        const date = dateInput && dateInput.value;
-
-        if (name && date) {
-          return Drupal.t('By @name on @date', {
-            '@name': name,
-            '@date': date
-          });
-        }
-
-        if (name) {
-          return Drupal.t('By @name', {
-            '@name': name
-          });
-        }
-
-        if (date) {
-          return Drupal.t('Authored on @date', {
-            '@date': date
-          });
-        }
-      });
-    }
+      $(context)
+        .find('.media-form-author')
+        .drupalSetSummary((context) => {
+          const nameInput = context.querySelector('.field--name-uid input');
+          const name = nameInput && nameInput.value;
+          const dateInput = context.querySelector('.field--name-created input');
+          const date = dateInput && dateInput.value;
 
+          if (name && date) {
+            return Drupal.t('By @name on @date', {
+              '@name': name,
+              '@date': date,
+            });
+          }
+          if (name) {
+            return Drupal.t('By @name', { '@name': name });
+          }
+          if (date) {
+            return Drupal.t('Authored on @date', { '@date': date });
+          }
+        });
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/media/js/media_embed_ckeditor.theme.es6.js b/core/modules/media/js/media_embed_ckeditor.theme.es6.js
deleted file mode 100644
index bb2bd6dcda47..000000000000
--- a/core/modules/media/js/media_embed_ckeditor.theme.es6.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * @file
- * Theme elements for the Media Embed text editor plugins.
- */
-
-((Drupal) => {
-  /**
-   * Themes the error displayed when the media embed preview fails.
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   *
-   * @see media-embed-error.html.twig
-   */
-  Drupal.theme.mediaEmbedPreviewError = () =>
-    `<div>${Drupal.t(
-      'An error occurred while trying to preview the media. Please save your work and reload this page.',
-    )}</div>`;
-})(Drupal);
diff --git a/core/modules/media/js/media_embed_ckeditor.theme.js b/core/modules/media/js/media_embed_ckeditor.theme.js
index bcacbb8bb5bb..bb2bd6dcda47 100644
--- a/core/modules/media/js/media_embed_ckeditor.theme.js
+++ b/core/modules/media/js/media_embed_ckeditor.theme.js
@@ -1,10 +1,19 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Theme elements for the Media Embed text editor plugins.
+ */
 
-(Drupal => {
-  Drupal.theme.mediaEmbedPreviewError = () => `<div>${Drupal.t('An error occurred while trying to preview the media. Please save your work and reload this page.')}</div>`;
-})(Drupal);
\ No newline at end of file
+((Drupal) => {
+  /**
+   * Themes the error displayed when the media embed preview fails.
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   *
+   * @see media-embed-error.html.twig
+   */
+  Drupal.theme.mediaEmbedPreviewError = () =>
+    `<div>${Drupal.t(
+      'An error occurred while trying to preview the media. Please save your work and reload this page.',
+    )}</div>`;
+})(Drupal);
diff --git a/core/modules/media/js/type_form.es6.js b/core/modules/media/js/type_form.es6.js
deleted file mode 100644
index f24d52b52e61..000000000000
--- a/core/modules/media/js/type_form.es6.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * @file
- * Defines JavaScript behaviors for the media type form.
- */
-
-(function ($, Drupal) {
-  /**
-   * Behaviors for setting summaries on media type form.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches summary behaviors on media type edit forms.
-   */
-  Drupal.behaviors.mediaTypeFormSummaries = {
-    attach(context) {
-      const $context = $(context);
-      // Provide the vertical tab summaries.
-      $context.find('#edit-workflow').drupalSetSummary((context) => {
-        const vals = [];
-        $(context)
-          .find('input[name^="options"]:checked')
-          .parent()
-          .each(function () {
-            vals.push(Drupal.checkPlain($(this).find('label')[0].textContent));
-          });
-        if (!$(context).find('#edit-options-status').is(':checked')) {
-          vals.unshift(Drupal.t('Not published'));
-        }
-        return vals.join(', ');
-      });
-      $(context)
-        .find('#edit-language')
-        .drupalSetSummary((context) => {
-          const vals = [];
-
-          vals.push(
-            $(context).find(
-              '.js-form-item-language-configuration-langcode select option:selected',
-            )[0].textContent,
-          );
-
-          $(context)
-            .find('input:checked')
-            .next('label')
-            .each(function () {
-              vals.push(Drupal.checkPlain(this.textContent));
-            });
-
-          return vals.join(', ');
-        });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/media/js/type_form.js b/core/modules/media/js/type_form.js
index e351a6d72ba6..f24d52b52e61 100644
--- a/core/modules/media/js/type_form.js
+++ b/core/modules/media/js/type_form.js
@@ -1,35 +1,54 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Defines JavaScript behaviors for the media type form.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Behaviors for setting summaries on media type form.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches summary behaviors on media type edit forms.
+   */
   Drupal.behaviors.mediaTypeFormSummaries = {
     attach(context) {
       const $context = $(context);
-      $context.find('#edit-workflow').drupalSetSummary(context => {
+      // Provide the vertical tab summaries.
+      $context.find('#edit-workflow').drupalSetSummary((context) => {
         const vals = [];
-        $(context).find('input[name^="options"]:checked').parent().each(function () {
-          vals.push(Drupal.checkPlain($(this).find('label')[0].textContent));
-        });
-
+        $(context)
+          .find('input[name^="options"]:checked')
+          .parent()
+          .each(function () {
+            vals.push(Drupal.checkPlain($(this).find('label')[0].textContent));
+          });
         if (!$(context).find('#edit-options-status').is(':checked')) {
           vals.unshift(Drupal.t('Not published'));
         }
-
-        return vals.join(', ');
-      });
-      $(context).find('#edit-language').drupalSetSummary(context => {
-        const vals = [];
-        vals.push($(context).find('.js-form-item-language-configuration-langcode select option:selected')[0].textContent);
-        $(context).find('input:checked').next('label').each(function () {
-          vals.push(Drupal.checkPlain(this.textContent));
-        });
         return vals.join(', ');
       });
-    }
+      $(context)
+        .find('#edit-language')
+        .drupalSetSummary((context) => {
+          const vals = [];
+
+          vals.push(
+            $(context).find(
+              '.js-form-item-language-configuration-langcode select option:selected',
+            )[0].textContent,
+          );
 
+          $(context)
+            .find('input:checked')
+            .next('label')
+            .each(function () {
+              vals.push(Drupal.checkPlain(this.textContent));
+            });
+
+          return vals.join(', ');
+        });
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/media_library/js/media_library.click_to_select.es6.js b/core/modules/media_library/js/media_library.click_to_select.es6.js
deleted file mode 100644
index f0e0d582b7c5..000000000000
--- a/core/modules/media_library/js/media_library.click_to_select.es6.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * @file media_library.click_to_select.es6.js
- */
-
-(($, Drupal) => {
-  /**
-   * Allows users to select an element which checks a hidden checkbox.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior for selecting media library item.
-   */
-  Drupal.behaviors.ClickToSelect = {
-    attach(context) {
-      $(
-        once(
-          'media-library-click-to-select',
-          '.js-click-to-select-trigger',
-          context,
-        ),
-      ).on('click', (event) => {
-        // Links inside the trigger should not be click-able.
-        event.preventDefault();
-        // Click the hidden checkbox when the trigger is clicked.
-        const $input = $(event.currentTarget)
-          .closest('.js-click-to-select')
-          .find('.js-click-to-select-checkbox input');
-        $input.prop('checked', !$input.prop('checked')).trigger('change');
-      });
-
-      $(
-        once(
-          'media-library-click-to-select',
-          '.js-click-to-select-checkbox input',
-          context,
-        ),
-      )
-        .on('change', ({ currentTarget }) => {
-          $(currentTarget)
-            .closest('.js-click-to-select')
-            .toggleClass('checked', $(currentTarget).prop('checked'));
-        })
-        // Adds is-focus class to the click-to-select element.
-        .on('focus blur', ({ currentTarget, type }) => {
-          $(currentTarget)
-            .closest('.js-click-to-select')
-            .toggleClass('is-focus', type === 'focus');
-        });
-
-      // Adds hover class to the click-to-select element.
-      $(
-        once(
-          'media-library-click-to-select-hover',
-          '.js-click-to-select-trigger, .js-click-to-select-checkbox',
-          context,
-        ),
-      ).on('mouseover mouseout', ({ currentTarget, type }) => {
-        $(currentTarget)
-          .closest('.js-click-to-select')
-          .toggleClass('is-hover', type === 'mouseover');
-      });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/media_library/js/media_library.click_to_select.js b/core/modules/media_library/js/media_library.click_to_select.js
index 514d42ecc155..9bacd3d111b9 100644
--- a/core/modules/media_library/js/media_library.click_to_select.js
+++ b/core/modules/media_library/js/media_library.click_to_select.js
@@ -1,38 +1,65 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file media_library.click_to_select.js
+ */
 
 (($, Drupal) => {
+  /**
+   * Allows users to select an element which checks a hidden checkbox.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior for selecting media library item.
+   */
   Drupal.behaviors.ClickToSelect = {
     attach(context) {
-      $(once('media-library-click-to-select', '.js-click-to-select-trigger', context)).on('click', event => {
+      $(
+        once(
+          'media-library-click-to-select',
+          '.js-click-to-select-trigger',
+          context,
+        ),
+      ).on('click', (event) => {
+        // Links inside the trigger should not be click-able.
         event.preventDefault();
-        const $input = $(event.currentTarget).closest('.js-click-to-select').find('.js-click-to-select-checkbox input');
+        // Click the hidden checkbox when the trigger is clicked.
+        const $input = $(event.currentTarget)
+          .closest('.js-click-to-select')
+          .find('.js-click-to-select-checkbox input');
         $input.prop('checked', !$input.prop('checked')).trigger('change');
       });
-      $(once('media-library-click-to-select', '.js-click-to-select-checkbox input', context)).on('change', _ref => {
-        let {
-          currentTarget
-        } = _ref;
-        $(currentTarget).closest('.js-click-to-select').toggleClass('checked', $(currentTarget).prop('checked'));
-      }).on('focus blur', _ref2 => {
-        let {
-          currentTarget,
-          type
-        } = _ref2;
-        $(currentTarget).closest('.js-click-to-select').toggleClass('is-focus', type === 'focus');
-      });
-      $(once('media-library-click-to-select-hover', '.js-click-to-select-trigger, .js-click-to-select-checkbox', context)).on('mouseover mouseout', _ref3 => {
-        let {
-          currentTarget,
-          type
-        } = _ref3;
-        $(currentTarget).closest('.js-click-to-select').toggleClass('is-hover', type === 'mouseover');
-      });
-    }
 
+      $(
+        once(
+          'media-library-click-to-select',
+          '.js-click-to-select-checkbox input',
+          context,
+        ),
+      )
+        .on('change', ({ currentTarget }) => {
+          $(currentTarget)
+            .closest('.js-click-to-select')
+            .toggleClass('checked', $(currentTarget).prop('checked'));
+        })
+        // Adds is-focus class to the click-to-select element.
+        .on('focus blur', ({ currentTarget, type }) => {
+          $(currentTarget)
+            .closest('.js-click-to-select')
+            .toggleClass('is-focus', type === 'focus');
+        });
+
+      // Adds hover class to the click-to-select element.
+      $(
+        once(
+          'media-library-click-to-select-hover',
+          '.js-click-to-select-trigger, .js-click-to-select-checkbox',
+          context,
+        ),
+      ).on('mouseover mouseout', ({ currentTarget, type }) => {
+        $(currentTarget)
+          .closest('.js-click-to-select')
+          .toggleClass('is-hover', type === 'mouseover');
+      });
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/media_library/js/media_library.ui.es6.js b/core/modules/media_library/js/media_library.ui.es6.js
deleted file mode 100644
index 569b44312110..000000000000
--- a/core/modules/media_library/js/media_library.ui.es6.js
+++ /dev/null
@@ -1,427 +0,0 @@
-/**
- * @file media_library.ui.es6.js
- */
-(($, Drupal, window, { tabbable }) => {
-  /**
-   * Wrapper object for the current state of the media library.
-   */
-  Drupal.MediaLibrary = {
-    /**
-     * When a user interacts with the media library we want the selection to
-     * persist as long as the media library modal is opened. We temporarily
-     * store the selected items while the user filters the media library view or
-     * navigates to different tabs.
-     */
-    currentSelection: [],
-  };
-
-  /**
-   * Command to update the current media library selection.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   The Drupal Ajax object.
-   * @param {object} response
-   *   Object holding the server response.
-   * @param {number} [status]
-   *   The HTTP status code.
-   */
-  Drupal.AjaxCommands.prototype.updateMediaLibrarySelection = function (
-    ajax,
-    response,
-    status,
-  ) {
-    Object.values(response.mediaIds).forEach((value) => {
-      Drupal.MediaLibrary.currentSelection.push(value);
-    });
-  };
-
-  /**
-   * Load media library content through AJAX.
-   *
-   * Standard AJAX links (using the 'use-ajax' class) replace the entire library
-   * dialog. When navigating to a media type through the vertical tabs, we only
-   * want to load the changed library content. This is not only more efficient,
-   * but also provides a more accessible user experience for screen readers.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to vertical tabs in the media library.
-   *
-   * @todo Remove when the AJAX system adds support for replacing a specific
-   *   selector via a link.
-   *   https://www.drupal.org/project/drupal/issues/3026636
-   */
-  Drupal.behaviors.MediaLibraryTabs = {
-    attach(context) {
-      const $menu = $('.js-media-library-menu');
-      $(once('media-library-menu-item', $menu.find('a')))
-        .on('keypress', (e) => {
-          // The AJAX link has the button role, so we need to make sure the link
-          // is also triggered when pressing the spacebar.
-          if (e.which === 32) {
-            e.preventDefault();
-            e.stopPropagation();
-            $(e.currentTarget).trigger('click');
-          }
-        })
-        .on('click', (e) => {
-          e.preventDefault();
-          e.stopPropagation();
-
-          // Replace the library content.
-          const ajaxObject = Drupal.ajax({
-            wrapper: 'media-library-content',
-            url: e.currentTarget.href,
-            dialogType: 'ajax',
-            progress: {
-              type: 'fullscreen',
-              message: Drupal.t('Please wait...'),
-            },
-          });
-
-          // Override the AJAX success callback to shift focus to the media
-          // library content.
-          ajaxObject.success = function (response, status) {
-            return Promise.resolve(
-              Drupal.Ajax.prototype.success.call(ajaxObject, response, status),
-            ).then(() => {
-              // Set focus to the first tabbable element in the media library
-              // content.
-              const mediaLibraryContent = document.getElementById(
-                'media-library-content',
-              );
-              if (mediaLibraryContent) {
-                const tabbableContent = tabbable(mediaLibraryContent);
-                if (tabbableContent.length) {
-                  tabbableContent[0].focus();
-                }
-              }
-            });
-          };
-          ajaxObject.execute();
-
-          // Set the selected tab.
-          $menu.find('.active-tab').remove();
-          $menu.find('a').removeClass('active');
-          $(e.currentTarget)
-            .addClass('active')
-            .html(
-              Drupal.t(
-                '<span class="visually-hidden">Show </span>@title<span class="visually-hidden"> media</span><span class="active-tab visually-hidden"> (selected)</span>',
-                { '@title': $(e.currentTarget).data('title') },
-              ),
-            );
-
-          // Announce the updated content.
-          Drupal.announce(
-            Drupal.t('Showing @title media.', {
-              '@title': $(e.currentTarget).data('title'),
-            }),
-          );
-        });
-    },
-  };
-
-  /**
-   * Load media library displays through AJAX.
-   *
-   * Standard AJAX links (using the 'use-ajax' class) replace the entire library
-   * dialog. When navigating to a media library views display, we only want to
-   * load the changed views display content. This is not only more efficient,
-   * but also provides a more accessible user experience for screen readers.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to vertical tabs in the media library.
-   *
-   * @todo Remove when the AJAX system adds support for replacing a specific
-   *   selector via a link.
-   *   https://www.drupal.org/project/drupal/issues/3026636
-   */
-  Drupal.behaviors.MediaLibraryViewsDisplay = {
-    attach(context) {
-      const $view = $(context).hasClass('.js-media-library-view')
-        ? $(context)
-        : $('.js-media-library-view', context);
-
-      // Add a class to the view to allow it to be replaced via AJAX.
-      // @todo Remove the custom ID when the AJAX system allows replacing
-      //    elements by selector.
-      //    https://www.drupal.org/project/drupal/issues/2821793
-      $view
-        .closest('.views-element-container')
-        .attr('id', 'media-library-view');
-
-      // We would ideally use a generic JavaScript specific class to detect the
-      // display links. Since we have no good way of altering display links yet,
-      // this is the best we can do for now.
-      // @todo Add media library specific classes and data attributes to the
-      //    media library display links when we can alter display links.
-      //    https://www.drupal.org/project/drupal/issues/3036694
-      $(
-        once(
-          'media-library-views-display-link',
-          '.views-display-link-widget, .views-display-link-widget_table',
-          context,
-        ),
-      ).on('click', (e) => {
-        e.preventDefault();
-        e.stopPropagation();
-
-        const $link = $(e.currentTarget);
-
-        // Add a loading and display announcement for screen reader users.
-        let loadingAnnouncement = '';
-        let displayAnnouncement = '';
-        let focusSelector = '';
-        if ($link.hasClass('views-display-link-widget')) {
-          loadingAnnouncement = Drupal.t('Loading grid view.');
-          displayAnnouncement = Drupal.t('Changed to grid view.');
-          focusSelector = '.views-display-link-widget';
-        } else if ($link.hasClass('views-display-link-widget_table')) {
-          loadingAnnouncement = Drupal.t('Loading table view.');
-          displayAnnouncement = Drupal.t('Changed to table view.');
-          focusSelector = '.views-display-link-widget_table';
-        }
-
-        // Replace the library view.
-        const ajaxObject = Drupal.ajax({
-          wrapper: 'media-library-view',
-          url: e.currentTarget.href,
-          dialogType: 'ajax',
-          progress: {
-            type: 'fullscreen',
-            message: loadingAnnouncement || Drupal.t('Please wait...'),
-          },
-        });
-
-        // Override the AJAX success callback to announce the updated content
-        // to screen readers.
-        if (displayAnnouncement || focusSelector) {
-          const success = ajaxObject.success;
-          ajaxObject.success = function (response, status) {
-            success.bind(this)(response, status);
-            // The AJAX link replaces the whole view, including the clicked
-            // link. Move the focus back to the clicked link when the view is
-            // replaced.
-            if (focusSelector) {
-              $(focusSelector).focus();
-            }
-            // Announce the new view is loaded to screen readers.
-            if (displayAnnouncement) {
-              Drupal.announce(displayAnnouncement);
-            }
-          };
-        }
-
-        ajaxObject.execute();
-
-        // Announce the new view is being loaded to screen readers.
-        // @todo Replace custom announcement when
-        //   https://www.drupal.org/project/drupal/issues/2973140 is in.
-        if (loadingAnnouncement) {
-          Drupal.announce(loadingAnnouncement);
-        }
-      });
-    },
-  };
-
-  /**
-   * Update the media library selection when loaded or media items are selected.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to select media items.
-   */
-  Drupal.behaviors.MediaLibraryItemSelection = {
-    attach(context, settings) {
-      const $form = $(
-        '.js-media-library-views-form, .js-media-library-add-form',
-        context,
-      );
-      const currentSelection = Drupal.MediaLibrary.currentSelection;
-
-      if (!$form.length) {
-        return;
-      }
-
-      const $mediaItems = $(
-        '.js-media-library-item input[type="checkbox"]',
-        $form,
-      );
-
-      /**
-       * Disable media items.
-       *
-       * @param {jQuery} $items
-       *   A jQuery object representing the media items that should be disabled.
-       */
-      function disableItems($items) {
-        $items
-          .prop('disabled', true)
-          .closest('.js-media-library-item')
-          .addClass('media-library-item--disabled');
-      }
-
-      /**
-       * Enable media items.
-       *
-       * @param {jQuery} $items
-       *   A jQuery object representing the media items that should be enabled.
-       */
-      function enableItems($items) {
-        $items
-          .prop('disabled', false)
-          .closest('.js-media-library-item')
-          .removeClass('media-library-item--disabled');
-      }
-
-      /**
-       * Update the number of selected items in the button pane.
-       *
-       * @param {number} remaining
-       *   The number of remaining slots.
-       */
-      function updateSelectionCount(remaining) {
-        // When the remaining number of items is a negative number, we allow an
-        // unlimited number of items. In that case we don't want to show the
-        // number of remaining slots.
-        const selectItemsText =
-          remaining < 0
-            ? Drupal.formatPlural(
-                currentSelection.length,
-                '1 item selected',
-                '@count items selected',
-              )
-            : Drupal.formatPlural(
-                remaining,
-                '@selected of @count item selected',
-                '@selected of @count items selected',
-                {
-                  '@selected': currentSelection.length,
-                },
-              );
-        // The selected count div could have been created outside of the
-        // context, so we unfortunately can't use context here.
-        $('.js-media-library-selected-count').html(selectItemsText);
-      }
-
-      // Update the selection array and the hidden form field when a media item
-      // is selected.
-      $(once('media-item-change', $mediaItems)).on('change', (e) => {
-        const id = e.currentTarget.value;
-
-        // Update the selection.
-        const position = currentSelection.indexOf(id);
-        if (e.currentTarget.checked) {
-          // Check if the ID is not already in the selection and add if needed.
-          if (position === -1) {
-            currentSelection.push(id);
-          }
-        } else if (position !== -1) {
-          // Remove the ID when it is in the current selection.
-          currentSelection.splice(position, 1);
-        }
-
-        const mediaLibraryModalSelection = document.querySelector(
-          '#media-library-modal-selection',
-        );
-
-        if (mediaLibraryModalSelection) {
-          // Set the selection in the hidden form element.
-          mediaLibraryModalSelection.value = currentSelection.join();
-          $(mediaLibraryModalSelection).trigger('change');
-        }
-
-        // Set the selection in the media library add form. Since the form is
-        // not necessarily loaded within the same context, we can't use the
-        // context here.
-        document
-          .querySelectorAll('.js-media-library-add-form-current-selection')
-          .forEach((item) => {
-            item.value = currentSelection.join();
-          });
-      });
-
-      // The hidden selection form field changes when the selection is updated.
-      $(
-        once(
-          'media-library-selection-change',
-          $form.find('#media-library-modal-selection'),
-        ),
-      ).on('change', (e) => {
-        updateSelectionCount(settings.media_library.selection_remaining);
-
-        // Prevent users from selecting more items than allowed.
-        if (
-          currentSelection.length === settings.media_library.selection_remaining
-        ) {
-          disableItems($mediaItems.not(':checked'));
-          enableItems($mediaItems.filter(':checked'));
-        } else {
-          enableItems($mediaItems);
-        }
-      });
-
-      // Apply the current selection to the media library view. Changing the
-      // checkbox values triggers the change event for the media items. The
-      // change event handles updating the hidden selection field for the form.
-      currentSelection.forEach((value) => {
-        $form
-          .find(`input[type="checkbox"][value="${value}"]`)
-          .prop('checked', true)
-          .trigger('change');
-      });
-
-      // Add the selection count to the button pane when a media library dialog
-      // is created.
-      if (!once('media-library-selection-info', 'html').length) {
-        return;
-      }
-      $(window).on('dialog:aftercreate', () => {
-        // Since the dialog HTML is not part of the context, we can't use
-        // context here.
-        const $buttonPane = $(
-          '.media-library-widget-modal .ui-dialog-buttonpane',
-        );
-        if (!$buttonPane.length) {
-          return;
-        }
-        $buttonPane.append(Drupal.theme('mediaLibrarySelectionCount'));
-        updateSelectionCount(settings.media_library.selection_remaining);
-      });
-    },
-  };
-
-  /**
-   * Clear the current selection.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to clear the selection when the library modal closes.
-   */
-  Drupal.behaviors.MediaLibraryModalClearSelection = {
-    attach() {
-      if (!once('media-library-clear-selection', 'html').length) {
-        return;
-      }
-      $(window).on('dialog:afterclose', () => {
-        Drupal.MediaLibrary.currentSelection = [];
-      });
-    },
-  };
-
-  /**
-   * Theme function for the selection count.
-   *
-   * @return {string}
-   *   The corresponding HTML.
-   */
-  Drupal.theme.mediaLibrarySelectionCount = function () {
-    return `<div class="media-library-selected-count js-media-library-selected-count" role="status" aria-live="polite" aria-atomic="true"></div>`;
-  };
-})(jQuery, Drupal, window, window.tabbable);
diff --git a/core/modules/media_library/js/media_library.ui.js b/core/modules/media_library/js/media_library.ui.js
index b7d5c61386e0..4e5529dde854 100644
--- a/core/modules/media_library/js/media_library.ui.js
+++ b/core/modules/media_library/js/media_library.ui.js
@@ -1,85 +1,181 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(($, Drupal, window, _ref) => {
-  let {
-    tabbable
-  } = _ref;
+ * @file media_library.ui.js
+ */
+(($, Drupal, window, { tabbable }) => {
+  /**
+   * Wrapper object for the current state of the media library.
+   */
   Drupal.MediaLibrary = {
-    currentSelection: []
+    /**
+     * When a user interacts with the media library we want the selection to
+     * persist as long as the media library modal is opened. We temporarily
+     * store the selected items while the user filters the media library view or
+     * navigates to different tabs.
+     */
+    currentSelection: [],
   };
 
-  Drupal.AjaxCommands.prototype.updateMediaLibrarySelection = function (ajax, response, status) {
-    Object.values(response.mediaIds).forEach(value => {
+  /**
+   * Command to update the current media library selection.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   The Drupal Ajax object.
+   * @param {object} response
+   *   Object holding the server response.
+   * @param {number} [status]
+   *   The HTTP status code.
+   */
+  Drupal.AjaxCommands.prototype.updateMediaLibrarySelection = function (
+    ajax,
+    response,
+    status,
+  ) {
+    Object.values(response.mediaIds).forEach((value) => {
       Drupal.MediaLibrary.currentSelection.push(value);
     });
   };
 
+  /**
+   * Load media library content through AJAX.
+   *
+   * Standard AJAX links (using the 'use-ajax' class) replace the entire library
+   * dialog. When navigating to a media type through the vertical tabs, we only
+   * want to load the changed library content. This is not only more efficient,
+   * but also provides a more accessible user experience for screen readers.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to vertical tabs in the media library.
+   *
+   * @todo Remove when the AJAX system adds support for replacing a specific
+   *   selector via a link.
+   *   https://www.drupal.org/project/drupal/issues/3026636
+   */
   Drupal.behaviors.MediaLibraryTabs = {
     attach(context) {
       const $menu = $('.js-media-library-menu');
-      $(once('media-library-menu-item', $menu.find('a'))).on('keypress', e => {
-        if (e.which === 32) {
+      $(once('media-library-menu-item', $menu.find('a')))
+        .on('keypress', (e) => {
+          // The AJAX link has the button role, so we need to make sure the link
+          // is also triggered when pressing the spacebar.
+          if (e.which === 32) {
+            e.preventDefault();
+            e.stopPropagation();
+            $(e.currentTarget).trigger('click');
+          }
+        })
+        .on('click', (e) => {
           e.preventDefault();
           e.stopPropagation();
-          $(e.currentTarget).trigger('click');
-        }
-      }).on('click', e => {
-        e.preventDefault();
-        e.stopPropagation();
-        const ajaxObject = Drupal.ajax({
-          wrapper: 'media-library-content',
-          url: e.currentTarget.href,
-          dialogType: 'ajax',
-          progress: {
-            type: 'fullscreen',
-            message: Drupal.t('Please wait...')
-          }
-        });
-
-        ajaxObject.success = function (response, status) {
-          return Promise.resolve(Drupal.Ajax.prototype.success.call(ajaxObject, response, status)).then(() => {
-            const mediaLibraryContent = document.getElementById('media-library-content');
 
-            if (mediaLibraryContent) {
-              const tabbableContent = tabbable(mediaLibraryContent);
-
-              if (tabbableContent.length) {
-                tabbableContent[0].focus();
-              }
-            }
+          // Replace the library content.
+          const ajaxObject = Drupal.ajax({
+            wrapper: 'media-library-content',
+            url: e.currentTarget.href,
+            dialogType: 'ajax',
+            progress: {
+              type: 'fullscreen',
+              message: Drupal.t('Please wait...'),
+            },
           });
-        };
-
-        ajaxObject.execute();
-        $menu.find('.active-tab').remove();
-        $menu.find('a').removeClass('active');
-        $(e.currentTarget).addClass('active').html(Drupal.t('<span class="visually-hidden">Show </span>@title<span class="visually-hidden"> media</span><span class="active-tab visually-hidden"> (selected)</span>', {
-          '@title': $(e.currentTarget).data('title')
-        }));
-        Drupal.announce(Drupal.t('Showing @title media.', {
-          '@title': $(e.currentTarget).data('title')
-        }));
-      });
-    }
 
+          // Override the AJAX success callback to shift focus to the media
+          // library content.
+          ajaxObject.success = function (response, status) {
+            return Promise.resolve(
+              Drupal.Ajax.prototype.success.call(ajaxObject, response, status),
+            ).then(() => {
+              // Set focus to the first tabbable element in the media library
+              // content.
+              const mediaLibraryContent = document.getElementById(
+                'media-library-content',
+              );
+              if (mediaLibraryContent) {
+                const tabbableContent = tabbable(mediaLibraryContent);
+                if (tabbableContent.length) {
+                  tabbableContent[0].focus();
+                }
+              }
+            });
+          };
+          ajaxObject.execute();
+
+          // Set the selected tab.
+          $menu.find('.active-tab').remove();
+          $menu.find('a').removeClass('active');
+          $(e.currentTarget)
+            .addClass('active')
+            .html(
+              Drupal.t(
+                '<span class="visually-hidden">Show </span>@title<span class="visually-hidden"> media</span><span class="active-tab visually-hidden"> (selected)</span>',
+                { '@title': $(e.currentTarget).data('title') },
+              ),
+            );
+
+          // Announce the updated content.
+          Drupal.announce(
+            Drupal.t('Showing @title media.', {
+              '@title': $(e.currentTarget).data('title'),
+            }),
+          );
+        });
+    },
   };
+
+  /**
+   * Load media library displays through AJAX.
+   *
+   * Standard AJAX links (using the 'use-ajax' class) replace the entire library
+   * dialog. When navigating to a media library views display, we only want to
+   * load the changed views display content. This is not only more efficient,
+   * but also provides a more accessible user experience for screen readers.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to vertical tabs in the media library.
+   *
+   * @todo Remove when the AJAX system adds support for replacing a specific
+   *   selector via a link.
+   *   https://www.drupal.org/project/drupal/issues/3026636
+   */
   Drupal.behaviors.MediaLibraryViewsDisplay = {
     attach(context) {
-      const $view = $(context).hasClass('.js-media-library-view') ? $(context) : $('.js-media-library-view', context);
-      $view.closest('.views-element-container').attr('id', 'media-library-view');
-      $(once('media-library-views-display-link', '.views-display-link-widget, .views-display-link-widget_table', context)).on('click', e => {
+      const $view = $(context).hasClass('.js-media-library-view')
+        ? $(context)
+        : $('.js-media-library-view', context);
+
+      // Add a class to the view to allow it to be replaced via AJAX.
+      // @todo Remove the custom ID when the AJAX system allows replacing
+      //    elements by selector.
+      //    https://www.drupal.org/project/drupal/issues/2821793
+      $view
+        .closest('.views-element-container')
+        .attr('id', 'media-library-view');
+
+      // We would ideally use a generic JavaScript specific class to detect the
+      // display links. Since we have no good way of altering display links yet,
+      // this is the best we can do for now.
+      // @todo Add media library specific classes and data attributes to the
+      //    media library display links when we can alter display links.
+      //    https://www.drupal.org/project/drupal/issues/3036694
+      $(
+        once(
+          'media-library-views-display-link',
+          '.views-display-link-widget, .views-display-link-widget_table',
+          context,
+        ),
+      ).on('click', (e) => {
         e.preventDefault();
         e.stopPropagation();
+
         const $link = $(e.currentTarget);
+
+        // Add a loading and display announcement for screen reader users.
         let loadingAnnouncement = '';
         let displayAnnouncement = '';
         let focusSelector = '';
-
         if ($link.hasClass('views-display-link-widget')) {
           loadingAnnouncement = Drupal.t('Loading grid view.');
           displayAnnouncement = Drupal.t('Changed to grid view.');
@@ -90,26 +186,30 @@
           focusSelector = '.views-display-link-widget_table';
         }
 
+        // Replace the library view.
         const ajaxObject = Drupal.ajax({
           wrapper: 'media-library-view',
           url: e.currentTarget.href,
           dialogType: 'ajax',
           progress: {
             type: 'fullscreen',
-            message: loadingAnnouncement || Drupal.t('Please wait...')
-          }
+            message: loadingAnnouncement || Drupal.t('Please wait...'),
+          },
         });
 
+        // Override the AJAX success callback to announce the updated content
+        // to screen readers.
         if (displayAnnouncement || focusSelector) {
           const success = ajaxObject.success;
-
           ajaxObject.success = function (response, status) {
             success.bind(this)(response, status);
-
+            // The AJAX link replaces the whole view, including the clicked
+            // link. Move the focus back to the clicked link when the view is
+            // replaced.
             if (focusSelector) {
               $(focusSelector).focus();
             }
-
+            // Announce the new view is loaded to screen readers.
             if (displayAnnouncement) {
               Drupal.announce(displayAnnouncement);
             }
@@ -118,107 +218,210 @@
 
         ajaxObject.execute();
 
+        // Announce the new view is being loaded to screen readers.
+        // @todo Replace custom announcement when
+        //   https://www.drupal.org/project/drupal/issues/2973140 is in.
         if (loadingAnnouncement) {
           Drupal.announce(loadingAnnouncement);
         }
       });
-    }
-
+    },
   };
+
+  /**
+   * Update the media library selection when loaded or media items are selected.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to select media items.
+   */
   Drupal.behaviors.MediaLibraryItemSelection = {
     attach(context, settings) {
-      const $form = $('.js-media-library-views-form, .js-media-library-add-form', context);
+      const $form = $(
+        '.js-media-library-views-form, .js-media-library-add-form',
+        context,
+      );
       const currentSelection = Drupal.MediaLibrary.currentSelection;
 
       if (!$form.length) {
         return;
       }
 
-      const $mediaItems = $('.js-media-library-item input[type="checkbox"]', $form);
-
+      const $mediaItems = $(
+        '.js-media-library-item input[type="checkbox"]',
+        $form,
+      );
+
+      /**
+       * Disable media items.
+       *
+       * @param {jQuery} $items
+       *   A jQuery object representing the media items that should be disabled.
+       */
       function disableItems($items) {
-        $items.prop('disabled', true).closest('.js-media-library-item').addClass('media-library-item--disabled');
+        $items
+          .prop('disabled', true)
+          .closest('.js-media-library-item')
+          .addClass('media-library-item--disabled');
       }
 
+      /**
+       * Enable media items.
+       *
+       * @param {jQuery} $items
+       *   A jQuery object representing the media items that should be enabled.
+       */
       function enableItems($items) {
-        $items.prop('disabled', false).closest('.js-media-library-item').removeClass('media-library-item--disabled');
+        $items
+          .prop('disabled', false)
+          .closest('.js-media-library-item')
+          .removeClass('media-library-item--disabled');
       }
 
+      /**
+       * Update the number of selected items in the button pane.
+       *
+       * @param {number} remaining
+       *   The number of remaining slots.
+       */
       function updateSelectionCount(remaining) {
-        const selectItemsText = remaining < 0 ? Drupal.formatPlural(currentSelection.length, '1 item selected', '@count items selected') : Drupal.formatPlural(remaining, '@selected of @count item selected', '@selected of @count items selected', {
-          '@selected': currentSelection.length
-        });
+        // When the remaining number of items is a negative number, we allow an
+        // unlimited number of items. In that case we don't want to show the
+        // number of remaining slots.
+        const selectItemsText =
+          remaining < 0
+            ? Drupal.formatPlural(
+                currentSelection.length,
+                '1 item selected',
+                '@count items selected',
+              )
+            : Drupal.formatPlural(
+                remaining,
+                '@selected of @count item selected',
+                '@selected of @count items selected',
+                {
+                  '@selected': currentSelection.length,
+                },
+              );
+        // The selected count div could have been created outside of the
+        // context, so we unfortunately can't use context here.
         $('.js-media-library-selected-count').html(selectItemsText);
       }
 
-      $(once('media-item-change', $mediaItems)).on('change', e => {
+      // Update the selection array and the hidden form field when a media item
+      // is selected.
+      $(once('media-item-change', $mediaItems)).on('change', (e) => {
         const id = e.currentTarget.value;
-        const position = currentSelection.indexOf(id);
 
+        // Update the selection.
+        const position = currentSelection.indexOf(id);
         if (e.currentTarget.checked) {
+          // Check if the ID is not already in the selection and add if needed.
           if (position === -1) {
             currentSelection.push(id);
           }
         } else if (position !== -1) {
+          // Remove the ID when it is in the current selection.
           currentSelection.splice(position, 1);
         }
 
-        const mediaLibraryModalSelection = document.querySelector('#media-library-modal-selection');
+        const mediaLibraryModalSelection = document.querySelector(
+          '#media-library-modal-selection',
+        );
 
         if (mediaLibraryModalSelection) {
+          // Set the selection in the hidden form element.
           mediaLibraryModalSelection.value = currentSelection.join();
           $(mediaLibraryModalSelection).trigger('change');
         }
 
-        document.querySelectorAll('.js-media-library-add-form-current-selection').forEach(item => {
-          item.value = currentSelection.join();
-        });
+        // Set the selection in the media library add form. Since the form is
+        // not necessarily loaded within the same context, we can't use the
+        // context here.
+        document
+          .querySelectorAll('.js-media-library-add-form-current-selection')
+          .forEach((item) => {
+            item.value = currentSelection.join();
+          });
       });
-      $(once('media-library-selection-change', $form.find('#media-library-modal-selection'))).on('change', e => {
+
+      // The hidden selection form field changes when the selection is updated.
+      $(
+        once(
+          'media-library-selection-change',
+          $form.find('#media-library-modal-selection'),
+        ),
+      ).on('change', (e) => {
         updateSelectionCount(settings.media_library.selection_remaining);
 
-        if (currentSelection.length === settings.media_library.selection_remaining) {
+        // Prevent users from selecting more items than allowed.
+        if (
+          currentSelection.length === settings.media_library.selection_remaining
+        ) {
           disableItems($mediaItems.not(':checked'));
           enableItems($mediaItems.filter(':checked'));
         } else {
           enableItems($mediaItems);
         }
       });
-      currentSelection.forEach(value => {
-        $form.find(`input[type="checkbox"][value="${value}"]`).prop('checked', true).trigger('change');
+
+      // Apply the current selection to the media library view. Changing the
+      // checkbox values triggers the change event for the media items. The
+      // change event handles updating the hidden selection field for the form.
+      currentSelection.forEach((value) => {
+        $form
+          .find(`input[type="checkbox"][value="${value}"]`)
+          .prop('checked', true)
+          .trigger('change');
       });
 
+      // Add the selection count to the button pane when a media library dialog
+      // is created.
       if (!once('media-library-selection-info', 'html').length) {
         return;
       }
-
       $(window).on('dialog:aftercreate', () => {
-        const $buttonPane = $('.media-library-widget-modal .ui-dialog-buttonpane');
-
+        // Since the dialog HTML is not part of the context, we can't use
+        // context here.
+        const $buttonPane = $(
+          '.media-library-widget-modal .ui-dialog-buttonpane',
+        );
         if (!$buttonPane.length) {
           return;
         }
-
         $buttonPane.append(Drupal.theme('mediaLibrarySelectionCount'));
         updateSelectionCount(settings.media_library.selection_remaining);
       });
-    }
-
+    },
   };
+
+  /**
+   * Clear the current selection.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to clear the selection when the library modal closes.
+   */
   Drupal.behaviors.MediaLibraryModalClearSelection = {
     attach() {
       if (!once('media-library-clear-selection', 'html').length) {
         return;
       }
-
       $(window).on('dialog:afterclose', () => {
         Drupal.MediaLibrary.currentSelection = [];
       });
-    }
-
+    },
   };
 
+  /**
+   * Theme function for the selection count.
+   *
+   * @return {string}
+   *   The corresponding HTML.
+   */
   Drupal.theme.mediaLibrarySelectionCount = function () {
     return `<div class="media-library-selected-count js-media-library-selected-count" role="status" aria-live="polite" aria-atomic="true"></div>`;
   };
-})(jQuery, Drupal, window, window.tabbable);
\ No newline at end of file
+})(jQuery, Drupal, window, window.tabbable);
diff --git a/core/modules/media_library/js/media_library.view.es6.js b/core/modules/media_library/js/media_library.view.es6.js
deleted file mode 100644
index 46a67c901d53..000000000000
--- a/core/modules/media_library/js/media_library.view.es6.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @file media_library.view.es6.js
- */
-(($, Drupal) => {
-  /**
-   * Adds checkbox to select all items in the library.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to select all media items.
-   */
-  Drupal.behaviors.MediaLibrarySelectAll = {
-    attach(context) {
-      const $view = $(
-        once(
-          'media-library-select-all',
-          '.js-media-library-view[data-view-display-id="page"]',
-          context,
-        ),
-      );
-      if ($view.length && $view.find('.js-media-library-item').length) {
-        const $checkbox = $(Drupal.theme('checkbox')).on(
-          'click',
-          ({ currentTarget }) => {
-            // Toggle all checkboxes.
-            const $checkboxes = $(currentTarget)
-              .closest('.js-media-library-view')
-              .find('.js-media-library-item input[type="checkbox"]');
-            $checkboxes
-              .prop('checked', $(currentTarget).prop('checked'))
-              .trigger('change');
-            // Announce the selection.
-            const announcement = $(currentTarget).prop('checked')
-              ? Drupal.t('All @count items selected', {
-                  '@count': $checkboxes.length,
-                })
-              : Drupal.t('Zero items selected');
-            Drupal.announce(announcement);
-          },
-        );
-        const $label = $('<label class="media-library-select-all"></label>');
-        $label[0].textContent = Drupal.t('Select all media');
-        $label.prepend($checkbox);
-        $view.find('.js-media-library-item').first().before($label);
-      }
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/media_library/js/media_library.view.js b/core/modules/media_library/js/media_library.view.js
index b254b3504196..1e1b220528f8 100644
--- a/core/modules/media_library/js/media_library.view.js
+++ b/core/modules/media_library/js/media_library.view.js
@@ -1,33 +1,49 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * @file media_library.view.js
+ */
 (($, Drupal) => {
+  /**
+   * Adds checkbox to select all items in the library.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to select all media items.
+   */
   Drupal.behaviors.MediaLibrarySelectAll = {
     attach(context) {
-      const $view = $(once('media-library-select-all', '.js-media-library-view[data-view-display-id="page"]', context));
-
+      const $view = $(
+        once(
+          'media-library-select-all',
+          '.js-media-library-view[data-view-display-id="page"]',
+          context,
+        ),
+      );
       if ($view.length && $view.find('.js-media-library-item').length) {
-        const $checkbox = $(Drupal.theme('checkbox')).on('click', _ref => {
-          let {
-            currentTarget
-          } = _ref;
-          const $checkboxes = $(currentTarget).closest('.js-media-library-view').find('.js-media-library-item input[type="checkbox"]');
-          $checkboxes.prop('checked', $(currentTarget).prop('checked')).trigger('change');
-          const announcement = $(currentTarget).prop('checked') ? Drupal.t('All @count items selected', {
-            '@count': $checkboxes.length
-          }) : Drupal.t('Zero items selected');
-          Drupal.announce(announcement);
-        });
+        const $checkbox = $(Drupal.theme('checkbox')).on(
+          'click',
+          ({ currentTarget }) => {
+            // Toggle all checkboxes.
+            const $checkboxes = $(currentTarget)
+              .closest('.js-media-library-view')
+              .find('.js-media-library-item input[type="checkbox"]');
+            $checkboxes
+              .prop('checked', $(currentTarget).prop('checked'))
+              .trigger('change');
+            // Announce the selection.
+            const announcement = $(currentTarget).prop('checked')
+              ? Drupal.t('All @count items selected', {
+                  '@count': $checkboxes.length,
+                })
+              : Drupal.t('Zero items selected');
+            Drupal.announce(announcement);
+          },
+        );
         const $label = $('<label class="media-library-select-all"></label>');
         $label[0].textContent = Drupal.t('Select all media');
         $label.prepend($checkbox);
         $view.find('.js-media-library-item').first().before($label);
       }
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/media_library/js/media_library.widget.es6.js b/core/modules/media_library/js/media_library.widget.es6.js
deleted file mode 100644
index afd74d656c96..000000000000
--- a/core/modules/media_library/js/media_library.widget.es6.js
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * @file media_library.widget.es6.js
- */
-(($, Drupal, Sortable) => {
-  /**
-   * Allows users to re-order their selection with drag+drop.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to re-order selected media items.
-   */
-  Drupal.behaviors.MediaLibraryWidgetSortable = {
-    attach(context) {
-      // Allow media items to be re-sorted with drag+drop in the widget.
-      const selection = context.querySelectorAll('.js-media-library-selection');
-      selection.forEach((widget) => {
-        Sortable.create(widget, {
-          draggable: '.js-media-library-item',
-          handle: '.js-media-library-item-preview',
-          onEnd: () => {
-            $(widget)
-              .children()
-              .each((index, child) => {
-                $(child).find('.js-media-library-item-weight')[0].value = index;
-              });
-          },
-        });
-      });
-    },
-  };
-
-  /**
-   * Allows selection order to be set without drag+drop for accessibility.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to toggle the weight field for media items.
-   */
-  Drupal.behaviors.MediaLibraryWidgetToggleWeight = {
-    attach(context) {
-      const strings = {
-        show: Drupal.t('Show media item weights'),
-        hide: Drupal.t('Hide media item weights'),
-      };
-      const mediaLibraryToggle = once(
-        'media-library-toggle',
-        '.js-media-library-widget-toggle-weight',
-        context,
-      );
-      $(mediaLibraryToggle).on('click', (e) => {
-        e.preventDefault();
-        const $target = $(e.currentTarget);
-        e.currentTarget.textContent = $target.hasClass('active')
-          ? strings.show
-          : strings.hide;
-        $target
-          .toggleClass('active')
-          .closest('.js-media-library-widget')
-          .find('.js-media-library-item-weight')
-          .parent()
-          .toggle();
-      });
-      mediaLibraryToggle.forEach((item) => {
-        item.textContent = strings.show;
-      });
-
-      $(once('media-library-toggle', '.js-media-library-item-weight', context))
-        .parent()
-        .hide();
-    },
-  };
-
-  /**
-   * Disable the open button when the user is not allowed to add more items.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to disable the media library open button.
-   */
-  Drupal.behaviors.MediaLibraryWidgetDisableButton = {
-    attach(context) {
-      // When the user returns from the modal to the widget, we want to shift
-      // the focus back to the open button. If the user is not allowed to add
-      // more items, the button needs to be disabled. Since we can't shift the
-      // focus to disabled elements, the focus is set back to the open button
-      // via JavaScript by adding the 'data-disabled-focus' attribute.
-      once(
-        'media-library-disable',
-        '.js-media-library-open-button[data-disabled-focus="true"]',
-        context,
-      ).forEach((button) => {
-        $(button).focus();
-
-        // There is a small delay between the focus set by the browser and the
-        // focus of screen readers. We need to give screen readers time to shift
-        // the focus as well before the button is disabled.
-        setTimeout(() => {
-          $(button).attr('disabled', 'disabled');
-        }, 50);
-      });
-    },
-  };
-})(jQuery, Drupal, Sortable);
diff --git a/core/modules/media_library/js/media_library.widget.js b/core/modules/media_library/js/media_library.widget.js
index 54546dc1409f..b9f5b8a5cb17 100644
--- a/core/modules/media_library/js/media_library.widget.js
+++ b/core/modules/media_library/js/media_library.widget.js
@@ -1,57 +1,106 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * @file media_library.widget.js
+ */
 (($, Drupal, Sortable) => {
+  /**
+   * Allows users to re-order their selection with drag+drop.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to re-order selected media items.
+   */
   Drupal.behaviors.MediaLibraryWidgetSortable = {
     attach(context) {
+      // Allow media items to be re-sorted with drag+drop in the widget.
       const selection = context.querySelectorAll('.js-media-library-selection');
-      selection.forEach(widget => {
+      selection.forEach((widget) => {
         Sortable.create(widget, {
           draggable: '.js-media-library-item',
           handle: '.js-media-library-item-preview',
           onEnd: () => {
-            $(widget).children().each((index, child) => {
-              $(child).find('.js-media-library-item-weight')[0].value = index;
-            });
-          }
+            $(widget)
+              .children()
+              .each((index, child) => {
+                $(child).find('.js-media-library-item-weight')[0].value = index;
+              });
+          },
         });
       });
-    }
-
+    },
   };
+
+  /**
+   * Allows selection order to be set without drag+drop for accessibility.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to toggle the weight field for media items.
+   */
   Drupal.behaviors.MediaLibraryWidgetToggleWeight = {
     attach(context) {
       const strings = {
         show: Drupal.t('Show media item weights'),
-        hide: Drupal.t('Hide media item weights')
+        hide: Drupal.t('Hide media item weights'),
       };
-      const mediaLibraryToggle = once('media-library-toggle', '.js-media-library-widget-toggle-weight', context);
-      $(mediaLibraryToggle).on('click', e => {
+      const mediaLibraryToggle = once(
+        'media-library-toggle',
+        '.js-media-library-widget-toggle-weight',
+        context,
+      );
+      $(mediaLibraryToggle).on('click', (e) => {
         e.preventDefault();
         const $target = $(e.currentTarget);
-        e.currentTarget.textContent = $target.hasClass('active') ? strings.show : strings.hide;
-        $target.toggleClass('active').closest('.js-media-library-widget').find('.js-media-library-item-weight').parent().toggle();
+        e.currentTarget.textContent = $target.hasClass('active')
+          ? strings.show
+          : strings.hide;
+        $target
+          .toggleClass('active')
+          .closest('.js-media-library-widget')
+          .find('.js-media-library-item-weight')
+          .parent()
+          .toggle();
       });
-      mediaLibraryToggle.forEach(item => {
+      mediaLibraryToggle.forEach((item) => {
         item.textContent = strings.show;
       });
-      $(once('media-library-toggle', '.js-media-library-item-weight', context)).parent().hide();
-    }
 
+      $(once('media-library-toggle', '.js-media-library-item-weight', context))
+        .parent()
+        .hide();
+    },
   };
+
+  /**
+   * Disable the open button when the user is not allowed to add more items.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to disable the media library open button.
+   */
   Drupal.behaviors.MediaLibraryWidgetDisableButton = {
     attach(context) {
-      once('media-library-disable', '.js-media-library-open-button[data-disabled-focus="true"]', context).forEach(button => {
+      // When the user returns from the modal to the widget, we want to shift
+      // the focus back to the open button. If the user is not allowed to add
+      // more items, the button needs to be disabled. Since we can't shift the
+      // focus to disabled elements, the focus is set back to the open button
+      // via JavaScript by adding the 'data-disabled-focus' attribute.
+      once(
+        'media-library-disable',
+        '.js-media-library-open-button[data-disabled-focus="true"]',
+        context,
+      ).forEach((button) => {
         $(button).focus();
+
+        // There is a small delay between the focus set by the browser and the
+        // focus of screen readers. We need to give screen readers time to shift
+        // the focus as well before the button is disabled.
         setTimeout(() => {
           $(button).attr('disabled', 'disabled');
         }, 50);
       });
-    }
-
+    },
   };
-})(jQuery, Drupal, Sortable);
\ No newline at end of file
+})(jQuery, Drupal, Sortable);
diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/EntityReferenceWidgetTest.php b/core/modules/media_library/tests/src/FunctionalJavascript/EntityReferenceWidgetTest.php
index 54de6cb25e35..94a0d511fdef 100644
--- a/core/modules/media_library/tests/src/FunctionalJavascript/EntityReferenceWidgetTest.php
+++ b/core/modules/media_library/tests/src/FunctionalJavascript/EntityReferenceWidgetTest.php
@@ -563,7 +563,7 @@ public function testAddAfterReordering(): void {
    * {@inheritdoc}
    */
   protected function sortableUpdate($item, $from, $to = NULL) {
-    // See core/modules/media_library/js/media_library.widget.es6.js.
+    // See core/modules/media_library/js/media_library.widget.js.
     $script = <<<JS
 (function ($) {
     var selection = document.querySelectorAll('.js-media-library-selection');
diff --git a/core/modules/menu_ui/menu_ui.admin.es6.js b/core/modules/menu_ui/menu_ui.admin.es6.js
deleted file mode 100644
index 9507b8d15ec8..000000000000
--- a/core/modules/menu_ui/menu_ui.admin.es6.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * @file
- * Menu UI admin behaviors.
- */
-
-(function ($, Drupal) {
-  /**
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.menuUiChangeParentItems = {
-    attach(context, settings) {
-      const menu = once('menu-parent', '#edit-menu');
-      if (menu.length) {
-        const $menu = $(menu);
-        // Update the list of available parent menu items to match the initial
-        // available menus.
-        Drupal.menuUiUpdateParentList();
-
-        // Update list of available parent menu items.
-        $menu.on('change', 'input', Drupal.menuUiUpdateParentList);
-      }
-    },
-  };
-
-  /**
-   * Function to set the options of the menu parent item dropdown.
-   */
-  Drupal.menuUiUpdateParentList = function () {
-    const $menu = $('#edit-menu');
-    const values = [];
-
-    $menu.find('input:checked').each(function () {
-      // Get the names of all checked menus.
-      values.push(Drupal.checkPlain(this.value));
-    });
-
-    $.ajax({
-      url: `${window.location.protocol}//${window.location.host}${Drupal.url(
-        'admin/structure/menu/parents',
-      )}`,
-      type: 'POST',
-      data: { 'menus[]': values },
-      dataType: 'json',
-      success(options) {
-        const $select = $('#edit-menu-parent');
-        // Save key of last selected element.
-        const selected = $select[0].value;
-        // Remove all existing options from dropdown.
-        $select.children().remove();
-        // Add new options to dropdown. Keep a count of options for testing later.
-        let totalOptions = 0;
-        Object.keys(options || {}).forEach((machineName) => {
-          const selectContents = document.createElement('option');
-          selectContents.selected = machineName === selected;
-          selectContents.value = machineName;
-          selectContents.textContent = options[machineName];
-          $select.append(selectContents);
-          totalOptions++;
-        });
-
-        // Hide the parent options if there are no options for it.
-        $select
-          .closest('div')
-          .toggle(totalOptions > 0)
-          .attr('hidden', totalOptions === 0);
-      },
-    });
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/menu_ui/menu_ui.admin.js b/core/modules/menu_ui/menu_ui.admin.js
index a590def3d337..9507b8d15ec8 100644
--- a/core/modules/menu_ui/menu_ui.admin.js
+++ b/core/modules/menu_ui/menu_ui.admin.js
@@ -1,44 +1,56 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Menu UI admin behaviors.
+ */
 
 (function ($, Drupal) {
+  /**
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.menuUiChangeParentItems = {
     attach(context, settings) {
       const menu = once('menu-parent', '#edit-menu');
-
       if (menu.length) {
         const $menu = $(menu);
+        // Update the list of available parent menu items to match the initial
+        // available menus.
         Drupal.menuUiUpdateParentList();
+
+        // Update list of available parent menu items.
         $menu.on('change', 'input', Drupal.menuUiUpdateParentList);
       }
-    }
-
+    },
   };
 
+  /**
+   * Function to set the options of the menu parent item dropdown.
+   */
   Drupal.menuUiUpdateParentList = function () {
     const $menu = $('#edit-menu');
     const values = [];
+
     $menu.find('input:checked').each(function () {
+      // Get the names of all checked menus.
       values.push(Drupal.checkPlain(this.value));
     });
+
     $.ajax({
-      url: `${window.location.protocol}//${window.location.host}${Drupal.url('admin/structure/menu/parents')}`,
+      url: `${window.location.protocol}//${window.location.host}${Drupal.url(
+        'admin/structure/menu/parents',
+      )}`,
       type: 'POST',
-      data: {
-        'menus[]': values
-      },
+      data: { 'menus[]': values },
       dataType: 'json',
-
       success(options) {
         const $select = $('#edit-menu-parent');
+        // Save key of last selected element.
         const selected = $select[0].value;
+        // Remove all existing options from dropdown.
         $select.children().remove();
+        // Add new options to dropdown. Keep a count of options for testing later.
         let totalOptions = 0;
-        Object.keys(options || {}).forEach(machineName => {
+        Object.keys(options || {}).forEach((machineName) => {
           const selectContents = document.createElement('option');
           selectContents.selected = machineName === selected;
           selectContents.value = machineName;
@@ -46,9 +58,13 @@
           $select.append(selectContents);
           totalOptions++;
         });
-        $select.closest('div').toggle(totalOptions > 0).attr('hidden', totalOptions === 0);
-      }
 
+        // Hide the parent options if there are no options for it.
+        $select
+          .closest('div')
+          .toggle(totalOptions > 0)
+          .attr('hidden', totalOptions === 0);
+      },
     });
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/menu_ui/menu_ui.es6.js b/core/modules/menu_ui/menu_ui.es6.js
deleted file mode 100644
index 51c417cab14e..000000000000
--- a/core/modules/menu_ui/menu_ui.es6.js
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * @file
- * Menu UI behaviors.
- */
-
-(function ($, Drupal) {
-  /**
-   * Set a summary on the menu link form.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Find the form and call `drupalSetSummary` on it.
-   */
-  Drupal.behaviors.menuUiDetailsSummaries = {
-    attach(context) {
-      $(context)
-        .find('.menu-link-form')
-        .drupalSetSummary((context) => {
-          const $context = $(context);
-          if (
-            $context.find('.js-form-item-menu-enabled input').is(':checked')
-          ) {
-            return Drupal.checkPlain(
-              $context.find('.js-form-item-menu-title input')[0].value,
-            );
-          }
-
-          return Drupal.t('Not in menu');
-        });
-    },
-  };
-
-  /**
-   * Automatically fill in a menu link title, if possible.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches change and keyup behavior for automatically filling out menu
-   *   link titles.
-   */
-  Drupal.behaviors.menuUiLinkAutomaticTitle = {
-    attach(context) {
-      const $context = $(context);
-      $context.find('.menu-link-form').each(function () {
-        const $this = $(this);
-        // Try to find menu settings widget elements as well as a 'title' field
-        // in the form, but play nicely with user permissions and form
-        // alterations.
-        const $checkbox = $this.find('.js-form-item-menu-enabled input');
-        const $linkTitle = $context.find('.js-form-item-menu-title input');
-        const $title = $this
-          .closest('form')
-          .find('.js-form-item-title-0-value input');
-        // Bail out if we do not have all required fields.
-        if (!($checkbox.length && $linkTitle.length && $title.length)) {
-          return;
-        }
-        // If there is a link title already, mark it as overridden. The user
-        // expects that toggling the checkbox twice will take over the node's
-        // title.
-        if ($checkbox.is(':checked') && $linkTitle[0].value.length) {
-          $linkTitle.data('menuLinkAutomaticTitleOverridden', true);
-        }
-        // Whenever the value is changed manually, disable this behavior.
-        $linkTitle.on('keyup', () => {
-          $linkTitle.data('menuLinkAutomaticTitleOverridden', true);
-        });
-        // Global trigger on checkbox (do not fill-in a value when disabled).
-        $checkbox.on('change', () => {
-          if ($checkbox.is(':checked')) {
-            if (!$linkTitle.data('menuLinkAutomaticTitleOverridden')) {
-              $linkTitle[0].value = $title[0].value;
-            }
-          } else {
-            $linkTitle[0].value = '';
-            $linkTitle.removeData('menuLinkAutomaticTitleOverridden');
-          }
-          $checkbox.closest('.vertical-tabs-pane').trigger('summaryUpdated');
-          $checkbox.trigger('formUpdated');
-        });
-        // Take over any title change.
-        $title.on('keyup', () => {
-          if (
-            !$linkTitle.data('menuLinkAutomaticTitleOverridden') &&
-            $checkbox.is(':checked')
-          ) {
-            $linkTitle[0].value = $title[0].value;
-            $linkTitle.trigger('formUpdated');
-          }
-        });
-      });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/menu_ui/menu_ui.js b/core/modules/menu_ui/menu_ui.js
index 58d32d44c78c..51c417cab14e 100644
--- a/core/modules/menu_ui/menu_ui.js
+++ b/core/modules/menu_ui/menu_ui.js
@@ -1,45 +1,73 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Menu UI behaviors.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Set a summary on the menu link form.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Find the form and call `drupalSetSummary` on it.
+   */
   Drupal.behaviors.menuUiDetailsSummaries = {
     attach(context) {
-      $(context).find('.menu-link-form').drupalSetSummary(context => {
-        const $context = $(context);
-
-        if ($context.find('.js-form-item-menu-enabled input').is(':checked')) {
-          return Drupal.checkPlain($context.find('.js-form-item-menu-title input')[0].value);
-        }
-
-        return Drupal.t('Not in menu');
-      });
-    }
+      $(context)
+        .find('.menu-link-form')
+        .drupalSetSummary((context) => {
+          const $context = $(context);
+          if (
+            $context.find('.js-form-item-menu-enabled input').is(':checked')
+          ) {
+            return Drupal.checkPlain(
+              $context.find('.js-form-item-menu-title input')[0].value,
+            );
+          }
 
+          return Drupal.t('Not in menu');
+        });
+    },
   };
+
+  /**
+   * Automatically fill in a menu link title, if possible.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches change and keyup behavior for automatically filling out menu
+   *   link titles.
+   */
   Drupal.behaviors.menuUiLinkAutomaticTitle = {
     attach(context) {
       const $context = $(context);
       $context.find('.menu-link-form').each(function () {
         const $this = $(this);
+        // Try to find menu settings widget elements as well as a 'title' field
+        // in the form, but play nicely with user permissions and form
+        // alterations.
         const $checkbox = $this.find('.js-form-item-menu-enabled input');
         const $linkTitle = $context.find('.js-form-item-menu-title input');
-        const $title = $this.closest('form').find('.js-form-item-title-0-value input');
-
+        const $title = $this
+          .closest('form')
+          .find('.js-form-item-title-0-value input');
+        // Bail out if we do not have all required fields.
         if (!($checkbox.length && $linkTitle.length && $title.length)) {
           return;
         }
-
+        // If there is a link title already, mark it as overridden. The user
+        // expects that toggling the checkbox twice will take over the node's
+        // title.
         if ($checkbox.is(':checked') && $linkTitle[0].value.length) {
           $linkTitle.data('menuLinkAutomaticTitleOverridden', true);
         }
-
+        // Whenever the value is changed manually, disable this behavior.
         $linkTitle.on('keyup', () => {
           $linkTitle.data('menuLinkAutomaticTitleOverridden', true);
         });
+        // Global trigger on checkbox (do not fill-in a value when disabled).
         $checkbox.on('change', () => {
           if ($checkbox.is(':checked')) {
             if (!$linkTitle.data('menuLinkAutomaticTitleOverridden')) {
@@ -49,18 +77,20 @@
             $linkTitle[0].value = '';
             $linkTitle.removeData('menuLinkAutomaticTitleOverridden');
           }
-
           $checkbox.closest('.vertical-tabs-pane').trigger('summaryUpdated');
           $checkbox.trigger('formUpdated');
         });
+        // Take over any title change.
         $title.on('keyup', () => {
-          if (!$linkTitle.data('menuLinkAutomaticTitleOverridden') && $checkbox.is(':checked')) {
+          if (
+            !$linkTitle.data('menuLinkAutomaticTitleOverridden') &&
+            $checkbox.is(':checked')
+          ) {
             $linkTitle[0].value = $title[0].value;
             $linkTitle.trigger('formUpdated');
           }
         });
       });
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/node/content_types.es6.js b/core/modules/node/content_types.es6.js
deleted file mode 100644
index b7650d1ef346..000000000000
--- a/core/modules/node/content_types.es6.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * @file
- * JavaScript for the node content editing form.
- */
-
-(function ($, Drupal) {
-  /**
-   * Behaviors for setting summaries on content type form.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches summary behaviors on content type edit forms.
-   */
-  Drupal.behaviors.contentTypes = {
-    attach(context) {
-      const $context = $(context);
-      // Provide the vertical tab summaries.
-      $context.find('#edit-submission').drupalSetSummary((context) => {
-        const vals = [];
-        vals.push(
-          Drupal.checkPlain($(context).find('#edit-title-label')[0].value) ||
-            Drupal.t('Requires a title'),
-        );
-        return vals.join(', ');
-      });
-      $context.find('#edit-workflow').drupalSetSummary((context) => {
-        const vals = [];
-        $(context)
-          .find('input[name^="options"]:checked')
-          .next('label')
-          .each(function () {
-            vals.push(Drupal.checkPlain(this.textContent));
-          });
-        if (!$(context).find('#edit-options-status').is(':checked')) {
-          vals.unshift(Drupal.t('Not published'));
-        }
-        return vals.join(', ');
-      });
-      $('#edit-language', context).drupalSetSummary((context) => {
-        const vals = [];
-
-        vals.push(
-          $(
-            '.js-form-item-language-configuration-langcode select option:selected',
-            context,
-          )[0].textContent,
-        );
-
-        $('input:checked', context)
-          .next('label')
-          .each(function () {
-            vals.push(Drupal.checkPlain(this.textContent));
-          });
-
-        return vals.join(', ');
-      });
-      $context.find('#edit-display').drupalSetSummary((context) => {
-        const vals = [];
-        const $editContext = $(context);
-        $editContext
-          .find('input:checked')
-          .next('label')
-          .each(function () {
-            vals.push(Drupal.checkPlain(this.textContent));
-          });
-        if (!$editContext.find('#edit-display-submitted').is(':checked')) {
-          vals.unshift(Drupal.t("Don't display post information"));
-        }
-        return vals.join(', ');
-      });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/node/content_types.js b/core/modules/node/content_types.js
index 5a87bb70b479..b7650d1ef346 100644
--- a/core/modules/node/content_types.js
+++ b/core/modules/node/content_types.js
@@ -1,53 +1,74 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * JavaScript for the node content editing form.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Behaviors for setting summaries on content type form.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches summary behaviors on content type edit forms.
+   */
   Drupal.behaviors.contentTypes = {
     attach(context) {
       const $context = $(context);
-      $context.find('#edit-submission').drupalSetSummary(context => {
+      // Provide the vertical tab summaries.
+      $context.find('#edit-submission').drupalSetSummary((context) => {
         const vals = [];
-        vals.push(Drupal.checkPlain($(context).find('#edit-title-label')[0].value) || Drupal.t('Requires a title'));
+        vals.push(
+          Drupal.checkPlain($(context).find('#edit-title-label')[0].value) ||
+            Drupal.t('Requires a title'),
+        );
         return vals.join(', ');
       });
-      $context.find('#edit-workflow').drupalSetSummary(context => {
+      $context.find('#edit-workflow').drupalSetSummary((context) => {
         const vals = [];
-        $(context).find('input[name^="options"]:checked').next('label').each(function () {
-          vals.push(Drupal.checkPlain(this.textContent));
-        });
-
+        $(context)
+          .find('input[name^="options"]:checked')
+          .next('label')
+          .each(function () {
+            vals.push(Drupal.checkPlain(this.textContent));
+          });
         if (!$(context).find('#edit-options-status').is(':checked')) {
           vals.unshift(Drupal.t('Not published'));
         }
-
         return vals.join(', ');
       });
-      $('#edit-language', context).drupalSetSummary(context => {
+      $('#edit-language', context).drupalSetSummary((context) => {
         const vals = [];
-        vals.push($('.js-form-item-language-configuration-langcode select option:selected', context)[0].textContent);
-        $('input:checked', context).next('label').each(function () {
-          vals.push(Drupal.checkPlain(this.textContent));
-        });
+
+        vals.push(
+          $(
+            '.js-form-item-language-configuration-langcode select option:selected',
+            context,
+          )[0].textContent,
+        );
+
+        $('input:checked', context)
+          .next('label')
+          .each(function () {
+            vals.push(Drupal.checkPlain(this.textContent));
+          });
+
         return vals.join(', ');
       });
-      $context.find('#edit-display').drupalSetSummary(context => {
+      $context.find('#edit-display').drupalSetSummary((context) => {
         const vals = [];
         const $editContext = $(context);
-        $editContext.find('input:checked').next('label').each(function () {
-          vals.push(Drupal.checkPlain(this.textContent));
-        });
-
+        $editContext
+          .find('input:checked')
+          .next('label')
+          .each(function () {
+            vals.push(Drupal.checkPlain(this.textContent));
+          });
         if (!$editContext.find('#edit-display-submitted').is(':checked')) {
           vals.unshift(Drupal.t("Don't display post information"));
         }
-
         return vals.join(', ');
       });
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/node/node.es6.js b/core/modules/node/node.es6.js
deleted file mode 100644
index c9ed55068d32..000000000000
--- a/core/modules/node/node.es6.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * @file
- * Defines JavaScript behaviors for the node module.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Behaviors for tabs in the node edit form.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches summary behavior for tabs in the node edit form.
-   */
-  Drupal.behaviors.nodeDetailsSummaries = {
-    attach(context) {
-      const $context = $(context);
-
-      $context.find('.node-form-author').drupalSetSummary((context) => {
-        const nameElement = context.querySelector('.field--name-uid input');
-        const name = nameElement && nameElement.value;
-        const dateElement = context.querySelector('.field--name-created input');
-        const date = dateElement && dateElement.value;
-
-        if (name && date) {
-          return Drupal.t('By @name on @date', {
-            '@name': name,
-            '@date': date,
-          });
-        }
-        if (name) {
-          return Drupal.t('By @name', { '@name': name });
-        }
-        if (date) {
-          return Drupal.t('Authored on @date', { '@date': date });
-        }
-      });
-
-      $context.find('.node-form-options').drupalSetSummary((context) => {
-        const $optionsContext = $(context);
-        const vals = [];
-
-        if ($optionsContext.find('input').is(':checked')) {
-          $optionsContext
-            .find('input:checked')
-            .next('label')
-            .each(function () {
-              vals.push(Drupal.checkPlain(this.textContent.trim()));
-            });
-          return vals.join(', ');
-        }
-
-        return Drupal.t('Not promoted');
-      });
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/node/node.js b/core/modules/node/node.js
index a92c5bb6f1fd..c9ed55068d32 100644
--- a/core/modules/node/node.js
+++ b/core/modules/node/node.js
@@ -1,15 +1,22 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Defines JavaScript behaviors for the node module.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * Behaviors for tabs in the node edit form.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches summary behavior for tabs in the node edit form.
+   */
   Drupal.behaviors.nodeDetailsSummaries = {
     attach(context) {
       const $context = $(context);
-      $context.find('.node-form-author').drupalSetSummary(context => {
+
+      $context.find('.node-form-author').drupalSetSummary((context) => {
         const nameElement = context.querySelector('.field--name-uid input');
         const name = nameElement && nameElement.value;
         const dateElement = context.querySelector('.field--name-created input');
@@ -18,36 +25,33 @@
         if (name && date) {
           return Drupal.t('By @name on @date', {
             '@name': name,
-            '@date': date
+            '@date': date,
           });
         }
-
         if (name) {
-          return Drupal.t('By @name', {
-            '@name': name
-          });
+          return Drupal.t('By @name', { '@name': name });
         }
-
         if (date) {
-          return Drupal.t('Authored on @date', {
-            '@date': date
-          });
+          return Drupal.t('Authored on @date', { '@date': date });
         }
       });
-      $context.find('.node-form-options').drupalSetSummary(context => {
+
+      $context.find('.node-form-options').drupalSetSummary((context) => {
         const $optionsContext = $(context);
         const vals = [];
 
         if ($optionsContext.find('input').is(':checked')) {
-          $optionsContext.find('input:checked').next('label').each(function () {
-            vals.push(Drupal.checkPlain(this.textContent.trim()));
-          });
+          $optionsContext
+            .find('input:checked')
+            .next('label')
+            .each(function () {
+              vals.push(Drupal.checkPlain(this.textContent.trim()));
+            });
           return vals.join(', ');
         }
 
         return Drupal.t('Not promoted');
       });
-    }
-
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/node/node.preview.es6.js b/core/modules/node/node.preview.es6.js
deleted file mode 100644
index 071d190fd8f3..000000000000
--- a/core/modules/node/node.preview.es6.js
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * @file
- * Preview behaviors.
- */
-
-(function ($, Drupal) {
-  /**
-   * Disables all non-relevant links in node previews.
-   *
-   * Destroys links (except local fragment identifiers such as href="#frag") in
-   * node previews to prevent users from leaving the page.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches confirmation prompt for clicking links in node preview mode.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detaches confirmation prompt for clicking links in node preview mode.
-   */
-  Drupal.behaviors.nodePreviewDestroyLinks = {
-    attach(context) {
-      function clickPreviewModal(event) {
-        // Only confirm leaving previews when left-clicking and user is not
-        // pressing the ALT, CTRL, META (Command key on the Macintosh keyboard)
-        // or SHIFT key.
-        if (
-          event.button === 0 &&
-          !event.altKey &&
-          !event.ctrlKey &&
-          !event.metaKey &&
-          !event.shiftKey
-        ) {
-          event.preventDefault();
-          const $previewDialog = $(
-            `<div>${Drupal.theme('nodePreviewModal')}</div>`,
-          ).appendTo('body');
-          Drupal.dialog($previewDialog, {
-            title: Drupal.t('Leave preview?'),
-            buttons: [
-              {
-                text: Drupal.t('Cancel'),
-                click() {
-                  $(this).dialog('close');
-                },
-              },
-              {
-                text: Drupal.t('Leave preview'),
-                click() {
-                  window.top.location.href = event.target.href;
-                },
-              },
-            ],
-          }).showModal();
-        }
-      }
-
-      if (!context.querySelector('.node-preview-container')) {
-        return;
-      }
-      if (once('node-preview', 'html').length) {
-        $(document).on(
-          'click.preview',
-          'a:not([href^="#"], .node-preview-container a)',
-          clickPreviewModal,
-        );
-      }
-    },
-    detach(context, settings, trigger) {
-      if (trigger === 'unload') {
-        if (
-          context.querySelector('.node-preview-container') &&
-          once.remove('node-preview', 'html').length
-        ) {
-          $(document).off('click.preview');
-        }
-      }
-    },
-  };
-
-  /**
-   * Switch view mode.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches automatic submit on `formUpdated.preview` events.
-   */
-  Drupal.behaviors.nodePreviewSwitchViewMode = {
-    attach(context) {
-      const autosubmit = once(
-        'autosubmit',
-        '[data-drupal-autosubmit]',
-        context,
-      );
-      if (autosubmit.length) {
-        $(autosubmit).on('formUpdated.preview', function () {
-          $(this.form).trigger('submit');
-        });
-      }
-    },
-  };
-
-  /**
-   * Theme function for node preview modal.
-   *
-   * @return {string}
-   *   Markup for the node preview modal.
-   */
-  Drupal.theme.nodePreviewModal = function () {
-    return `<p>${Drupal.t(
-      'Leaving the preview will cause unsaved changes to be lost. Are you sure you want to leave the preview?',
-    )}</p><small class="description">${Drupal.t(
-      'CTRL+Left click will prevent this dialog from showing and proceed to the clicked link.',
-    )}</small>`;
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/node/node.preview.js b/core/modules/node/node.preview.js
index dff9d0984629..071d190fd8f3 100644
--- a/core/modules/node/node.preview.js
+++ b/core/modules/node/node.preview.js
@@ -1,34 +1,55 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Preview behaviors.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Disables all non-relevant links in node previews.
+   *
+   * Destroys links (except local fragment identifiers such as href="#frag") in
+   * node previews to prevent users from leaving the page.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches confirmation prompt for clicking links in node preview mode.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches confirmation prompt for clicking links in node preview mode.
+   */
   Drupal.behaviors.nodePreviewDestroyLinks = {
     attach(context) {
       function clickPreviewModal(event) {
-        if (event.button === 0 && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey) {
+        // Only confirm leaving previews when left-clicking and user is not
+        // pressing the ALT, CTRL, META (Command key on the Macintosh keyboard)
+        // or SHIFT key.
+        if (
+          event.button === 0 &&
+          !event.altKey &&
+          !event.ctrlKey &&
+          !event.metaKey &&
+          !event.shiftKey
+        ) {
           event.preventDefault();
-          const $previewDialog = $(`<div>${Drupal.theme('nodePreviewModal')}</div>`).appendTo('body');
+          const $previewDialog = $(
+            `<div>${Drupal.theme('nodePreviewModal')}</div>`,
+          ).appendTo('body');
           Drupal.dialog($previewDialog, {
             title: Drupal.t('Leave preview?'),
-            buttons: [{
-              text: Drupal.t('Cancel'),
-
-              click() {
-                $(this).dialog('close');
-              }
-
-            }, {
-              text: Drupal.t('Leave preview'),
-
-              click() {
-                window.top.location.href = event.target.href;
-              }
-
-            }]
+            buttons: [
+              {
+                text: Drupal.t('Cancel'),
+                click() {
+                  $(this).dialog('close');
+                },
+              },
+              {
+                text: Drupal.t('Leave preview'),
+                click() {
+                  window.top.location.href = event.target.href;
+                },
+              },
+            ],
           }).showModal();
         }
       }
@@ -36,35 +57,60 @@
       if (!context.querySelector('.node-preview-container')) {
         return;
       }
-
       if (once('node-preview', 'html').length) {
-        $(document).on('click.preview', 'a:not([href^="#"], .node-preview-container a)', clickPreviewModal);
+        $(document).on(
+          'click.preview',
+          'a:not([href^="#"], .node-preview-container a)',
+          clickPreviewModal,
+        );
       }
     },
-
     detach(context, settings, trigger) {
       if (trigger === 'unload') {
-        if (context.querySelector('.node-preview-container') && once.remove('node-preview', 'html').length) {
+        if (
+          context.querySelector('.node-preview-container') &&
+          once.remove('node-preview', 'html').length
+        ) {
           $(document).off('click.preview');
         }
       }
-    }
-
+    },
   };
+
+  /**
+   * Switch view mode.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches automatic submit on `formUpdated.preview` events.
+   */
   Drupal.behaviors.nodePreviewSwitchViewMode = {
     attach(context) {
-      const autosubmit = once('autosubmit', '[data-drupal-autosubmit]', context);
-
+      const autosubmit = once(
+        'autosubmit',
+        '[data-drupal-autosubmit]',
+        context,
+      );
       if (autosubmit.length) {
         $(autosubmit).on('formUpdated.preview', function () {
           $(this.form).trigger('submit');
         });
       }
-    }
-
+    },
   };
 
+  /**
+   * Theme function for node preview modal.
+   *
+   * @return {string}
+   *   Markup for the node preview modal.
+   */
   Drupal.theme.nodePreviewModal = function () {
-    return `<p>${Drupal.t('Leaving the preview will cause unsaved changes to be lost. Are you sure you want to leave the preview?')}</p><small class="description">${Drupal.t('CTRL+Left click will prevent this dialog from showing and proceed to the clicked link.')}</small>`;
+    return `<p>${Drupal.t(
+      'Leaving the preview will cause unsaved changes to be lost. Are you sure you want to leave the preview?',
+    )}</p><small class="description">${Drupal.t(
+      'CTRL+Left click will prevent this dialog from showing and proceed to the clicked link.',
+    )}</small>`;
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/path/path.es6.js b/core/modules/path/path.es6.js
deleted file mode 100644
index 9d55741b78d9..000000000000
--- a/core/modules/path/path.es6.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * @file
- * Attaches behaviors for the Path module.
- */
-(function ($, Drupal) {
-  /**
-   * Behaviors for settings summaries on path edit forms.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches summary behavior on path edit forms.
-   */
-  Drupal.behaviors.pathDetailsSummaries = {
-    attach(context) {
-      $(context)
-        .find('.path-form')
-        .drupalSetSummary((context) => {
-          const pathElement = document.querySelector(
-            '.js-form-item-path-0-alias input',
-          );
-          const path = pathElement && pathElement.value;
-          return path
-            ? Drupal.t('Alias: @alias', { '@alias': path })
-            : Drupal.t('No alias');
-        });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/path/path.js b/core/modules/path/path.js
index b02e559a6767..9d55741b78d9 100644
--- a/core/modules/path/path.js
+++ b/core/modules/path/path.js
@@ -1,21 +1,29 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * @file
+ * Attaches behaviors for the Path module.
+ */
 (function ($, Drupal) {
+  /**
+   * Behaviors for settings summaries on path edit forms.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches summary behavior on path edit forms.
+   */
   Drupal.behaviors.pathDetailsSummaries = {
     attach(context) {
-      $(context).find('.path-form').drupalSetSummary(context => {
-        const pathElement = document.querySelector('.js-form-item-path-0-alias input');
-        const path = pathElement && pathElement.value;
-        return path ? Drupal.t('Alias: @alias', {
-          '@alias': path
-        }) : Drupal.t('No alias');
-      });
-    }
-
+      $(context)
+        .find('.path-form')
+        .drupalSetSummary((context) => {
+          const pathElement = document.querySelector(
+            '.js-form-item-path-0-alias input',
+          );
+          const path = pathElement && pathElement.value;
+          return path
+            ? Drupal.t('Alias: @alias', { '@alias': path })
+            : Drupal.t('No alias');
+        });
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/settings_tray/js/settings_tray.es6.js b/core/modules/settings_tray/js/settings_tray.es6.js
deleted file mode 100644
index 86910eaba19a..000000000000
--- a/core/modules/settings_tray/js/settings_tray.es6.js
+++ /dev/null
@@ -1,260 +0,0 @@
-/**
- * @file
- * Drupal's Settings Tray library.
- *
- * @private
- */
-
-(($, Drupal) => {
-  const blockConfigureSelector = '[data-settings-tray-edit]';
-  const toggleEditSelector = '[data-drupal-settingstray="toggle"]';
-  const itemsToToggleSelector =
-    '[data-off-canvas-main-canvas], #toolbar-bar, [data-drupal-settingstray="editable"] a, [data-drupal-settingstray="editable"] button';
-  const contextualItemsSelector =
-    '[data-contextual-id] a, [data-contextual-id] button';
-
-  /**
-   * Prevent default click events except contextual links.
-   *
-   * In edit mode the default action of click events is suppressed.
-   *
-   * @param {jQuery.Event} event
-   *   The click event.
-   */
-  function preventClick(event) {
-    // Do not prevent contextual links.
-    if ($(event.target).closest('.contextual-links').length) {
-      return;
-    }
-    event.preventDefault();
-  }
-
-  /**
-   * Close any active toolbar tray before entering edit mode.
-   */
-  function closeToolbarTrays() {
-    $(Drupal.toolbar.models.toolbarModel.get('activeTab')).trigger('click');
-  }
-
-  /**
-   * Closes/removes off-canvas.
-   */
-  function closeOffCanvas() {
-    $('.ui-dialog-off-canvas .ui-dialog-titlebar-close').trigger('click');
-  }
-
-  /**
-   * Gets all items that should be toggled with class during edit mode.
-   *
-   * @return {jQuery}
-   *   Items that should be toggled.
-   */
-  function getItemsToToggle() {
-    return $(itemsToToggleSelector).not(contextualItemsSelector);
-  }
-
-  /**
-   * Helper to switch edit mode state.
-   *
-   * @param {boolean} editMode
-   *   True enable edit mode, false disable edit mode.
-   */
-  function setEditModeState(editMode) {
-    if (!document.querySelector('[data-off-canvas-main-canvas]')) {
-      throw new Error(
-        'data-off-canvas-main-canvas is missing from settings-tray-page-wrapper.html.twig',
-      );
-    }
-    editMode = !!editMode;
-    let $editables;
-    const editButton = document.querySelector(toggleEditSelector);
-    // Turn on edit mode.
-    if (editMode) {
-      if (editButton) {
-        editButton.textContent = Drupal.t('Editing');
-      }
-      closeToolbarTrays();
-
-      $editables = $(
-        once('settingstray', '[data-drupal-settingstray="editable"]'),
-      );
-      if ($editables.length) {
-        // Use event capture to prevent clicks on links.
-        document
-          .querySelector('[data-off-canvas-main-canvas]')
-          .addEventListener('click', preventClick, true);
-        /**
-         * When a click occurs try and find the settings-tray edit link
-         * and click it.
-         */
-        $editables
-          .not(contextualItemsSelector)
-          .on('click.settingstray', (e) => {
-            // Contextual links are allowed to function in Edit mode.
-            if (
-              $(e.target).closest('.contextual').length ||
-              !localStorage.getItem('Drupal.contextualToolbar.isViewing')
-            ) {
-              return;
-            }
-            $(e.currentTarget).find(blockConfigureSelector).trigger('click');
-          });
-      }
-    }
-    // Disable edit mode.
-    else {
-      $editables = $(
-        once.remove('settingstray', '[data-drupal-settingstray="editable"]'),
-      );
-      if ($editables.length) {
-        document
-          .querySelector('[data-off-canvas-main-canvas]')
-          .removeEventListener('click', preventClick, true);
-        $editables.off('.settingstray');
-      }
-      if (editButton) {
-        editButton.textContent = Drupal.t('Edit');
-      }
-      closeOffCanvas();
-    }
-    getItemsToToggle().toggleClass('js-settings-tray-edit-mode', editMode);
-    $('.edit-mode-inactive').toggleClass('visually-hidden', editMode);
-  }
-
-  /**
-   * Helper to check the state of the settings-tray mode.
-   *
-   * @todo don't use a class for this.
-   *
-   * @return {boolean}
-   *   State of the settings-tray edit mode.
-   */
-  function isInEditMode() {
-    return $('#toolbar-bar').hasClass('js-settings-tray-edit-mode');
-  }
-
-  /**
-   * Helper to toggle Edit mode.
-   */
-  function toggleEditMode() {
-    setEditModeState(!isInEditMode());
-  }
-
-  /**
-   * Prepares Ajax links to work with off-canvas and Settings Tray module.
-   */
-  function prepareAjaxLinks() {
-    // Find all Ajax instances that use the 'off_canvas' renderer.
-    Drupal.ajax.instances
-      /**
-       * If there is an element and the renderer is 'off_canvas' then we want
-       * to add our changes.
-       */
-      .filter(
-        (instance) =>
-          instance &&
-          $(instance.element).attr('data-dialog-renderer') === 'off_canvas',
-      )
-      /**
-       * Loop through all Ajax instances that use the 'off_canvas' renderer to
-       * set active editable ID.
-       */
-      .forEach((instance) => {
-        // Check to make sure existing dialogOptions aren't overridden.
-        if (!instance.options.data.hasOwnProperty('dialogOptions')) {
-          instance.options.data.dialogOptions = {};
-        }
-        instance.options.data.dialogOptions.settingsTrayActiveEditableId = $(
-          instance.element,
-        )
-          .parents('.settings-tray-editable')
-          .attr('id');
-        instance.progress = { type: 'fullscreen' };
-      });
-  }
-
-  /**
-   * Reacts to contextual links being added.
-   *
-   * @param {jQuery.Event} event
-   *   The `drupalContextualLinkAdded` event.
-   * @param {object} data
-   *   An object containing the data relevant to the event.
-   *
-   * @listens event:drupalContextualLinkAdded
-   */
-  $(document).on('drupalContextualLinkAdded', (event, data) => {
-    /**
-     * When contextual links are add we need to set extra properties on the
-     * instances in Drupal.ajax.instances for them to work with Edit Mode.
-     */
-    prepareAjaxLinks();
-
-    // When the first contextual link is added to the page set Edit Mode.
-    once('settings_tray.edit_mode_init', 'body').forEach(() => {
-      const editMode =
-        localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false';
-      if (editMode) {
-        setEditModeState(true);
-      }
-    });
-
-    /**
-     * Bind a listener to all 'Quick edit' links for blocks. Click "Edit"
-     * button in toolbar to force Contextual Edit which starts Settings Tray
-     * edit mode also.
-     */
-    data.$el.find(blockConfigureSelector).on('click.settingstray', () => {
-      if (!isInEditMode()) {
-        $(toggleEditSelector).trigger('click').trigger('click.settings_tray');
-      }
-    });
-  });
-
-  $(document).on('keyup.settingstray', (e) => {
-    if (isInEditMode() && e.keyCode === 27) {
-      Drupal.announce(Drupal.t('Exited edit mode.'));
-      toggleEditMode();
-    }
-  });
-
-  /**
-   * Toggle the js-settings-tray-edit-mode class on items that we want to
-   * disable while in edit mode.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Toggle the js-settings-tray-edit-mode class.
-   */
-  Drupal.behaviors.toggleEditMode = {
-    attach() {
-      $(once('settingstray', toggleEditSelector)).on(
-        'click.settingstray',
-        toggleEditMode,
-      );
-    },
-  };
-
-  // Manage Active editable class on opening and closing of the dialog.
-  $(window).on({
-    'dialog:beforecreate': (event, dialog, $element, settings) => {
-      if ($element.is('#drupal-off-canvas')) {
-        $('body .settings-tray-active-editable').removeClass(
-          'settings-tray-active-editable',
-        );
-        const $activeElement = $(`#${settings.settingsTrayActiveEditableId}`);
-        if ($activeElement.length) {
-          $activeElement.addClass('settings-tray-active-editable');
-        }
-      }
-    },
-    'dialog:beforeclose': (event, dialog, $element) => {
-      if ($element.is('#drupal-off-canvas')) {
-        $('body .settings-tray-active-editable').removeClass(
-          'settings-tray-active-editable',
-        );
-      }
-    },
-  });
-})(jQuery, Drupal);
diff --git a/core/modules/settings_tray/js/settings_tray.js b/core/modules/settings_tray/js/settings_tray.js
index de38668073a6..86910eaba19a 100644
--- a/core/modules/settings_tray/js/settings_tray.js
+++ b/core/modules/settings_tray/js/settings_tray.js
@@ -1,136 +1,249 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Drupal's Settings Tray library.
+ *
+ * @private
+ */
 
 (($, Drupal) => {
   const blockConfigureSelector = '[data-settings-tray-edit]';
   const toggleEditSelector = '[data-drupal-settingstray="toggle"]';
-  const itemsToToggleSelector = '[data-off-canvas-main-canvas], #toolbar-bar, [data-drupal-settingstray="editable"] a, [data-drupal-settingstray="editable"] button';
-  const contextualItemsSelector = '[data-contextual-id] a, [data-contextual-id] button';
+  const itemsToToggleSelector =
+    '[data-off-canvas-main-canvas], #toolbar-bar, [data-drupal-settingstray="editable"] a, [data-drupal-settingstray="editable"] button';
+  const contextualItemsSelector =
+    '[data-contextual-id] a, [data-contextual-id] button';
 
+  /**
+   * Prevent default click events except contextual links.
+   *
+   * In edit mode the default action of click events is suppressed.
+   *
+   * @param {jQuery.Event} event
+   *   The click event.
+   */
   function preventClick(event) {
+    // Do not prevent contextual links.
     if ($(event.target).closest('.contextual-links').length) {
       return;
     }
-
     event.preventDefault();
   }
 
+  /**
+   * Close any active toolbar tray before entering edit mode.
+   */
   function closeToolbarTrays() {
     $(Drupal.toolbar.models.toolbarModel.get('activeTab')).trigger('click');
   }
 
+  /**
+   * Closes/removes off-canvas.
+   */
   function closeOffCanvas() {
     $('.ui-dialog-off-canvas .ui-dialog-titlebar-close').trigger('click');
   }
 
+  /**
+   * Gets all items that should be toggled with class during edit mode.
+   *
+   * @return {jQuery}
+   *   Items that should be toggled.
+   */
   function getItemsToToggle() {
     return $(itemsToToggleSelector).not(contextualItemsSelector);
   }
 
+  /**
+   * Helper to switch edit mode state.
+   *
+   * @param {boolean} editMode
+   *   True enable edit mode, false disable edit mode.
+   */
   function setEditModeState(editMode) {
     if (!document.querySelector('[data-off-canvas-main-canvas]')) {
-      throw new Error('data-off-canvas-main-canvas is missing from settings-tray-page-wrapper.html.twig');
+      throw new Error(
+        'data-off-canvas-main-canvas is missing from settings-tray-page-wrapper.html.twig',
+      );
     }
-
     editMode = !!editMode;
     let $editables;
     const editButton = document.querySelector(toggleEditSelector);
-
+    // Turn on edit mode.
     if (editMode) {
       if (editButton) {
         editButton.textContent = Drupal.t('Editing');
       }
-
       closeToolbarTrays();
-      $editables = $(once('settingstray', '[data-drupal-settingstray="editable"]'));
 
+      $editables = $(
+        once('settingstray', '[data-drupal-settingstray="editable"]'),
+      );
       if ($editables.length) {
-        document.querySelector('[data-off-canvas-main-canvas]').addEventListener('click', preventClick, true);
-        $editables.not(contextualItemsSelector).on('click.settingstray', e => {
-          if ($(e.target).closest('.contextual').length || !localStorage.getItem('Drupal.contextualToolbar.isViewing')) {
-            return;
-          }
-
-          $(e.currentTarget).find(blockConfigureSelector).trigger('click');
-        });
+        // Use event capture to prevent clicks on links.
+        document
+          .querySelector('[data-off-canvas-main-canvas]')
+          .addEventListener('click', preventClick, true);
+        /**
+         * When a click occurs try and find the settings-tray edit link
+         * and click it.
+         */
+        $editables
+          .not(contextualItemsSelector)
+          .on('click.settingstray', (e) => {
+            // Contextual links are allowed to function in Edit mode.
+            if (
+              $(e.target).closest('.contextual').length ||
+              !localStorage.getItem('Drupal.contextualToolbar.isViewing')
+            ) {
+              return;
+            }
+            $(e.currentTarget).find(blockConfigureSelector).trigger('click');
+          });
       }
-    } else {
-      $editables = $(once.remove('settingstray', '[data-drupal-settingstray="editable"]'));
-
+    }
+    // Disable edit mode.
+    else {
+      $editables = $(
+        once.remove('settingstray', '[data-drupal-settingstray="editable"]'),
+      );
       if ($editables.length) {
-        document.querySelector('[data-off-canvas-main-canvas]').removeEventListener('click', preventClick, true);
+        document
+          .querySelector('[data-off-canvas-main-canvas]')
+          .removeEventListener('click', preventClick, true);
         $editables.off('.settingstray');
       }
-
       if (editButton) {
         editButton.textContent = Drupal.t('Edit');
       }
-
       closeOffCanvas();
     }
-
     getItemsToToggle().toggleClass('js-settings-tray-edit-mode', editMode);
     $('.edit-mode-inactive').toggleClass('visually-hidden', editMode);
   }
 
+  /**
+   * Helper to check the state of the settings-tray mode.
+   *
+   * @todo don't use a class for this.
+   *
+   * @return {boolean}
+   *   State of the settings-tray edit mode.
+   */
   function isInEditMode() {
     return $('#toolbar-bar').hasClass('js-settings-tray-edit-mode');
   }
 
+  /**
+   * Helper to toggle Edit mode.
+   */
   function toggleEditMode() {
     setEditModeState(!isInEditMode());
   }
 
+  /**
+   * Prepares Ajax links to work with off-canvas and Settings Tray module.
+   */
   function prepareAjaxLinks() {
-    Drupal.ajax.instances.filter(instance => instance && $(instance.element).attr('data-dialog-renderer') === 'off_canvas').forEach(instance => {
-      if (!instance.options.data.hasOwnProperty('dialogOptions')) {
-        instance.options.data.dialogOptions = {};
-      }
-
-      instance.options.data.dialogOptions.settingsTrayActiveEditableId = $(instance.element).parents('.settings-tray-editable').attr('id');
-      instance.progress = {
-        type: 'fullscreen'
-      };
-    });
+    // Find all Ajax instances that use the 'off_canvas' renderer.
+    Drupal.ajax.instances
+      /**
+       * If there is an element and the renderer is 'off_canvas' then we want
+       * to add our changes.
+       */
+      .filter(
+        (instance) =>
+          instance &&
+          $(instance.element).attr('data-dialog-renderer') === 'off_canvas',
+      )
+      /**
+       * Loop through all Ajax instances that use the 'off_canvas' renderer to
+       * set active editable ID.
+       */
+      .forEach((instance) => {
+        // Check to make sure existing dialogOptions aren't overridden.
+        if (!instance.options.data.hasOwnProperty('dialogOptions')) {
+          instance.options.data.dialogOptions = {};
+        }
+        instance.options.data.dialogOptions.settingsTrayActiveEditableId = $(
+          instance.element,
+        )
+          .parents('.settings-tray-editable')
+          .attr('id');
+        instance.progress = { type: 'fullscreen' };
+      });
   }
 
+  /**
+   * Reacts to contextual links being added.
+   *
+   * @param {jQuery.Event} event
+   *   The `drupalContextualLinkAdded` event.
+   * @param {object} data
+   *   An object containing the data relevant to the event.
+   *
+   * @listens event:drupalContextualLinkAdded
+   */
   $(document).on('drupalContextualLinkAdded', (event, data) => {
+    /**
+     * When contextual links are add we need to set extra properties on the
+     * instances in Drupal.ajax.instances for them to work with Edit Mode.
+     */
     prepareAjaxLinks();
-    once('settings_tray.edit_mode_init', 'body').forEach(() => {
-      const editMode = localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false';
 
+    // When the first contextual link is added to the page set Edit Mode.
+    once('settings_tray.edit_mode_init', 'body').forEach(() => {
+      const editMode =
+        localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false';
       if (editMode) {
         setEditModeState(true);
       }
     });
+
+    /**
+     * Bind a listener to all 'Quick edit' links for blocks. Click "Edit"
+     * button in toolbar to force Contextual Edit which starts Settings Tray
+     * edit mode also.
+     */
     data.$el.find(blockConfigureSelector).on('click.settingstray', () => {
       if (!isInEditMode()) {
         $(toggleEditSelector).trigger('click').trigger('click.settings_tray');
       }
     });
   });
-  $(document).on('keyup.settingstray', e => {
+
+  $(document).on('keyup.settingstray', (e) => {
     if (isInEditMode() && e.keyCode === 27) {
       Drupal.announce(Drupal.t('Exited edit mode.'));
       toggleEditMode();
     }
   });
+
+  /**
+   * Toggle the js-settings-tray-edit-mode class on items that we want to
+   * disable while in edit mode.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Toggle the js-settings-tray-edit-mode class.
+   */
   Drupal.behaviors.toggleEditMode = {
     attach() {
-      $(once('settingstray', toggleEditSelector)).on('click.settingstray', toggleEditMode);
-    }
-
+      $(once('settingstray', toggleEditSelector)).on(
+        'click.settingstray',
+        toggleEditMode,
+      );
+    },
   };
+
+  // Manage Active editable class on opening and closing of the dialog.
   $(window).on({
     'dialog:beforecreate': (event, dialog, $element, settings) => {
       if ($element.is('#drupal-off-canvas')) {
-        $('body .settings-tray-active-editable').removeClass('settings-tray-active-editable');
+        $('body .settings-tray-active-editable').removeClass(
+          'settings-tray-active-editable',
+        );
         const $activeElement = $(`#${settings.settingsTrayActiveEditableId}`);
-
         if ($activeElement.length) {
           $activeElement.addClass('settings-tray-active-editable');
         }
@@ -138,8 +251,10 @@
     },
     'dialog:beforeclose': (event, dialog, $element) => {
       if ($element.is('#drupal-off-canvas')) {
-        $('body .settings-tray-active-editable').removeClass('settings-tray-active-editable');
+        $('body .settings-tray-active-editable').removeClass(
+          'settings-tray-active-editable',
+        );
       }
-    }
+    },
   });
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/settings_tray/settings_tray.api.php b/core/modules/settings_tray/settings_tray.api.php
index 1221daf3b307..1132f3d25fba 100644
--- a/core/modules/settings_tray/settings_tray.api.php
+++ b/core/modules/settings_tray/settings_tray.api.php
@@ -30,7 +30,7 @@
  * By default, the Settings Tray shows any block's built-in form in the
  * off-canvas dialog.
  *
- * @see core/misc/dialog/off-canvas.es6.js
+ * @see core/misc/dialog/off-canvas.js
  *
  * However, many blocks would benefit from a tailored form which either:
  * - limits the form items displayed in the Settings Tray to only items that
diff --git a/core/modules/statistics/statistics.es6.js b/core/modules/statistics/statistics.es6.js
deleted file mode 100644
index 7c0360dc7c0d..000000000000
--- a/core/modules/statistics/statistics.es6.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * @file
- * Statistics functionality.
- */
-
-(function ($, Drupal, drupalSettings) {
-  $(document).ready(() => {
-    $.ajax({
-      type: 'POST',
-      cache: false,
-      url: drupalSettings.statistics.url,
-      data: drupalSettings.statistics.data,
-    });
-  });
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/statistics/statistics.js b/core/modules/statistics/statistics.js
index 0c2f4107fb53..7c0360dc7c0d 100644
--- a/core/modules/statistics/statistics.js
+++ b/core/modules/statistics/statistics.js
@@ -1,9 +1,7 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Statistics functionality.
+ */
 
 (function ($, Drupal, drupalSettings) {
   $(document).ready(() => {
@@ -11,7 +9,7 @@
       type: 'POST',
       cache: false,
       url: drupalSettings.statistics.url,
-      data: drupalSettings.statistics.data
+      data: drupalSettings.statistics.data,
     });
   });
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/system/js/system.date.es6.js b/core/modules/system/js/system.date.es6.js
deleted file mode 100644
index 2ea0af1d95a0..000000000000
--- a/core/modules/system/js/system.date.es6.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * @file
- * Provides date format preview feature.
- */
-
-(function ($, Drupal, drupalSettings) {
-  const dateFormats = drupalSettings.dateFormats;
-
-  /**
-   * Display the preview for date format entered.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attach behavior for previewing date formats on input elements.
-   */
-  Drupal.behaviors.dateFormat = {
-    attach(context) {
-      const source = once(
-        'dateFormat',
-        '[data-drupal-date-formatter="source"]',
-        context,
-      );
-      const target = once(
-        'dateFormat',
-        '[data-drupal-date-formatter="preview"]',
-        context,
-      );
-
-      // All elements have to exist.
-      if (!source.length || !target.length) {
-        return;
-      }
-
-      /**
-       * Event handler that replaces date characters with value.
-       *
-       * @param {jQuery.Event} e
-       *   The jQuery event triggered.
-       */
-      function dateFormatHandler(e) {
-        const baseValue = e.target.value || '';
-        const dateString = baseValue.replace(/\\?(.?)/gi, (key, value) =>
-          dateFormats[key] ? dateFormats[key] : value,
-        );
-
-        // Set date preview.
-        target.forEach((item) => {
-          item.querySelectorAll('em').forEach((em) => {
-            em.textContent = dateString;
-          });
-        });
-
-        $(target).toggleClass('js-hide', !dateString.length);
-      }
-
-      /**
-       * On given event triggers the date character replacement.
-       */
-      $(source)
-        .on(
-          'keyup.dateFormat change.dateFormat input.dateFormat',
-          dateFormatHandler,
-        )
-        // Initialize preview.
-        .trigger('keyup');
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/system/js/system.date.js b/core/modules/system/js/system.date.js
index 586fca6adff1..2ea0af1d95a0 100644
--- a/core/modules/system/js/system.date.js
+++ b/core/modules/system/js/system.date.js
@@ -1,34 +1,69 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Provides date format preview feature.
+ */
 
 (function ($, Drupal, drupalSettings) {
   const dateFormats = drupalSettings.dateFormats;
+
+  /**
+   * Display the preview for date format entered.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach behavior for previewing date formats on input elements.
+   */
   Drupal.behaviors.dateFormat = {
     attach(context) {
-      const source = once('dateFormat', '[data-drupal-date-formatter="source"]', context);
-      const target = once('dateFormat', '[data-drupal-date-formatter="preview"]', context);
+      const source = once(
+        'dateFormat',
+        '[data-drupal-date-formatter="source"]',
+        context,
+      );
+      const target = once(
+        'dateFormat',
+        '[data-drupal-date-formatter="preview"]',
+        context,
+      );
 
+      // All elements have to exist.
       if (!source.length || !target.length) {
         return;
       }
 
+      /**
+       * Event handler that replaces date characters with value.
+       *
+       * @param {jQuery.Event} e
+       *   The jQuery event triggered.
+       */
       function dateFormatHandler(e) {
         const baseValue = e.target.value || '';
-        const dateString = baseValue.replace(/\\?(.?)/gi, (key, value) => dateFormats[key] ? dateFormats[key] : value);
-        target.forEach(item => {
-          item.querySelectorAll('em').forEach(em => {
+        const dateString = baseValue.replace(/\\?(.?)/gi, (key, value) =>
+          dateFormats[key] ? dateFormats[key] : value,
+        );
+
+        // Set date preview.
+        target.forEach((item) => {
+          item.querySelectorAll('em').forEach((em) => {
             em.textContent = dateString;
           });
         });
+
         $(target).toggleClass('js-hide', !dateString.length);
       }
 
-      $(source).on('keyup.dateFormat change.dateFormat input.dateFormat', dateFormatHandler).trigger('keyup');
-    }
-
+      /**
+       * On given event triggers the date character replacement.
+       */
+      $(source)
+        .on(
+          'keyup.dateFormat change.dateFormat input.dateFormat',
+          dateFormatHandler,
+        )
+        // Initialize preview.
+        .trigger('keyup');
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/system/js/system.es6.js b/core/modules/system/js/system.es6.js
deleted file mode 100644
index 7bca481c068b..000000000000
--- a/core/modules/system/js/system.es6.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * @file
- * System behaviors.
- */
-
-(function ($, Drupal, drupalSettings) {
-  // Cache IDs in an array for ease of use.
-  const ids = [];
-
-  /**
-   * Attaches field copy behavior from input fields to other input fields.
-   *
-   * When a field is filled out, apply its value to other fields that will
-   * likely use the same value. In the installer this is used to populate the
-   * administrator email address with the same value as the site email address.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the field copy behavior to an input field.
-   */
-  Drupal.behaviors.copyFieldValue = {
-    attach(context) {
-      // List of fields IDs on which to bind the event listener.
-      // Create an array of IDs to use with jQuery.
-      Object.keys(drupalSettings.copyFieldValue || {}).forEach((element) => {
-        ids.push(element);
-      });
-
-      if (ids.length) {
-        // Listen to value:copy events on all dependent fields.
-        // We have to use body and not document because of the way jQuery events
-        // bubble up the DOM tree.
-        $(once('copy-field-values', 'body')).on(
-          'value:copy',
-          this.valueTargetCopyHandler,
-        );
-        // Listen on all source elements.
-        $(once('copy-field-values', `#${ids.join(', #')}`)).on(
-          'blur',
-          this.valueSourceBlurHandler,
-        );
-      }
-    },
-    detach(context, settings, trigger) {
-      if (trigger === 'unload' && ids.length) {
-        $(once.remove('copy-field-values', 'body')).off('value:copy');
-        $(once.remove('copy-field-values', `#${ids.join(', #')}`)).off('blur');
-      }
-    },
-
-    /**
-     * Event handler that fill the target element with the specified value.
-     *
-     * @param {jQuery.Event} e
-     *   Event object.
-     * @param {string} value
-     *   Custom value from jQuery trigger.
-     */
-    valueTargetCopyHandler(e, value) {
-      const { target } = e;
-      if (target.value === '') {
-        target.value = value;
-      }
-    },
-
-    /**
-     * Handler for a Blur event on a source field.
-     *
-     * This event handler will trigger a 'value:copy' event on all dependent
-     * fields.
-     *
-     * @param {jQuery.Event} e
-     *   The event triggered.
-     */
-    valueSourceBlurHandler(e) {
-      const { value } = e.target;
-      const targetIds = drupalSettings.copyFieldValue[e.target.id];
-      $(`#${targetIds.join(', #')}`).trigger('value:copy', value);
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/system/js/system.js b/core/modules/system/js/system.js
index 86bbfb220a8b..7bca481c068b 100644
--- a/core/modules/system/js/system.js
+++ b/core/modules/system/js/system.js
@@ -1,24 +1,47 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * System behaviors.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  // Cache IDs in an array for ease of use.
   const ids = [];
+
+  /**
+   * Attaches field copy behavior from input fields to other input fields.
+   *
+   * When a field is filled out, apply its value to other fields that will
+   * likely use the same value. In the installer this is used to populate the
+   * administrator email address with the same value as the site email address.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the field copy behavior to an input field.
+   */
   Drupal.behaviors.copyFieldValue = {
     attach(context) {
-      Object.keys(drupalSettings.copyFieldValue || {}).forEach(element => {
+      // List of fields IDs on which to bind the event listener.
+      // Create an array of IDs to use with jQuery.
+      Object.keys(drupalSettings.copyFieldValue || {}).forEach((element) => {
         ids.push(element);
       });
 
       if (ids.length) {
-        $(once('copy-field-values', 'body')).on('value:copy', this.valueTargetCopyHandler);
-        $(once('copy-field-values', `#${ids.join(', #')}`)).on('blur', this.valueSourceBlurHandler);
+        // Listen to value:copy events on all dependent fields.
+        // We have to use body and not document because of the way jQuery events
+        // bubble up the DOM tree.
+        $(once('copy-field-values', 'body')).on(
+          'value:copy',
+          this.valueTargetCopyHandler,
+        );
+        // Listen on all source elements.
+        $(once('copy-field-values', `#${ids.join(', #')}`)).on(
+          'blur',
+          this.valueSourceBlurHandler,
+        );
       }
     },
-
     detach(context, settings, trigger) {
       if (trigger === 'unload' && ids.length) {
         $(once.remove('copy-field-values', 'body')).off('value:copy');
@@ -26,23 +49,34 @@
       }
     },
 
+    /**
+     * Event handler that fill the target element with the specified value.
+     *
+     * @param {jQuery.Event} e
+     *   Event object.
+     * @param {string} value
+     *   Custom value from jQuery trigger.
+     */
     valueTargetCopyHandler(e, value) {
-      const {
-        target
-      } = e;
-
+      const { target } = e;
       if (target.value === '') {
         target.value = value;
       }
     },
 
+    /**
+     * Handler for a Blur event on a source field.
+     *
+     * This event handler will trigger a 'value:copy' event on all dependent
+     * fields.
+     *
+     * @param {jQuery.Event} e
+     *   The event triggered.
+     */
     valueSourceBlurHandler(e) {
-      const {
-        value
-      } = e.target;
+      const { value } = e.target;
       const targetIds = drupalSettings.copyFieldValue[e.target.id];
       $(`#${targetIds.join(', #')}`).trigger('value:copy', value);
-    }
-
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/system/js/system.modules.es6.js b/core/modules/system/js/system.modules.es6.js
deleted file mode 100644
index f46b1226dcdd..000000000000
--- a/core/modules/system/js/system.modules.es6.js
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * @file
- * Module page behaviors.
- */
-
-(function ($, Drupal, debounce) {
-  /**
-   * Filters the module list table by a text input search string.
-   *
-   * Additionally accounts for multiple tables being wrapped in "package" details
-   * elements.
-   *
-   * Text search input: input.table-filter-text
-   * Target table:      input.table-filter-text[data-table]
-   * Source text:       .table-filter-text-source, .module-name, .module-description
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.tableFilterByText = {
-    attach(context, settings) {
-      const [input] = once('table-filter-text', 'input.table-filter-text');
-      if (!input) {
-        return;
-      }
-      const $table = $(input.getAttribute('data-table'));
-      let $rowsAndDetails;
-      let $rows;
-      let $details;
-      let searching = false;
-
-      function hidePackageDetails(index, element) {
-        const $packDetails = $(element);
-        const $visibleRows = $packDetails.find('tbody tr:visible');
-        $packDetails.toggle($visibleRows.length > 0);
-      }
-
-      function filterModuleList(e) {
-        const query = e.target.value;
-        // Case insensitive expression to find query at the beginning of a word.
-        const re = new RegExp(`\\b${query}`, 'i');
-
-        function showModuleRow(index, row) {
-          const sources = row.querySelectorAll(
-            '.table-filter-text-source, .module-name, .module-description',
-          );
-          let sourcesConcat = '';
-          // Concatenate the textContent of the elements in the row.
-          sources.forEach((item) => {
-            sourcesConcat += item.textContent;
-          });
-          const textMatch = sourcesConcat.search(re) !== -1;
-          $(row).closest('tr').toggle(textMatch);
-        }
-        // Search over all rows and packages.
-        $rowsAndDetails.show();
-
-        // Filter if the length of the query is at least 2 characters.
-        if (query.length >= 2) {
-          searching = true;
-          $rows.each(showModuleRow);
-
-          // Note that we first open all <details> to be able to use ':visible'.
-          // Mark the <details> elements that were closed before filtering, so
-          // they can be reclosed when filtering is removed.
-          $details
-            .not('[open]')
-            .attr('data-drupal-system-state', 'forced-open');
-
-          // Hide the package <details> if they don't have any visible rows.
-          // Note that we first show() all <details> to be able to use ':visible'.
-          $details.attr('open', true).each(hidePackageDetails);
-
-          Drupal.announce(
-            Drupal.t('!modules modules are available in the modified list.', {
-              '!modules': $rowsAndDetails.find('tbody tr:visible').length,
-            }),
-          );
-        } else if (searching) {
-          searching = false;
-          $rowsAndDetails.show();
-          // Return <details> elements that had been closed before filtering
-          // to a closed state.
-          $details
-            .filter('[data-drupal-system-state="forced-open"]')
-            .removeAttr('data-drupal-system-state')
-            .attr('open', false);
-        }
-      }
-
-      function preventEnterKey(event) {
-        if (event.which === 13) {
-          event.preventDefault();
-          event.stopPropagation();
-        }
-      }
-
-      if ($table.length) {
-        $rowsAndDetails = $table.find('tr, details');
-        $rows = $table.find('tbody tr');
-        $details = $rowsAndDetails.filter('.package-listing');
-
-        $(input).on({
-          keyup: debounce(filterModuleList, 200),
-          keydown: preventEnterKey,
-        });
-      }
-    },
-  };
-})(jQuery, Drupal, Drupal.debounce);
diff --git a/core/modules/system/js/system.modules.js b/core/modules/system/js/system.modules.js
index fb19695e9fde..f46b1226dcdd 100644
--- a/core/modules/system/js/system.modules.js
+++ b/core/modules/system/js/system.modules.js
@@ -1,19 +1,27 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Module page behaviors.
+ */
 
 (function ($, Drupal, debounce) {
+  /**
+   * Filters the module list table by a text input search string.
+   *
+   * Additionally accounts for multiple tables being wrapped in "package" details
+   * elements.
+   *
+   * Text search input: input.table-filter-text
+   * Target table:      input.table-filter-text[data-table]
+   * Source text:       .table-filter-text-source, .module-name, .module-description
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.tableFilterByText = {
     attach(context, settings) {
       const [input] = once('table-filter-text', 'input.table-filter-text');
-
       if (!input) {
         return;
       }
-
       const $table = $(input.getAttribute('data-table'));
       let $rowsAndDetails;
       let $rows;
@@ -28,32 +36,54 @@
 
       function filterModuleList(e) {
         const query = e.target.value;
+        // Case insensitive expression to find query at the beginning of a word.
         const re = new RegExp(`\\b${query}`, 'i');
 
         function showModuleRow(index, row) {
-          const sources = row.querySelectorAll('.table-filter-text-source, .module-name, .module-description');
+          const sources = row.querySelectorAll(
+            '.table-filter-text-source, .module-name, .module-description',
+          );
           let sourcesConcat = '';
-          sources.forEach(item => {
+          // Concatenate the textContent of the elements in the row.
+          sources.forEach((item) => {
             sourcesConcat += item.textContent;
           });
           const textMatch = sourcesConcat.search(re) !== -1;
           $(row).closest('tr').toggle(textMatch);
         }
-
+        // Search over all rows and packages.
         $rowsAndDetails.show();
 
+        // Filter if the length of the query is at least 2 characters.
         if (query.length >= 2) {
           searching = true;
           $rows.each(showModuleRow);
-          $details.not('[open]').attr('data-drupal-system-state', 'forced-open');
+
+          // Note that we first open all <details> to be able to use ':visible'.
+          // Mark the <details> elements that were closed before filtering, so
+          // they can be reclosed when filtering is removed.
+          $details
+            .not('[open]')
+            .attr('data-drupal-system-state', 'forced-open');
+
+          // Hide the package <details> if they don't have any visible rows.
+          // Note that we first show() all <details> to be able to use ':visible'.
           $details.attr('open', true).each(hidePackageDetails);
-          Drupal.announce(Drupal.t('!modules modules are available in the modified list.', {
-            '!modules': $rowsAndDetails.find('tbody tr:visible').length
-          }));
+
+          Drupal.announce(
+            Drupal.t('!modules modules are available in the modified list.', {
+              '!modules': $rowsAndDetails.find('tbody tr:visible').length,
+            }),
+          );
         } else if (searching) {
           searching = false;
           $rowsAndDetails.show();
-          $details.filter('[data-drupal-system-state="forced-open"]').removeAttr('data-drupal-system-state').attr('open', false);
+          // Return <details> elements that had been closed before filtering
+          // to a closed state.
+          $details
+            .filter('[data-drupal-system-state="forced-open"]')
+            .removeAttr('data-drupal-system-state')
+            .attr('open', false);
         }
       }
 
@@ -68,12 +98,12 @@
         $rowsAndDetails = $table.find('tr, details');
         $rows = $table.find('tbody tr');
         $details = $rowsAndDetails.filter('.package-listing');
+
         $(input).on({
           keyup: debounce(filterModuleList, 200),
-          keydown: preventEnterKey
+          keydown: preventEnterKey,
         });
       }
-    }
-
+    },
   };
-})(jQuery, Drupal, Drupal.debounce);
\ No newline at end of file
+})(jQuery, Drupal, Drupal.debounce);
diff --git a/core/modules/system/tests/modules/ajax_test/js/command_promise-ajax.es6.js b/core/modules/system/tests/modules/ajax_test/js/command_promise-ajax.es6.js
deleted file mode 100644
index 8f4e40d85ba5..000000000000
--- a/core/modules/system/tests/modules/ajax_test/js/command_promise-ajax.es6.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * @file
- *  Testing behavior for the add_js command.
- */
-
-(($, Drupal) => {
-  /**
-   * Test Ajax execution Order.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   {@link Drupal.Ajax} object created by {@link Drupal.Ajax}.
-   * @param {object} response
-   *   The response from the Ajax request.
-   * @param {string} response.selector
-   *   A jQuery selector string.
-   *
-   * @return {Promise}
-   *  The promise that will resolve once this command has finished executing.
-   */
-  Drupal.AjaxCommands.prototype.ajaxCommandReturnPromise = function (
-    ajax,
-    response,
-  ) {
-    return new Promise((resolve, reject) => {
-      setTimeout(() => {
-        this.insert(ajax, response);
-        resolve();
-      }, Math.random() * 500);
-    });
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/system/tests/modules/ajax_test/js/command_promise-ajax.js b/core/modules/system/tests/modules/ajax_test/js/command_promise-ajax.js
index 162ac73f3c65..8f4e40d85ba5 100644
--- a/core/modules/system/tests/modules/ajax_test/js/command_promise-ajax.js
+++ b/core/modules/system/tests/modules/ajax_test/js/command_promise-ajax.js
@@ -1,12 +1,26 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ *  Testing behavior for the add_js command.
+ */
 
 (($, Drupal) => {
-  Drupal.AjaxCommands.prototype.ajaxCommandReturnPromise = function (ajax, response) {
+  /**
+   * Test Ajax execution Order.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   {@link Drupal.Ajax} object created by {@link Drupal.Ajax}.
+   * @param {object} response
+   *   The response from the Ajax request.
+   * @param {string} response.selector
+   *   A jQuery selector string.
+   *
+   * @return {Promise}
+   *  The promise that will resolve once this command has finished executing.
+   */
+  Drupal.AjaxCommands.prototype.ajaxCommandReturnPromise = function (
+    ajax,
+    response,
+  ) {
     return new Promise((resolve, reject) => {
       setTimeout(() => {
         this.insert(ajax, response);
@@ -14,4 +28,4 @@
       }, Math.random() * 500);
     });
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/system/tests/modules/ajax_test/js/focus-ajax.es6.js b/core/modules/system/tests/modules/ajax_test/js/focus-ajax.es6.js
deleted file mode 100644
index 1a66c404d16f..000000000000
--- a/core/modules/system/tests/modules/ajax_test/js/focus-ajax.es6.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * @file
- * For testing FocusFirstCommand.
- */
-
-((Drupal) => {
-  Drupal.behaviors.focusFirstTest = {
-    attach() {
-      // Add data-has-focus attribute to focused elements so tests have a
-      // selector to wait for before moving to the next test step.
-      once('focusin', document.body).forEach((element) => {
-        element.addEventListener('focusin', (e) => {
-          document
-            .querySelectorAll('[data-has-focus]')
-            .forEach((wasFocused) => {
-              wasFocused.removeAttribute('data-has-focus');
-            });
-          e.target.setAttribute('data-has-focus', true);
-        });
-      });
-    },
-  };
-})(Drupal, once);
diff --git a/core/modules/system/tests/modules/ajax_test/js/focus-ajax.js b/core/modules/system/tests/modules/ajax_test/js/focus-ajax.js
index 22314f02041a..1a66c404d16f 100644
--- a/core/modules/system/tests/modules/ajax_test/js/focus-ajax.js
+++ b/core/modules/system/tests/modules/ajax_test/js/focus-ajax.js
@@ -1,22 +1,23 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * For testing FocusFirstCommand.
+ */
 
-(Drupal => {
+((Drupal) => {
   Drupal.behaviors.focusFirstTest = {
     attach() {
-      once('focusin', document.body).forEach(element => {
-        element.addEventListener('focusin', e => {
-          document.querySelectorAll('[data-has-focus]').forEach(wasFocused => {
-            wasFocused.removeAttribute('data-has-focus');
-          });
+      // Add data-has-focus attribute to focused elements so tests have a
+      // selector to wait for before moving to the next test step.
+      once('focusin', document.body).forEach((element) => {
+        element.addEventListener('focusin', (e) => {
+          document
+            .querySelectorAll('[data-has-focus]')
+            .forEach((wasFocused) => {
+              wasFocused.removeAttribute('data-has-focus');
+            });
           e.target.setAttribute('data-has-focus', true);
         });
       });
-    }
-
+    },
   };
-})(Drupal, once);
\ No newline at end of file
+})(Drupal, once);
diff --git a/core/modules/system/tests/modules/ajax_test/js/insert-ajax.es6.js b/core/modules/system/tests/modules/ajax_test/js/insert-ajax.es6.js
deleted file mode 100644
index 175e0596128e..000000000000
--- a/core/modules/system/tests/modules/ajax_test/js/insert-ajax.es6.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * @file
- * Drupal behavior to attach click event handlers to ajax-insert and
- * ajax-insert-inline links for testing ajax requests.
- */
-
-(function ($, window, Drupal) {
-  Drupal.behaviors.insertTest = {
-    attach(context) {
-      $(once('ajax-insert', '.ajax-insert')).on('click', (event) => {
-        event.preventDefault();
-        const ajaxSettings = {
-          url: event.currentTarget.getAttribute('href'),
-          wrapper: 'ajax-target',
-          base: false,
-          element: false,
-          method: event.currentTarget.getAttribute('data-method'),
-          effect: event.currentTarget.getAttribute('data-effect'),
-        };
-        const myAjaxObject = Drupal.ajax(ajaxSettings);
-        myAjaxObject.execute();
-      });
-
-      $(once('ajax-insert', '.ajax-insert-inline')).on('click', (event) => {
-        event.preventDefault();
-        const ajaxSettings = {
-          url: event.currentTarget.getAttribute('href'),
-          wrapper: 'ajax-target-inline',
-          base: false,
-          element: false,
-          method: event.currentTarget.getAttribute('data-method'),
-          effect: event.currentTarget.getAttribute('data-effect'),
-        };
-        const myAjaxObject = Drupal.ajax(ajaxSettings);
-        myAjaxObject.execute();
-      });
-
-      $(context).addClass('processed');
-    },
-  };
-})(jQuery, window, Drupal);
diff --git a/core/modules/system/tests/modules/ajax_test/js/insert-ajax.js b/core/modules/system/tests/modules/ajax_test/js/insert-ajax.js
index a41e676e3679..175e0596128e 100644
--- a/core/modules/system/tests/modules/ajax_test/js/insert-ajax.js
+++ b/core/modules/system/tests/modules/ajax_test/js/insert-ajax.js
@@ -1,14 +1,13 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Drupal behavior to attach click event handlers to ajax-insert and
+ * ajax-insert-inline links for testing ajax requests.
+ */
 
 (function ($, window, Drupal) {
   Drupal.behaviors.insertTest = {
     attach(context) {
-      $(once('ajax-insert', '.ajax-insert')).on('click', event => {
+      $(once('ajax-insert', '.ajax-insert')).on('click', (event) => {
         event.preventDefault();
         const ajaxSettings = {
           url: event.currentTarget.getAttribute('href'),
@@ -16,12 +15,13 @@
           base: false,
           element: false,
           method: event.currentTarget.getAttribute('data-method'),
-          effect: event.currentTarget.getAttribute('data-effect')
+          effect: event.currentTarget.getAttribute('data-effect'),
         };
         const myAjaxObject = Drupal.ajax(ajaxSettings);
         myAjaxObject.execute();
       });
-      $(once('ajax-insert', '.ajax-insert-inline')).on('click', event => {
+
+      $(once('ajax-insert', '.ajax-insert-inline')).on('click', (event) => {
         event.preventDefault();
         const ajaxSettings = {
           url: event.currentTarget.getAttribute('href'),
@@ -29,13 +29,13 @@
           base: false,
           element: false,
           method: event.currentTarget.getAttribute('data-method'),
-          effect: event.currentTarget.getAttribute('data-effect')
+          effect: event.currentTarget.getAttribute('data-effect'),
         };
         const myAjaxObject = Drupal.ajax(ajaxSettings);
         myAjaxObject.execute();
       });
-      $(context).addClass('processed');
-    }
 
+      $(context).addClass('processed');
+    },
   };
-})(jQuery, window, Drupal);
\ No newline at end of file
+})(jQuery, window, Drupal);
diff --git a/core/modules/system/tests/modules/css_disable_transitions_test/js/disable_transitions.theme.es6.js b/core/modules/system/tests/modules/css_disable_transitions_test/js/disable_transitions.theme.es6.js
deleted file mode 100644
index c496f53d1ad8..000000000000
--- a/core/modules/system/tests/modules/css_disable_transitions_test/js/disable_transitions.theme.es6.js
+++ /dev/null
@@ -1,3 +0,0 @@
-if (window.jQuery) {
-  jQuery.fx.off = true;
-}
diff --git a/core/modules/system/tests/modules/css_disable_transitions_test/js/disable_transitions.theme.js b/core/modules/system/tests/modules/css_disable_transitions_test/js/disable_transitions.theme.js
index d8040df5b02f..c496f53d1ad8 100644
--- a/core/modules/system/tests/modules/css_disable_transitions_test/js/disable_transitions.theme.js
+++ b/core/modules/system/tests/modules/css_disable_transitions_test/js/disable_transitions.theme.js
@@ -1,10 +1,3 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
 if (window.jQuery) {
   jQuery.fx.off = true;
-}
\ No newline at end of file
+}
diff --git a/core/modules/system/tests/modules/jquery_keyevent_polyfilll_test/js/jquery.keyevent.polyfill.es6.js b/core/modules/system/tests/modules/jquery_keyevent_polyfilll_test/js/jquery.keyevent.polyfill.es6.js
deleted file mode 100644
index 6e342c4b5054..000000000000
--- a/core/modules/system/tests/modules/jquery_keyevent_polyfilll_test/js/jquery.keyevent.polyfill.es6.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @file
- * Adds a jQuery polyfill for event.which.
- *
- * In jQuery 3.6, the event.which polyfill was removed, which is not needed for
- * any supported browsers, but is still necessary to trigger keyboard events in
- * FunctionalJavaScript tests.
- *
- * @todo: This polyfill may be removed if MinkSelenium2Driver updates its use of
- * syn.js, https://github.com/minkphp/MinkSelenium2Driver/pull/333
- *
- * @see https://github.com/jquery/jquery/issues/4755
- * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/which
- */
-
-(($) => {
-  // This is the polyfill implementation from jQuery 3.5.1, modified only to
-  // meet Drupal coding standards.
-  jQuery.event.addProp('which', function (event) {
-    const keyEventRegex = /^key/;
-    const mouseEventRegex = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;
-    const button = event.button;
-
-    // Add which for key events
-    if (event.which == null && keyEventRegex.test(event.type)) {
-      return event.charCode != null ? event.charCode : event.keyCode;
-    }
-
-    // Add which for click: 1 === left; 2 === middle; 3 === right
-    if (
-      !event.which &&
-      button !== undefined &&
-      mouseEventRegex.test(event.type)
-    ) {
-      if (button && 1) {
-        return 1;
-      }
-
-      if (button && 2) {
-        return 3;
-      }
-
-      if (button && 4) {
-        return 2;
-      }
-
-      return 0;
-    }
-
-    return event.which;
-  });
-})(jQuery);
diff --git a/core/modules/system/tests/modules/jquery_keyevent_polyfilll_test/js/jquery.keyevent.polyfill.js b/core/modules/system/tests/modules/jquery_keyevent_polyfilll_test/js/jquery.keyevent.polyfill.js
index a39a83757470..6e342c4b5054 100644
--- a/core/modules/system/tests/modules/jquery_keyevent_polyfilll_test/js/jquery.keyevent.polyfill.js
+++ b/core/modules/system/tests/modules/jquery_keyevent_polyfilll_test/js/jquery.keyevent.polyfill.js
@@ -1,21 +1,37 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Adds a jQuery polyfill for event.which.
+ *
+ * In jQuery 3.6, the event.which polyfill was removed, which is not needed for
+ * any supported browsers, but is still necessary to trigger keyboard events in
+ * FunctionalJavaScript tests.
+ *
+ * @todo: This polyfill may be removed if MinkSelenium2Driver updates its use of
+ * syn.js, https://github.com/minkphp/MinkSelenium2Driver/pull/333
+ *
+ * @see https://github.com/jquery/jquery/issues/4755
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/which
+ */
 
-($ => {
+(($) => {
+  // This is the polyfill implementation from jQuery 3.5.1, modified only to
+  // meet Drupal coding standards.
   jQuery.event.addProp('which', function (event) {
     const keyEventRegex = /^key/;
     const mouseEventRegex = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;
     const button = event.button;
 
+    // Add which for key events
     if (event.which == null && keyEventRegex.test(event.type)) {
       return event.charCode != null ? event.charCode : event.keyCode;
     }
 
-    if (!event.which && button !== undefined && mouseEventRegex.test(event.type)) {
+    // Add which for click: 1 === left; 2 === middle; 3 === right
+    if (
+      !event.which &&
+      button !== undefined &&
+      mouseEventRegex.test(event.type)
+    ) {
       if (button && 1) {
         return 1;
       }
@@ -33,4 +49,4 @@
 
     return event.which;
   });
-})(jQuery);
\ No newline at end of file
+})(jQuery);
diff --git a/core/modules/system/tests/modules/js_deprecation_test/js/js_deprecation_test.es6.js b/core/modules/system/tests/modules/js_deprecation_test/js/js_deprecation_test.es6.js
deleted file mode 100644
index ca93f925764c..000000000000
--- a/core/modules/system/tests/modules/js_deprecation_test/js/js_deprecation_test.es6.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * @file
- *  Testing tools for deprecating JavaScript functions and class properties.
- */
-(function ({ deprecationError, deprecatedProperty, behaviors }) {
-  const deprecatedFunction = () => {
-    deprecationError({
-      message: 'This function is deprecated for testing purposes.',
-    });
-  };
-  const objectWithDeprecatedProperty = deprecatedProperty({
-    target: { deprecatedProperty: 'Kitten' },
-    deprecatedProperty: 'deprecatedProperty',
-    message: 'This property is deprecated for testing purposes.',
-  });
-
-  behaviors.testDeprecations = {
-    attach: () => {
-      deprecatedFunction();
-      const deprecatedProperty =
-        objectWithDeprecatedProperty.deprecatedProperty;
-    },
-  };
-})(Drupal);
diff --git a/core/modules/system/tests/modules/js_deprecation_test/js/js_deprecation_test.js b/core/modules/system/tests/modules/js_deprecation_test/js/js_deprecation_test.js
index 00fd3e87bb09..ca93f925764c 100644
--- a/core/modules/system/tests/modules/js_deprecation_test/js/js_deprecation_test.js
+++ b/core/modules/system/tests/modules/js_deprecation_test/js/js_deprecation_test.js
@@ -1,34 +1,24 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(function (_ref) {
-  let {
-    deprecationError,
-    deprecatedProperty,
-    behaviors
-  } = _ref;
-
+ * @file
+ *  Testing tools for deprecating JavaScript functions and class properties.
+ */
+(function ({ deprecationError, deprecatedProperty, behaviors }) {
   const deprecatedFunction = () => {
     deprecationError({
-      message: 'This function is deprecated for testing purposes.'
+      message: 'This function is deprecated for testing purposes.',
     });
   };
-
   const objectWithDeprecatedProperty = deprecatedProperty({
-    target: {
-      deprecatedProperty: 'Kitten'
-    },
+    target: { deprecatedProperty: 'Kitten' },
     deprecatedProperty: 'deprecatedProperty',
-    message: 'This property is deprecated for testing purposes.'
+    message: 'This property is deprecated for testing purposes.',
   });
+
   behaviors.testDeprecations = {
     attach: () => {
       deprecatedFunction();
-      const deprecatedProperty = objectWithDeprecatedProperty.deprecatedProperty;
-    }
+      const deprecatedProperty =
+        objectWithDeprecatedProperty.deprecatedProperty;
+    },
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.es6.js b/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.es6.js
deleted file mode 100644
index 421d036ee850..000000000000
--- a/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.es6.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @file
- *  Testing tools for JavaScript errors.
- */
-(function ({ throwError, behaviors }) {
-  behaviors.testErrors = {
-    attach: () => {
-      throwError(new Error('A manually thrown error.'));
-    },
-  };
-})(Drupal);
diff --git a/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.js b/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.js
index 22f29ca63d83..421d036ee850 100644
--- a/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.js
+++ b/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.js
@@ -1,18 +1,11 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(function (_ref) {
-  let {
-    throwError,
-    behaviors
-  } = _ref;
+ * @file
+ *  Testing tools for JavaScript errors.
+ */
+(function ({ throwError, behaviors }) {
   behaviors.testErrors = {
     attach: () => {
       throwError(new Error('A manually thrown error.'));
-    }
+    },
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/modules/system/tests/modules/js_interaction_test/js/js_interaction_test.trigger_link.es6.js b/core/modules/system/tests/modules/js_interaction_test/js/js_interaction_test.trigger_link.es6.js
deleted file mode 100644
index bd47c33c00b6..000000000000
--- a/core/modules/system/tests/modules/js_interaction_test/js/js_interaction_test.trigger_link.es6.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * @file
- *  Testing behavior for JSInteractionTest.
- */
-
-(({ behaviors }) => {
-  /**
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the click listener on the trigger link.
-   */
-  behaviors.js_interaction_test_trigger_link = {
-    attach() {
-      const removeBlockerTrigger = once(
-        'remove-blocker-trigger',
-        '.remove-blocker-trigger',
-      ).shift();
-      removeBlockerTrigger.addEventListener('click', (event) => {
-        event.preventDefault();
-        setTimeout(() => {
-          document.querySelector('.blocker-element').remove();
-        }, 100);
-      });
-
-      const enableFieldTrigger = once(
-        'enable-field-trigger',
-        '.enable-field-trigger',
-      ).shift();
-      enableFieldTrigger.addEventListener('click', (event) => {
-        event.preventDefault();
-        setTimeout(() => {
-          document.querySelector('input[name="target_field"]').disabled = false;
-        }, 100);
-      });
-    },
-  };
-})(Drupal);
diff --git a/core/modules/system/tests/modules/js_interaction_test/js/js_interaction_test.trigger_link.js b/core/modules/system/tests/modules/js_interaction_test/js/js_interaction_test.trigger_link.js
index 0187dca9fc05..bd47c33c00b6 100644
--- a/core/modules/system/tests/modules/js_interaction_test/js/js_interaction_test.trigger_link.js
+++ b/core/modules/system/tests/modules/js_interaction_test/js/js_interaction_test.trigger_link.js
@@ -1,31 +1,38 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ *  Testing behavior for JSInteractionTest.
+ */
 
-(_ref => {
-  let {
-    behaviors
-  } = _ref;
+(({ behaviors }) => {
+  /**
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the click listener on the trigger link.
+   */
   behaviors.js_interaction_test_trigger_link = {
     attach() {
-      const removeBlockerTrigger = once('remove-blocker-trigger', '.remove-blocker-trigger').shift();
-      removeBlockerTrigger.addEventListener('click', event => {
+      const removeBlockerTrigger = once(
+        'remove-blocker-trigger',
+        '.remove-blocker-trigger',
+      ).shift();
+      removeBlockerTrigger.addEventListener('click', (event) => {
         event.preventDefault();
         setTimeout(() => {
           document.querySelector('.blocker-element').remove();
         }, 100);
       });
-      const enableFieldTrigger = once('enable-field-trigger', '.enable-field-trigger').shift();
-      enableFieldTrigger.addEventListener('click', event => {
+
+      const enableFieldTrigger = once(
+        'enable-field-trigger',
+        '.enable-field-trigger',
+      ).shift();
+      enableFieldTrigger.addEventListener('click', (event) => {
         event.preventDefault();
         setTimeout(() => {
           document.querySelector('input[name="target_field"]').disabled = false;
         }, 100);
       });
-    }
-
+    },
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js b/core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js
deleted file mode 100644
index 4c38b23f58d0..000000000000
--- a/core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * @file
- *  Testing behavior for JSMessageTest.
- */
-
-(($, { behaviors }, { testMessages }) => {
-  // Message types.
-  const indexes = {};
-  testMessages.types.forEach((type) => {
-    indexes[type] = [];
-  });
-
-  // Message storage.
-  const messageObjects = {
-    default: {
-      zone: new Drupal.Message(),
-      indexes,
-    },
-    multiple: [],
-  };
-  // Ensure clear() can be called on a newly created message object.
-  messageObjects.default.zone.clear();
-
-  testMessages.selectors.filter(Boolean).forEach((selector) => {
-    messageObjects[selector] = {
-      zone: new Drupal.Message(document.querySelector(selector)),
-      indexes,
-    };
-  });
-
-  /**
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Add click listeners that show and remove links with context and type.
-   */
-  behaviors.js_message_test = {
-    attach() {
-      $(once('messages-details', '[data-drupal-messages-area]')).on(
-        'click',
-        '[data-action]',
-        (e) => {
-          const $target = $(e.currentTarget);
-          const type = $target.attr('data-type');
-          const area =
-            $target
-              .closest('[data-drupal-messages-area]')
-              .attr('data-drupal-messages-area') || 'default';
-          const message = messageObjects[area].zone;
-          const action = $target.attr('data-action');
-
-          if (action === 'add') {
-            messageObjects[area].indexes[type].push(
-              message.add(
-                `This is a message of the type, ${type}. You be the judge of its importance.`,
-                { type },
-              ),
-            );
-          } else if (action === 'remove') {
-            message.remove(messageObjects[area].indexes[type].pop());
-          }
-        },
-      );
-      $(once('add-multiple', '[data-action="add-multiple"]')).on(
-        'click',
-        () => {
-          /**
-           * Add several of different types to make sure message type doesn't
-           * cause issues in the API.
-           */
-          [0, 1, 2, 3, 4, 5].forEach((i) => {
-            messageObjects.multiple.push(
-              messageObjects.default.zone.add(
-                `This is message number ${i} of the type, ${
-                  testMessages.types[i % testMessages.types.length]
-                }. You be the judge of its importance.`,
-                { type: testMessages.types[i % testMessages.types.length] },
-              ),
-            );
-          });
-        },
-      );
-      $(once('remove-multiple', '[data-action="remove-multiple"]')).on(
-        'click',
-        () => {
-          messageObjects.multiple.forEach((messageIndex) =>
-            messageObjects.default.zone.remove(messageIndex),
-          );
-          messageObjects.multiple = [];
-        },
-      );
-      $(once('add-multiple-error', '[data-action="add-multiple-error"]')).on(
-        'click',
-        () => {
-          // Use the same number of elements to facilitate things on the PHP side.
-          [0, 1, 2, 3, 4, 5].forEach((i) =>
-            messageObjects.default.zone.add(`Msg-${i}`, { type: 'error' }),
-          );
-          messageObjects.default.zone.add(
-            `Msg-${testMessages.types.length * 2}`,
-            { type: 'status' },
-          );
-        },
-      );
-      $(once('remove-type', '[data-action="remove-type"]')).on('click', () => {
-        Array.prototype.map
-          .call(
-            document.querySelectorAll('[data-drupal-message-id^="error"]'),
-            (element) => element.getAttribute('data-drupal-message-id'),
-          )
-          .forEach((id) => messageObjects.default.zone.remove(id));
-      });
-      $(once('clear-all', '[data-action="clear-all"]')).on('click', () => {
-        messageObjects.default.zone.clear();
-      });
-      $(once('id-no-status', '[data-action="id-no-status"]')).on(
-        'click',
-        () => {
-          messageObjects.default.zone.add('Msg-id-no-status', {
-            id: 'my-special-id',
-          });
-        },
-      );
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/system/tests/modules/js_message_test/js/js_message_test.js b/core/modules/system/tests/modules/js_message_test/js/js_message_test.js
index c63a5eb69dc7..4c38b23f58d0 100644
--- a/core/modules/system/tests/modules/js_message_test/js/js_message_test.js
+++ b/core/modules/system/tests/modules/js_message_test/js/js_message_test.js
@@ -1,83 +1,126 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ *  Testing behavior for JSMessageTest.
+ */
 
-(($, _ref, _ref2) => {
-  let {
-    behaviors
-  } = _ref;
-  let {
-    testMessages
-  } = _ref2;
+(($, { behaviors }, { testMessages }) => {
+  // Message types.
   const indexes = {};
-  testMessages.types.forEach(type => {
+  testMessages.types.forEach((type) => {
     indexes[type] = [];
   });
+
+  // Message storage.
   const messageObjects = {
     default: {
       zone: new Drupal.Message(),
-      indexes
+      indexes,
     },
-    multiple: []
+    multiple: [],
   };
+  // Ensure clear() can be called on a newly created message object.
   messageObjects.default.zone.clear();
-  testMessages.selectors.filter(Boolean).forEach(selector => {
+
+  testMessages.selectors.filter(Boolean).forEach((selector) => {
     messageObjects[selector] = {
       zone: new Drupal.Message(document.querySelector(selector)),
-      indexes
+      indexes,
     };
   });
+
+  /**
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Add click listeners that show and remove links with context and type.
+   */
   behaviors.js_message_test = {
     attach() {
-      $(once('messages-details', '[data-drupal-messages-area]')).on('click', '[data-action]', e => {
-        const $target = $(e.currentTarget);
-        const type = $target.attr('data-type');
-        const area = $target.closest('[data-drupal-messages-area]').attr('data-drupal-messages-area') || 'default';
-        const message = messageObjects[area].zone;
-        const action = $target.attr('data-action');
+      $(once('messages-details', '[data-drupal-messages-area]')).on(
+        'click',
+        '[data-action]',
+        (e) => {
+          const $target = $(e.currentTarget);
+          const type = $target.attr('data-type');
+          const area =
+            $target
+              .closest('[data-drupal-messages-area]')
+              .attr('data-drupal-messages-area') || 'default';
+          const message = messageObjects[area].zone;
+          const action = $target.attr('data-action');
 
-        if (action === 'add') {
-          messageObjects[area].indexes[type].push(message.add(`This is a message of the type, ${type}. You be the judge of its importance.`, {
-            type
-          }));
-        } else if (action === 'remove') {
-          message.remove(messageObjects[area].indexes[type].pop());
-        }
-      });
-      $(once('add-multiple', '[data-action="add-multiple"]')).on('click', () => {
-        [0, 1, 2, 3, 4, 5].forEach(i => {
-          messageObjects.multiple.push(messageObjects.default.zone.add(`This is message number ${i} of the type, ${testMessages.types[i % testMessages.types.length]}. You be the judge of its importance.`, {
-            type: testMessages.types[i % testMessages.types.length]
-          }));
-        });
-      });
-      $(once('remove-multiple', '[data-action="remove-multiple"]')).on('click', () => {
-        messageObjects.multiple.forEach(messageIndex => messageObjects.default.zone.remove(messageIndex));
-        messageObjects.multiple = [];
-      });
-      $(once('add-multiple-error', '[data-action="add-multiple-error"]')).on('click', () => {
-        [0, 1, 2, 3, 4, 5].forEach(i => messageObjects.default.zone.add(`Msg-${i}`, {
-          type: 'error'
-        }));
-        messageObjects.default.zone.add(`Msg-${testMessages.types.length * 2}`, {
-          type: 'status'
-        });
-      });
+          if (action === 'add') {
+            messageObjects[area].indexes[type].push(
+              message.add(
+                `This is a message of the type, ${type}. You be the judge of its importance.`,
+                { type },
+              ),
+            );
+          } else if (action === 'remove') {
+            message.remove(messageObjects[area].indexes[type].pop());
+          }
+        },
+      );
+      $(once('add-multiple', '[data-action="add-multiple"]')).on(
+        'click',
+        () => {
+          /**
+           * Add several of different types to make sure message type doesn't
+           * cause issues in the API.
+           */
+          [0, 1, 2, 3, 4, 5].forEach((i) => {
+            messageObjects.multiple.push(
+              messageObjects.default.zone.add(
+                `This is message number ${i} of the type, ${
+                  testMessages.types[i % testMessages.types.length]
+                }. You be the judge of its importance.`,
+                { type: testMessages.types[i % testMessages.types.length] },
+              ),
+            );
+          });
+        },
+      );
+      $(once('remove-multiple', '[data-action="remove-multiple"]')).on(
+        'click',
+        () => {
+          messageObjects.multiple.forEach((messageIndex) =>
+            messageObjects.default.zone.remove(messageIndex),
+          );
+          messageObjects.multiple = [];
+        },
+      );
+      $(once('add-multiple-error', '[data-action="add-multiple-error"]')).on(
+        'click',
+        () => {
+          // Use the same number of elements to facilitate things on the PHP side.
+          [0, 1, 2, 3, 4, 5].forEach((i) =>
+            messageObjects.default.zone.add(`Msg-${i}`, { type: 'error' }),
+          );
+          messageObjects.default.zone.add(
+            `Msg-${testMessages.types.length * 2}`,
+            { type: 'status' },
+          );
+        },
+      );
       $(once('remove-type', '[data-action="remove-type"]')).on('click', () => {
-        Array.prototype.map.call(document.querySelectorAll('[data-drupal-message-id^="error"]'), element => element.getAttribute('data-drupal-message-id')).forEach(id => messageObjects.default.zone.remove(id));
+        Array.prototype.map
+          .call(
+            document.querySelectorAll('[data-drupal-message-id^="error"]'),
+            (element) => element.getAttribute('data-drupal-message-id'),
+          )
+          .forEach((id) => messageObjects.default.zone.remove(id));
       });
       $(once('clear-all', '[data-action="clear-all"]')).on('click', () => {
         messageObjects.default.zone.clear();
       });
-      $(once('id-no-status', '[data-action="id-no-status"]')).on('click', () => {
-        messageObjects.default.zone.add('Msg-id-no-status', {
-          id: 'my-special-id'
-        });
-      });
-    }
-
+      $(once('id-no-status', '[data-action="id-no-status"]')).on(
+        'click',
+        () => {
+          messageObjects.default.zone.add('Msg-id-no-status', {
+            id: 'my-special-id',
+          });
+        },
+      );
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.es6.js b/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.es6.js
deleted file mode 100644
index dd6fe578ed36..000000000000
--- a/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.es6.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * @file
- *  Support code for testing JavaScript error handling in functional tests.
- */
-(function (Drupal) {
-  if (typeof console !== 'undefined' && console.warn) {
-    const originalWarnFunction = console.warn;
-    console.warn = (warning) => {
-      const warnings = JSON.parse(
-        sessionStorage.getItem('js_testing_log_test.warnings') ||
-          JSON.stringify([]),
-      );
-      warnings.push(warning);
-      sessionStorage.setItem(
-        'js_testing_log_test.warnings',
-        JSON.stringify(warnings),
-      );
-      originalWarnFunction(warning);
-    };
-
-    const originalThrowFunction = Drupal.throwError;
-    Drupal.throwError = (error) => {
-      const errors = JSON.parse(
-        sessionStorage.getItem('js_testing_log_test.errors') ||
-          JSON.stringify([]),
-      );
-      errors.push(error.stack);
-      sessionStorage.setItem(
-        'js_testing_log_test.errors',
-        JSON.stringify(errors),
-      );
-      originalThrowFunction(error);
-    };
-  }
-})(Drupal);
diff --git a/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.js b/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.js
index bf4904dd6ad3..dd6fe578ed36 100644
--- a/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.js
+++ b/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.js
@@ -1,28 +1,35 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * @file
+ *  Support code for testing JavaScript error handling in functional tests.
+ */
 (function (Drupal) {
   if (typeof console !== 'undefined' && console.warn) {
     const originalWarnFunction = console.warn;
-
-    console.warn = warning => {
-      const warnings = JSON.parse(sessionStorage.getItem('js_testing_log_test.warnings') || JSON.stringify([]));
+    console.warn = (warning) => {
+      const warnings = JSON.parse(
+        sessionStorage.getItem('js_testing_log_test.warnings') ||
+          JSON.stringify([]),
+      );
       warnings.push(warning);
-      sessionStorage.setItem('js_testing_log_test.warnings', JSON.stringify(warnings));
+      sessionStorage.setItem(
+        'js_testing_log_test.warnings',
+        JSON.stringify(warnings),
+      );
       originalWarnFunction(warning);
     };
 
     const originalThrowFunction = Drupal.throwError;
-
-    Drupal.throwError = error => {
-      const errors = JSON.parse(sessionStorage.getItem('js_testing_log_test.errors') || JSON.stringify([]));
+    Drupal.throwError = (error) => {
+      const errors = JSON.parse(
+        sessionStorage.getItem('js_testing_log_test.errors') ||
+          JSON.stringify([]),
+      );
       errors.push(error.stack);
-      sessionStorage.setItem('js_testing_log_test.errors', JSON.stringify(errors));
+      sessionStorage.setItem(
+        'js_testing_log_test.errors',
+        JSON.stringify(errors),
+      );
       originalThrowFunction(error);
     };
   }
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.es6.js b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.es6.js
deleted file mode 100644
index a22c818079f4..000000000000
--- a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.es6.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @file
- *  Testing behavior for JSWebAssertTest.
- */
-
-(($, Drupal) => {
-  /**
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Makes changes in the DOM to be able to test the completion of AJAX in assertWaitOnAjaxRequest.
-   */
-  Drupal.behaviors.js_webassert_test_wait_for_ajax_request = {
-    attach() {
-      $('#edit-test-assert-no-element-after-wait-pass').on('click', (e) => {
-        e.preventDefault();
-        setTimeout(() => {
-          $('#edit-test-assert-no-element-after-wait-pass').remove();
-        }, 500);
-      });
-
-      $('#edit-test-assert-no-element-after-wait-fail').on('click', (e) => {
-        e.preventDefault();
-        setTimeout(() => {
-          $('#edit-test-assert-no-element-after-wait-fail').remove();
-        }, 2000);
-      });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.js b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.js
index 7241cbb7f80b..a22c818079f4 100644
--- a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.js
+++ b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.js
@@ -1,26 +1,30 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ *  Testing behavior for JSWebAssertTest.
+ */
 
 (($, Drupal) => {
+  /**
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Makes changes in the DOM to be able to test the completion of AJAX in assertWaitOnAjaxRequest.
+   */
   Drupal.behaviors.js_webassert_test_wait_for_ajax_request = {
     attach() {
-      $('#edit-test-assert-no-element-after-wait-pass').on('click', e => {
+      $('#edit-test-assert-no-element-after-wait-pass').on('click', (e) => {
         e.preventDefault();
         setTimeout(() => {
           $('#edit-test-assert-no-element-after-wait-pass').remove();
         }, 500);
       });
-      $('#edit-test-assert-no-element-after-wait-fail').on('click', e => {
+
+      $('#edit-test-assert-no-element-after-wait-fail').on('click', (e) => {
         e.preventDefault();
         setTimeout(() => {
           $('#edit-test-assert-no-element-after-wait-fail').remove();
         }, 2000);
       });
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_ajax_request.es6.js b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_ajax_request.es6.js
deleted file mode 100644
index abea6396e250..000000000000
--- a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_ajax_request.es6.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * @file
- *  Testing behavior for JSWebAssertTest.
- */
-
-(function (Drupal, drupalSettings) {
-  /**
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Makes changes in the DOM to be able to test the completion of AJAX in assertWaitOnAjaxRequest.
-   */
-  Drupal.behaviors.js_webassert_test_wait_for_ajax_request = {
-    attach(context) {
-      const waitAjaxInput = document.querySelector(
-        'input[name="test_assert_wait_on_ajax_input"]',
-      );
-      // Confirm the input exists before assigning a value to it.
-      if (waitAjaxInput) {
-        waitAjaxInput.value = 'js_webassert_test';
-      }
-    },
-  };
-})(Drupal, drupalSettings);
diff --git a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_ajax_request.js b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_ajax_request.js
index a62ccd82f4ce..abea6396e250 100644
--- a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_ajax_request.js
+++ b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_ajax_request.js
@@ -1,19 +1,24 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ *  Testing behavior for JSWebAssertTest.
+ */
 
 (function (Drupal, drupalSettings) {
+  /**
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Makes changes in the DOM to be able to test the completion of AJAX in assertWaitOnAjaxRequest.
+   */
   Drupal.behaviors.js_webassert_test_wait_for_ajax_request = {
     attach(context) {
-      const waitAjaxInput = document.querySelector('input[name="test_assert_wait_on_ajax_input"]');
-
+      const waitAjaxInput = document.querySelector(
+        'input[name="test_assert_wait_on_ajax_input"]',
+      );
+      // Confirm the input exists before assigning a value to it.
       if (waitAjaxInput) {
         waitAjaxInput.value = 'js_webassert_test';
       }
-    }
-
+    },
   };
-})(Drupal, drupalSettings);
\ No newline at end of file
+})(Drupal, drupalSettings);
diff --git a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_element.es6.js b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_element.es6.js
deleted file mode 100644
index 0017d6a913e6..000000000000
--- a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_element.es6.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * @file
- *  Testing behavior for JSWebAssertTest.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Makes changes in the DOM to be able to test the completion of AJAX in assertWaitOnAjaxRequest.
-   */
-  Drupal.behaviors.js_webassert_test_wait_for_element = {
-    attach(context) {
-      $('#js_webassert_test_element_invisible').show();
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_element.js b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_element.js
index d42862110163..0017d6a913e6 100644
--- a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_element.js
+++ b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.wait_for_element.js
@@ -1,15 +1,18 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ *  Testing behavior for JSWebAssertTest.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Makes changes in the DOM to be able to test the completion of AJAX in assertWaitOnAjaxRequest.
+   */
   Drupal.behaviors.js_webassert_test_wait_for_element = {
     attach(context) {
       $('#js_webassert_test_element_invisible').show();
-    }
-
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/system/tests/modules/off_canvas_test/js/resize-helper.es6.js b/core/modules/system/tests/modules/off_canvas_test/js/resize-helper.es6.js
deleted file mode 100644
index c7dd3de9bf53..000000000000
--- a/core/modules/system/tests/modules/off_canvas_test/js/resize-helper.es6.js
+++ /dev/null
@@ -1,18 +0,0 @@
-(function ({ offCanvas }) {
-  const originalResetSize = offCanvas.resetSize;
-
-  /**
-   * Wraps the Drupal.offCanvas.resetSize() method.
-   *
-   * @param {jQuery.Event} event
-   *   The event triggered.
-   * @param {object} event.data
-   *   Data attached to the event.
-   */
-  offCanvas.resetSize = (event) => {
-    originalResetSize(event);
-    // Set an attribute so that tests can reliably detect when the off-canvas
-    // area has been resized.
-    event.data.$element.attr('data-resize-done', 'true');
-  };
-})(Drupal);
diff --git a/core/modules/system/tests/modules/off_canvas_test/js/resize-helper.js b/core/modules/system/tests/modules/off_canvas_test/js/resize-helper.js
index 77c613f3fa25..c7dd3de9bf53 100644
--- a/core/modules/system/tests/modules/off_canvas_test/js/resize-helper.js
+++ b/core/modules/system/tests/modules/off_canvas_test/js/resize-helper.js
@@ -1,18 +1,18 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(function (_ref) {
-  let {
-    offCanvas
-  } = _ref;
+(function ({ offCanvas }) {
   const originalResetSize = offCanvas.resetSize;
 
-  offCanvas.resetSize = event => {
+  /**
+   * Wraps the Drupal.offCanvas.resetSize() method.
+   *
+   * @param {jQuery.Event} event
+   *   The event triggered.
+   * @param {object} event.data
+   *   Data attached to the event.
+   */
+  offCanvas.resetSize = (event) => {
     originalResetSize(event);
+    // Set an attribute so that tests can reliably detect when the off-canvas
+    // area has been resized.
     event.data.$element.attr('data-resize-done', 'true');
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/modules/system/tests/modules/olivero_test/js/log-errors.es6.js b/core/modules/system/tests/modules/olivero_test/js/log-errors.es6.js
deleted file mode 100644
index 676f0a50190f..000000000000
--- a/core/modules/system/tests/modules/olivero_test/js/log-errors.es6.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- * @file
- * Log all errors.
- */
-
-Drupal.errorLog = [];
-
-window.addEventListener('error', (e) => {
-  Drupal.errorLog.push(e);
-});
diff --git a/core/modules/system/tests/modules/olivero_test/js/log-errors.js b/core/modules/system/tests/modules/olivero_test/js/log-errors.js
index 60cdc04e786c..676f0a50190f 100644
--- a/core/modules/system/tests/modules/olivero_test/js/log-errors.js
+++ b/core/modules/system/tests/modules/olivero_test/js/log-errors.js
@@ -1,11 +1,10 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Log all errors.
+ */
 
 Drupal.errorLog = [];
-window.addEventListener('error', e => {
+
+window.addEventListener('error', (e) => {
   Drupal.errorLog.push(e);
-});
\ No newline at end of file
+});
diff --git a/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.es6.js b/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.es6.js
deleted file mode 100644
index b0d631cc9b42..000000000000
--- a/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.es6.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * @file
- * Testing behaviors for tabledrag library.
- */
-(function ($, Drupal) {
-  /**
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Removes a test class from the handle elements to allow verifying that
-   *   dragging operations have been executed.
-   */
-  Drupal.behaviors.tableDragTest = {
-    attach(context) {
-      $(once('tabledrag-test', '.tabledrag-handle', context)).on(
-        'keydown.tabledrag-test',
-        (event) => {
-          $(event.currentTarget).removeClass('tabledrag-test-dragging');
-        },
-      );
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.js b/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.js
index c0ee7081b061..b0d631cc9b42 100644
--- a/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.js
+++ b/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.js
@@ -1,17 +1,23 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * @file
+ * Testing behaviors for tabledrag library.
+ */
 (function ($, Drupal) {
+  /**
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Removes a test class from the handle elements to allow verifying that
+   *   dragging operations have been executed.
+   */
   Drupal.behaviors.tableDragTest = {
     attach(context) {
-      $(once('tabledrag-test', '.tabledrag-handle', context)).on('keydown.tabledrag-test', event => {
-        $(event.currentTarget).removeClass('tabledrag-test-dragging');
-      });
-    }
-
+      $(once('tabledrag-test', '.tabledrag-handle', context)).on(
+        'keydown.tabledrag-test',
+        (event) => {
+          $(event.currentTarget).removeClass('tabledrag-test-dragging');
+        },
+      );
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.es6.js b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.es6.js
deleted file mode 100644
index 39bf0bb5724f..000000000000
--- a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.es6.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * @file
- * This file is for testing asset file inclusion, no contents are necessary.
- *
- * @ignore
- */
diff --git a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.js b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.js
index 9d11a7c1c32d..39bf0bb5724f 100644
--- a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.js
+++ b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.js
@@ -1,6 +1,6 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
\ No newline at end of file
+ * @file
+ * This file is for testing asset file inclusion, no contents are necessary.
+ *
+ * @ignore
+ */
diff --git a/core/modules/system/tests/themes/test_theme/js/collapse.es6.js b/core/modules/system/tests/themes/test_theme/js/collapse.es6.js
deleted file mode 100644
index 4d66841e8164..000000000000
--- a/core/modules/system/tests/themes/test_theme/js/collapse.es6.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * @file
- * Test JS asset file for test_theme.theme.
- */
diff --git a/core/modules/system/tests/themes/test_theme/js/collapse.js b/core/modules/system/tests/themes/test_theme/js/collapse.js
index 9d11a7c1c32d..4d66841e8164 100644
--- a/core/modules/system/tests/themes/test_theme/js/collapse.js
+++ b/core/modules/system/tests/themes/test_theme/js/collapse.js
@@ -1,6 +1,4 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
\ No newline at end of file
+ * @file
+ * Test JS asset file for test_theme.theme.
+ */
diff --git a/core/modules/taxonomy/taxonomy.es6.js b/core/modules/taxonomy/taxonomy.es6.js
deleted file mode 100644
index 7b9d9298e258..000000000000
--- a/core/modules/taxonomy/taxonomy.es6.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * @file
- * Taxonomy behaviors.
- */
-
-(function ($, Drupal) {
-  /**
-   * Reorder taxonomy terms.
-   *
-   * This behavior is dependent on the tableDrag behavior, since it uses the
-   * objects initialized in that behavior to update the row.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the drag behavior to an applicable table element.
-   */
-  Drupal.behaviors.termDrag = {
-    attach(context, settings) {
-      const backStep = settings.taxonomy.backStep;
-      const forwardStep = settings.taxonomy.forwardStep;
-      // Get the taxonomy tableDrag object.
-      const tableDrag = Drupal.tableDrag.taxonomy;
-      const $table = $('#taxonomy');
-      const rows = $table.find('tr').length;
-
-      // When a row is swapped, keep previous and next page classes set.
-      tableDrag.row.prototype.onSwap = function (swappedRow) {
-        $table
-          .find('tr.taxonomy-term-preview')
-          .removeClass('taxonomy-term-preview');
-        $table
-          .find('tr.taxonomy-term-divider-top')
-          .removeClass('taxonomy-term-divider-top');
-        $table
-          .find('tr.taxonomy-term-divider-bottom')
-          .removeClass('taxonomy-term-divider-bottom');
-
-        const tableBody = $table[0].tBodies[0];
-        if (backStep) {
-          for (let n = 0; n < backStep; n++) {
-            $(tableBody.rows[n]).addClass('taxonomy-term-preview');
-          }
-          $(tableBody.rows[backStep - 1]).addClass('taxonomy-term-divider-top');
-          $(tableBody.rows[backStep]).addClass('taxonomy-term-divider-bottom');
-        }
-
-        if (forwardStep) {
-          for (let k = rows - forwardStep - 1; k < rows - 1; k++) {
-            $(tableBody.rows[k]).addClass('taxonomy-term-preview');
-          }
-          $(tableBody.rows[rows - forwardStep - 2]).addClass(
-            'taxonomy-term-divider-top',
-          );
-          $(tableBody.rows[rows - forwardStep - 1]).addClass(
-            'taxonomy-term-divider-bottom',
-          );
-        }
-      };
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/taxonomy/taxonomy.js b/core/modules/taxonomy/taxonomy.js
index 8b65002ce8b2..7b9d9298e258 100644
--- a/core/modules/taxonomy/taxonomy.js
+++ b/core/modules/taxonomy/taxonomy.js
@@ -1,30 +1,46 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Taxonomy behaviors.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Reorder taxonomy terms.
+   *
+   * This behavior is dependent on the tableDrag behavior, since it uses the
+   * objects initialized in that behavior to update the row.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the drag behavior to an applicable table element.
+   */
   Drupal.behaviors.termDrag = {
     attach(context, settings) {
       const backStep = settings.taxonomy.backStep;
       const forwardStep = settings.taxonomy.forwardStep;
+      // Get the taxonomy tableDrag object.
       const tableDrag = Drupal.tableDrag.taxonomy;
       const $table = $('#taxonomy');
       const rows = $table.find('tr').length;
 
+      // When a row is swapped, keep previous and next page classes set.
       tableDrag.row.prototype.onSwap = function (swappedRow) {
-        $table.find('tr.taxonomy-term-preview').removeClass('taxonomy-term-preview');
-        $table.find('tr.taxonomy-term-divider-top').removeClass('taxonomy-term-divider-top');
-        $table.find('tr.taxonomy-term-divider-bottom').removeClass('taxonomy-term-divider-bottom');
-        const tableBody = $table[0].tBodies[0];
+        $table
+          .find('tr.taxonomy-term-preview')
+          .removeClass('taxonomy-term-preview');
+        $table
+          .find('tr.taxonomy-term-divider-top')
+          .removeClass('taxonomy-term-divider-top');
+        $table
+          .find('tr.taxonomy-term-divider-bottom')
+          .removeClass('taxonomy-term-divider-bottom');
 
+        const tableBody = $table[0].tBodies[0];
         if (backStep) {
           for (let n = 0; n < backStep; n++) {
             $(tableBody.rows[n]).addClass('taxonomy-term-preview');
           }
-
           $(tableBody.rows[backStep - 1]).addClass('taxonomy-term-divider-top');
           $(tableBody.rows[backStep]).addClass('taxonomy-term-divider-bottom');
         }
@@ -33,12 +49,14 @@
           for (let k = rows - forwardStep - 1; k < rows - 1; k++) {
             $(tableBody.rows[k]).addClass('taxonomy-term-preview');
           }
-
-          $(tableBody.rows[rows - forwardStep - 2]).addClass('taxonomy-term-divider-top');
-          $(tableBody.rows[rows - forwardStep - 1]).addClass('taxonomy-term-divider-bottom');
+          $(tableBody.rows[rows - forwardStep - 2]).addClass(
+            'taxonomy-term-divider-top',
+          );
+          $(tableBody.rows[rows - forwardStep - 1]).addClass(
+            'taxonomy-term-divider-bottom',
+          );
         }
       };
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/text/text.es6.js b/core/modules/text/text.es6.js
deleted file mode 100644
index c584f2dbd132..000000000000
--- a/core/modules/text/text.es6.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @file
- * Text behaviors.
- */
-
-(function ($, Drupal) {
-  /**
-   * Auto-hide summary textarea if empty and show hide and unhide links.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches auto-hide behavior on `text-summary` events.
-   */
-  Drupal.behaviors.textSummary = {
-    attach(context, settings) {
-      once('text-summary', '.js-text-summary', context).forEach((summary) => {
-        const $widget = $(summary).closest('.js-text-format-wrapper');
-
-        const $summary = $widget.find('.js-text-summary-wrapper');
-        const $summaryLabel = $summary.find('label').eq(0);
-        const $full = $widget.children('.js-form-type-textarea');
-        let $fullLabel = $full.find('label').eq(0);
-
-        // Create a placeholder label when the field cardinality is greater
-        // than 1.
-        if ($fullLabel.length === 0) {
-          $fullLabel = $('<label></label>').prependTo($full);
-        }
-
-        // To ensure the summary toggle is shown in case the label is hidden
-        // (in multivalue fields in particular), show the label but hide
-        // the original text of the label.
-        if ($fullLabel.hasClass('visually-hidden')) {
-          $fullLabel.html(
-            (index, oldHtml) =>
-              `<span class="visually-hidden">${oldHtml}</span>`,
-          );
-          $fullLabel.removeClass('visually-hidden');
-        }
-
-        // Set up the edit/hide summary link.
-        const $link = $(
-          `<span class="field-edit-link"> (<button type="button" class="link link-edit-summary">${Drupal.t(
-            'Hide summary',
-          )}</button>)</span>`,
-        );
-        const $button = $link.find('button');
-        let toggleClick = true;
-        $link
-          .on('click', (e) => {
-            if (toggleClick) {
-              $summary.hide();
-              $button.html(Drupal.t('Edit summary'));
-              $link.appendTo($fullLabel);
-            } else {
-              $summary.show();
-              $button.html(Drupal.t('Hide summary'));
-              $link.appendTo($summaryLabel);
-            }
-            e.preventDefault();
-            toggleClick = !toggleClick;
-          })
-          .appendTo($summaryLabel);
-
-        // If no summary is set, hide the summary field.
-        if (summary.value === '') {
-          $link.trigger('click');
-        }
-      });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/text/text.js b/core/modules/text/text.js
index 0996a9e4f288..c584f2dbd132 100644
--- a/core/modules/text/text.js
+++ b/core/modules/text/text.js
@@ -1,52 +1,73 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Text behaviors.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Auto-hide summary textarea if empty and show hide and unhide links.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches auto-hide behavior on `text-summary` events.
+   */
   Drupal.behaviors.textSummary = {
     attach(context, settings) {
-      once('text-summary', '.js-text-summary', context).forEach(summary => {
+      once('text-summary', '.js-text-summary', context).forEach((summary) => {
         const $widget = $(summary).closest('.js-text-format-wrapper');
+
         const $summary = $widget.find('.js-text-summary-wrapper');
         const $summaryLabel = $summary.find('label').eq(0);
         const $full = $widget.children('.js-form-type-textarea');
         let $fullLabel = $full.find('label').eq(0);
 
+        // Create a placeholder label when the field cardinality is greater
+        // than 1.
         if ($fullLabel.length === 0) {
           $fullLabel = $('<label></label>').prependTo($full);
         }
 
+        // To ensure the summary toggle is shown in case the label is hidden
+        // (in multivalue fields in particular), show the label but hide
+        // the original text of the label.
         if ($fullLabel.hasClass('visually-hidden')) {
-          $fullLabel.html((index, oldHtml) => `<span class="visually-hidden">${oldHtml}</span>`);
+          $fullLabel.html(
+            (index, oldHtml) =>
+              `<span class="visually-hidden">${oldHtml}</span>`,
+          );
           $fullLabel.removeClass('visually-hidden');
         }
 
-        const $link = $(`<span class="field-edit-link"> (<button type="button" class="link link-edit-summary">${Drupal.t('Hide summary')}</button>)</span>`);
+        // Set up the edit/hide summary link.
+        const $link = $(
+          `<span class="field-edit-link"> (<button type="button" class="link link-edit-summary">${Drupal.t(
+            'Hide summary',
+          )}</button>)</span>`,
+        );
         const $button = $link.find('button');
         let toggleClick = true;
-        $link.on('click', e => {
-          if (toggleClick) {
-            $summary.hide();
-            $button.html(Drupal.t('Edit summary'));
-            $link.appendTo($fullLabel);
-          } else {
-            $summary.show();
-            $button.html(Drupal.t('Hide summary'));
-            $link.appendTo($summaryLabel);
-          }
-
-          e.preventDefault();
-          toggleClick = !toggleClick;
-        }).appendTo($summaryLabel);
+        $link
+          .on('click', (e) => {
+            if (toggleClick) {
+              $summary.hide();
+              $button.html(Drupal.t('Edit summary'));
+              $link.appendTo($fullLabel);
+            } else {
+              $summary.show();
+              $button.html(Drupal.t('Hide summary'));
+              $link.appendTo($summaryLabel);
+            }
+            e.preventDefault();
+            toggleClick = !toggleClick;
+          })
+          .appendTo($summaryLabel);
 
+        // If no summary is set, hide the summary field.
         if (summary.value === '') {
           $link.trigger('click');
         }
       });
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/toolbar/js/escapeAdmin.es6.js b/core/modules/toolbar/js/escapeAdmin.es6.js
deleted file mode 100644
index 30af90bd36cf..000000000000
--- a/core/modules/toolbar/js/escapeAdmin.es6.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * @file
- * Replaces the home link in toolbar with a back to site link.
- */
-
-(function ($, Drupal, drupalSettings) {
-  const pathInfo = drupalSettings.path;
-  const escapeAdminPath = sessionStorage.getItem('escapeAdminPath');
-  const windowLocation = window.location;
-
-  // Saves the last non-administrative page in the browser to be able to link
-  // back to it when browsing administrative pages. If there is a destination
-  // parameter there is not need to save the current path because the page is
-  // loaded within an existing "workflow".
-  if (
-    !pathInfo.currentPathIsAdmin &&
-    !/destination=/.test(windowLocation.search)
-  ) {
-    sessionStorage.setItem('escapeAdminPath', windowLocation);
-  }
-
-  /**
-   * Replaces the "Home" link with "Back to site" link.
-   *
-   * Back to site link points to the last non-administrative page the user
-   * visited within the same browser tab.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the replacement functionality to the toolbar-escape-admin element.
-   */
-  Drupal.behaviors.escapeAdmin = {
-    attach() {
-      const toolbarEscape = once('escapeAdmin', '[data-toolbar-escape-admin]');
-      if (toolbarEscape.length && pathInfo.currentPathIsAdmin) {
-        if (escapeAdminPath !== null) {
-          $(toolbarEscape).attr('href', escapeAdminPath);
-        } else {
-          toolbarEscape[0].textContent = Drupal.t('Home');
-        }
-      }
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/toolbar/js/escapeAdmin.js b/core/modules/toolbar/js/escapeAdmin.js
index 151fff189fd3..30af90bd36cf 100644
--- a/core/modules/toolbar/js/escapeAdmin.js
+++ b/core/modules/toolbar/js/escapeAdmin.js
@@ -1,23 +1,38 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Replaces the home link in toolbar with a back to site link.
+ */
 
 (function ($, Drupal, drupalSettings) {
   const pathInfo = drupalSettings.path;
   const escapeAdminPath = sessionStorage.getItem('escapeAdminPath');
   const windowLocation = window.location;
 
-  if (!pathInfo.currentPathIsAdmin && !/destination=/.test(windowLocation.search)) {
+  // Saves the last non-administrative page in the browser to be able to link
+  // back to it when browsing administrative pages. If there is a destination
+  // parameter there is not need to save the current path because the page is
+  // loaded within an existing "workflow".
+  if (
+    !pathInfo.currentPathIsAdmin &&
+    !/destination=/.test(windowLocation.search)
+  ) {
     sessionStorage.setItem('escapeAdminPath', windowLocation);
   }
 
+  /**
+   * Replaces the "Home" link with "Back to site" link.
+   *
+   * Back to site link points to the last non-administrative page the user
+   * visited within the same browser tab.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the replacement functionality to the toolbar-escape-admin element.
+   */
   Drupal.behaviors.escapeAdmin = {
     attach() {
       const toolbarEscape = once('escapeAdmin', '[data-toolbar-escape-admin]');
-
       if (toolbarEscape.length && pathInfo.currentPathIsAdmin) {
         if (escapeAdminPath !== null) {
           $(toolbarEscape).attr('href', escapeAdminPath);
@@ -25,7 +40,6 @@
           toolbarEscape[0].textContent = Drupal.t('Home');
         }
       }
-    }
-
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/toolbar/js/models/MenuModel.es6.js b/core/modules/toolbar/js/models/MenuModel.es6.js
deleted file mode 100644
index 3d5f8352e114..000000000000
--- a/core/modules/toolbar/js/models/MenuModel.es6.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * @file
- * A Backbone Model for collapsible menus.
- */
-
-(function (Backbone, Drupal) {
-  /**
-   * Backbone Model for collapsible menus.
-   *
-   * @constructor
-   *
-   * @augments Backbone.Model
-   */
-  Drupal.toolbar.MenuModel = Backbone.Model.extend(
-    /** @lends Drupal.toolbar.MenuModel# */ {
-      /**
-       * @type {object}
-       *
-       * @prop {object} subtrees
-       */
-      defaults: /** @lends Drupal.toolbar.MenuModel# */ {
-        /**
-         * @type {object}
-         */
-        subtrees: {},
-      },
-    },
-  );
-})(Backbone, Drupal);
diff --git a/core/modules/toolbar/js/models/MenuModel.js b/core/modules/toolbar/js/models/MenuModel.js
index e3217fff9782..3d5f8352e114 100644
--- a/core/modules/toolbar/js/models/MenuModel.js
+++ b/core/modules/toolbar/js/models/MenuModel.js
@@ -1,14 +1,29 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone Model for collapsible menus.
+ */
 
 (function (Backbone, Drupal) {
-  Drupal.toolbar.MenuModel = Backbone.Model.extend({
-    defaults: {
-      subtrees: {}
-    }
-  });
-})(Backbone, Drupal);
\ No newline at end of file
+  /**
+   * Backbone Model for collapsible menus.
+   *
+   * @constructor
+   *
+   * @augments Backbone.Model
+   */
+  Drupal.toolbar.MenuModel = Backbone.Model.extend(
+    /** @lends Drupal.toolbar.MenuModel# */ {
+      /**
+       * @type {object}
+       *
+       * @prop {object} subtrees
+       */
+      defaults: /** @lends Drupal.toolbar.MenuModel# */ {
+        /**
+         * @type {object}
+         */
+        subtrees: {},
+      },
+    },
+  );
+})(Backbone, Drupal);
diff --git a/core/modules/toolbar/js/models/ToolbarModel.es6.js b/core/modules/toolbar/js/models/ToolbarModel.es6.js
deleted file mode 100644
index ccc0bc06c2e7..000000000000
--- a/core/modules/toolbar/js/models/ToolbarModel.es6.js
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * @file
- * A Backbone Model for the toolbar.
- */
-
-(function (Backbone, Drupal) {
-  /**
-   * Backbone model for the toolbar.
-   *
-   * @constructor
-   *
-   * @augments Backbone.Model
-   */
-  Drupal.toolbar.ToolbarModel = Backbone.Model.extend(
-    /** @lends Drupal.toolbar.ToolbarModel# */ {
-      /**
-       * @type {object}
-       *
-       * @prop activeTab
-       * @prop activeTray
-       * @prop isOriented
-       * @prop isFixed
-       * @prop areSubtreesLoaded
-       * @prop isViewportOverflowConstrained
-       * @prop orientation
-       * @prop locked
-       * @prop isTrayToggleVisible
-       * @prop height
-       * @prop offsets
-       */
-      defaults: /** @lends Drupal.toolbar.ToolbarModel# */ {
-        /**
-         * The active toolbar tab. All other tabs should be inactive under
-         * normal circumstances. It will remain active across page loads. The
-         * active item is stored as an ID selector e.g. '#toolbar-item--1'.
-         *
-         * @type {string}
-         */
-        activeTab: null,
-
-        /**
-         * Represents whether a tray is open or not. Stored as an ID selector e.g.
-         * '#toolbar-item--1-tray'.
-         *
-         * @type {string}
-         */
-        activeTray: null,
-
-        /**
-         * Indicates whether the toolbar is displayed in an oriented fashion,
-         * either horizontal or vertical.
-         *
-         * @type {bool}
-         */
-        isOriented: false,
-
-        /**
-         * Indicates whether the toolbar is positioned absolute (false) or fixed
-         * (true).
-         *
-         * @type {bool}
-         */
-        isFixed: false,
-
-        /**
-         * Menu subtrees are loaded through an AJAX request only when the Toolbar
-         * is set to a vertical orientation.
-         *
-         * @type {bool}
-         */
-        areSubtreesLoaded: false,
-
-        /**
-         * If the viewport overflow becomes constrained, isFixed must be true so
-         * that elements in the trays aren't lost off-screen and impossible to
-         * get to.
-         *
-         * @type {bool}
-         */
-        isViewportOverflowConstrained: false,
-
-        /**
-         * The orientation of the active tray.
-         *
-         * @type {string}
-         */
-        orientation: 'horizontal',
-
-        /**
-         * A tray is locked if a user toggled it to vertical. Otherwise a tray
-         * will switch between vertical and horizontal orientation based on the
-         * configured breakpoints. The locked state will be maintained across page
-         * loads.
-         *
-         * @type {bool}
-         */
-        locked: false,
-
-        /**
-         * Indicates whether the tray orientation toggle is visible.
-         *
-         * @type {bool}
-         */
-        isTrayToggleVisible: true,
-
-        /**
-         * The height of the toolbar.
-         *
-         * @type {number}
-         */
-        height: null,
-
-        /**
-         * The current viewport offsets determined by {@link Drupal.displace}. The
-         * offsets suggest how a module might position is components relative to
-         * the viewport.
-         *
-         * @type {object}
-         *
-         * @prop {number} top
-         * @prop {number} right
-         * @prop {number} bottom
-         * @prop {number} left
-         */
-        offsets: {
-          top: 0,
-          right: 0,
-          bottom: 0,
-          left: 0,
-        },
-      },
-
-      /**
-       * {@inheritdoc}
-       *
-       * @param {object} attributes
-       *   Attributes for the toolbar.
-       * @param {object} options
-       *   Options for the toolbar.
-       *
-       * @return {string|undefined}
-       *   Returns an error message if validation failed.
-       */
-      validate(attributes, options) {
-        // Prevent the orientation being set to horizontal if it is locked, unless
-        // override has not been passed as an option.
-        if (
-          attributes.orientation === 'horizontal' &&
-          this.get('locked') &&
-          !options.override
-        ) {
-          return Drupal.t(
-            'The toolbar cannot be set to a horizontal orientation when it is locked.',
-          );
-        }
-      },
-    },
-  );
-})(Backbone, Drupal);
diff --git a/core/modules/toolbar/js/models/ToolbarModel.js b/core/modules/toolbar/js/models/ToolbarModel.js
index 379894e181e7..ccc0bc06c2e7 100644
--- a/core/modules/toolbar/js/models/ToolbarModel.js
+++ b/core/modules/toolbar/js/models/ToolbarModel.js
@@ -1,36 +1,159 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone Model for the toolbar.
+ */
 
 (function (Backbone, Drupal) {
-  Drupal.toolbar.ToolbarModel = Backbone.Model.extend({
-    defaults: {
-      activeTab: null,
-      activeTray: null,
-      isOriented: false,
-      isFixed: false,
-      areSubtreesLoaded: false,
-      isViewportOverflowConstrained: false,
-      orientation: 'horizontal',
-      locked: false,
-      isTrayToggleVisible: true,
-      height: null,
-      offsets: {
-        top: 0,
-        right: 0,
-        bottom: 0,
-        left: 0
-      }
-    },
+  /**
+   * Backbone model for the toolbar.
+   *
+   * @constructor
+   *
+   * @augments Backbone.Model
+   */
+  Drupal.toolbar.ToolbarModel = Backbone.Model.extend(
+    /** @lends Drupal.toolbar.ToolbarModel# */ {
+      /**
+       * @type {object}
+       *
+       * @prop activeTab
+       * @prop activeTray
+       * @prop isOriented
+       * @prop isFixed
+       * @prop areSubtreesLoaded
+       * @prop isViewportOverflowConstrained
+       * @prop orientation
+       * @prop locked
+       * @prop isTrayToggleVisible
+       * @prop height
+       * @prop offsets
+       */
+      defaults: /** @lends Drupal.toolbar.ToolbarModel# */ {
+        /**
+         * The active toolbar tab. All other tabs should be inactive under
+         * normal circumstances. It will remain active across page loads. The
+         * active item is stored as an ID selector e.g. '#toolbar-item--1'.
+         *
+         * @type {string}
+         */
+        activeTab: null,
+
+        /**
+         * Represents whether a tray is open or not. Stored as an ID selector e.g.
+         * '#toolbar-item--1-tray'.
+         *
+         * @type {string}
+         */
+        activeTray: null,
+
+        /**
+         * Indicates whether the toolbar is displayed in an oriented fashion,
+         * either horizontal or vertical.
+         *
+         * @type {bool}
+         */
+        isOriented: false,
+
+        /**
+         * Indicates whether the toolbar is positioned absolute (false) or fixed
+         * (true).
+         *
+         * @type {bool}
+         */
+        isFixed: false,
+
+        /**
+         * Menu subtrees are loaded through an AJAX request only when the Toolbar
+         * is set to a vertical orientation.
+         *
+         * @type {bool}
+         */
+        areSubtreesLoaded: false,
+
+        /**
+         * If the viewport overflow becomes constrained, isFixed must be true so
+         * that elements in the trays aren't lost off-screen and impossible to
+         * get to.
+         *
+         * @type {bool}
+         */
+        isViewportOverflowConstrained: false,
 
-    validate(attributes, options) {
-      if (attributes.orientation === 'horizontal' && this.get('locked') && !options.override) {
-        return Drupal.t('The toolbar cannot be set to a horizontal orientation when it is locked.');
-      }
-    }
+        /**
+         * The orientation of the active tray.
+         *
+         * @type {string}
+         */
+        orientation: 'horizontal',
 
-  });
-})(Backbone, Drupal);
\ No newline at end of file
+        /**
+         * A tray is locked if a user toggled it to vertical. Otherwise a tray
+         * will switch between vertical and horizontal orientation based on the
+         * configured breakpoints. The locked state will be maintained across page
+         * loads.
+         *
+         * @type {bool}
+         */
+        locked: false,
+
+        /**
+         * Indicates whether the tray orientation toggle is visible.
+         *
+         * @type {bool}
+         */
+        isTrayToggleVisible: true,
+
+        /**
+         * The height of the toolbar.
+         *
+         * @type {number}
+         */
+        height: null,
+
+        /**
+         * The current viewport offsets determined by {@link Drupal.displace}. The
+         * offsets suggest how a module might position is components relative to
+         * the viewport.
+         *
+         * @type {object}
+         *
+         * @prop {number} top
+         * @prop {number} right
+         * @prop {number} bottom
+         * @prop {number} left
+         */
+        offsets: {
+          top: 0,
+          right: 0,
+          bottom: 0,
+          left: 0,
+        },
+      },
+
+      /**
+       * {@inheritdoc}
+       *
+       * @param {object} attributes
+       *   Attributes for the toolbar.
+       * @param {object} options
+       *   Options for the toolbar.
+       *
+       * @return {string|undefined}
+       *   Returns an error message if validation failed.
+       */
+      validate(attributes, options) {
+        // Prevent the orientation being set to horizontal if it is locked, unless
+        // override has not been passed as an option.
+        if (
+          attributes.orientation === 'horizontal' &&
+          this.get('locked') &&
+          !options.override
+        ) {
+          return Drupal.t(
+            'The toolbar cannot be set to a horizontal orientation when it is locked.',
+          );
+        }
+      },
+    },
+  );
+})(Backbone, Drupal);
diff --git a/core/modules/toolbar/js/toolbar.es6.js b/core/modules/toolbar/js/toolbar.es6.js
deleted file mode 100644
index 017e91112a48..000000000000
--- a/core/modules/toolbar/js/toolbar.es6.js
+++ /dev/null
@@ -1,317 +0,0 @@
-/**
- * @file
- * Defines the behavior of the Drupal administration toolbar.
- */
-
-(function ($, Drupal, drupalSettings) {
-  // Merge run-time settings with the defaults.
-  const options = $.extend(
-    {
-      breakpoints: {
-        'toolbar.narrow': '',
-        'toolbar.standard': '',
-        'toolbar.wide': '',
-      },
-    },
-    drupalSettings.toolbar,
-    // Merge strings on top of drupalSettings so that they are not mutable.
-    {
-      strings: {
-        horizontal: Drupal.t('Horizontal orientation'),
-        vertical: Drupal.t('Vertical orientation'),
-      },
-    },
-  );
-
-  /**
-   * Registers tabs with the toolbar.
-   *
-   * The Drupal toolbar allows modules to register top-level tabs. These may
-   * point directly to a resource or toggle the visibility of a tray.
-   *
-   * Modules register tabs with hook_toolbar().
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the toolbar rendering functionality to the toolbar element.
-   */
-  Drupal.behaviors.toolbar = {
-    attach(context) {
-      // Verify that the user agent understands media queries. Complex admin
-      // toolbar layouts require media query support.
-      if (!window.matchMedia('only screen').matches) {
-        return;
-      }
-      // Process the administrative toolbar.
-      once('toolbar', '#toolbar-administration', context).forEach((toolbar) => {
-        // Establish the toolbar models and views.
-        const model = new Drupal.toolbar.ToolbarModel({
-          locked: JSON.parse(
-            localStorage.getItem('Drupal.toolbar.trayVerticalLocked'),
-          ),
-          activeTab: document.getElementById(
-            JSON.parse(localStorage.getItem('Drupal.toolbar.activeTabID')),
-          ),
-          height: $('#toolbar-administration').outerHeight(),
-        });
-
-        Drupal.toolbar.models.toolbarModel = model;
-
-        // Attach a listener to the configured media query breakpoints.
-        // Executes it before Drupal.toolbar.views to avoid extra rendering.
-        Object.keys(options.breakpoints).forEach((label) => {
-          const mq = options.breakpoints[label];
-          const mql = window.matchMedia(mq);
-          Drupal.toolbar.mql[label] = mql;
-          // Curry the model and the label of the media query breakpoint to
-          // the mediaQueryChangeHandler function.
-          mql.addListener(
-            Drupal.toolbar.mediaQueryChangeHandler.bind(null, model, label),
-          );
-          // Fire the mediaQueryChangeHandler for each configured breakpoint
-          // so that they process once.
-          Drupal.toolbar.mediaQueryChangeHandler.call(null, model, label, mql);
-        });
-
-        Drupal.toolbar.views.toolbarVisualView =
-          new Drupal.toolbar.ToolbarVisualView({
-            el: toolbar,
-            model,
-            strings: options.strings,
-          });
-        Drupal.toolbar.views.toolbarAuralView =
-          new Drupal.toolbar.ToolbarAuralView({
-            el: toolbar,
-            model,
-            strings: options.strings,
-          });
-        Drupal.toolbar.views.bodyVisualView = new Drupal.toolbar.BodyVisualView(
-          {
-            el: toolbar,
-            model,
-          },
-        );
-
-        // Force layout render to fix mobile view. Only needed on load, not
-        // for every media query match.
-        model.trigger('change:isFixed', model, model.get('isFixed'));
-        model.trigger('change:activeTray', model, model.get('activeTray'));
-
-        // Render collapsible menus.
-        const menuModel = new Drupal.toolbar.MenuModel();
-        Drupal.toolbar.models.menuModel = menuModel;
-        Drupal.toolbar.views.menuVisualView = new Drupal.toolbar.MenuVisualView(
-          {
-            el: $(toolbar).find('.toolbar-menu-administration').get(0),
-            model: menuModel,
-            strings: options.strings,
-          },
-        );
-
-        // Handle the resolution of Drupal.toolbar.setSubtrees.
-        // This is handled with a deferred so that the function may be invoked
-        // asynchronously.
-        Drupal.toolbar.setSubtrees.done((subtrees) => {
-          menuModel.set('subtrees', subtrees);
-          const theme = drupalSettings.ajaxPageState.theme;
-          localStorage.setItem(
-            `Drupal.toolbar.subtrees.${theme}`,
-            JSON.stringify(subtrees),
-          );
-          // Indicate on the toolbarModel that subtrees are now loaded.
-          model.set('areSubtreesLoaded', true);
-        });
-
-        // Trigger an initial attempt to load menu subitems. This first attempt
-        // is made after the media query handlers have had an opportunity to
-        // process. The toolbar starts in the vertical orientation by default,
-        // unless the viewport is wide enough to accommodate a horizontal
-        // orientation. Thus we give the Toolbar a chance to determine if it
-        // should be set to horizontal orientation before attempting to load
-        // menu subtrees.
-        Drupal.toolbar.views.toolbarVisualView.loadSubtrees();
-
-        $(document)
-          // Update the model when the viewport offset changes.
-          .on('drupalViewportOffsetChange.toolbar', (event, offsets) => {
-            model.set('offsets', offsets);
-          });
-
-        // Broadcast model changes to other modules.
-        model
-          .on('change:orientation', (model, orientation) => {
-            $(document).trigger('drupalToolbarOrientationChange', orientation);
-          })
-          .on('change:activeTab', (model, tab) => {
-            $(document).trigger('drupalToolbarTabChange', tab);
-          })
-          .on('change:activeTray', (model, tray) => {
-            $(document).trigger('drupalToolbarTrayChange', tray);
-          });
-
-        // If the toolbar's orientation is horizontal and no active tab is
-        // defined then show the tray of the first toolbar tab by default (but
-        // not the first 'Home' toolbar tab).
-        if (
-          Drupal.toolbar.models.toolbarModel.get('orientation') ===
-            'horizontal' &&
-          Drupal.toolbar.models.toolbarModel.get('activeTab') === null
-        ) {
-          Drupal.toolbar.models.toolbarModel.set({
-            activeTab: $(
-              '.toolbar-bar .toolbar-tab:not(.home-toolbar-tab) a',
-            ).get(0),
-          });
-        }
-
-        $(window).on({
-          'dialog:aftercreate': (event, dialog, $element, settings) => {
-            const $toolbar = $('#toolbar-bar');
-            $toolbar.css('margin-top', '0');
-
-            // When off-canvas is positioned in top, toolbar has to be moved down.
-            if (settings.drupalOffCanvasPosition === 'top') {
-              const height = Drupal.offCanvas
-                .getContainer($element)
-                .outerHeight();
-              $toolbar.css('margin-top', `${height}px`);
-
-              $element.on('dialogContentResize.off-canvas', () => {
-                const newHeight = Drupal.offCanvas
-                  .getContainer($element)
-                  .outerHeight();
-                $toolbar.css('margin-top', `${newHeight}px`);
-              });
-            }
-          },
-          'dialog:beforeclose': () => {
-            $('#toolbar-bar').css('margin-top', '0');
-          },
-        });
-      });
-    },
-  };
-
-  /**
-   * Toolbar methods of Backbone objects.
-   *
-   * @namespace
-   */
-  Drupal.toolbar = {
-    /**
-     * A hash of View instances.
-     *
-     * @type {object.<string, Backbone.View>}
-     */
-    views: {},
-
-    /**
-     * A hash of Model instances.
-     *
-     * @type {object.<string, Backbone.Model>}
-     */
-    models: {},
-
-    /**
-     * A hash of MediaQueryList objects tracked by the toolbar.
-     *
-     * @type {object.<string, object>}
-     */
-    mql: {},
-
-    /**
-     * Accepts a list of subtree menu elements.
-     *
-     * A deferred object that is resolved by an inlined JavaScript callback.
-     *
-     * @type {jQuery.Deferred}
-     *
-     * @see toolbar_subtrees_jsonp().
-     */
-    setSubtrees: new $.Deferred(),
-
-    /**
-     * Respond to configured narrow media query changes.
-     *
-     * @param {Drupal.toolbar.ToolbarModel} model
-     *   A toolbar model
-     * @param {string} label
-     *   Media query label.
-     * @param {object} mql
-     *   A MediaQueryList object.
-     */
-    mediaQueryChangeHandler(model, label, mql) {
-      switch (label) {
-        case 'toolbar.narrow':
-          model.set({
-            isOriented: mql.matches,
-            isTrayToggleVisible: false,
-          });
-          // If the toolbar doesn't have an explicit orientation yet, or if the
-          // narrow media query doesn't match then set the orientation to
-          // vertical.
-          if (!mql.matches || !model.get('orientation')) {
-            model.set({ orientation: 'vertical' }, { validate: true });
-          }
-          break;
-
-        case 'toolbar.standard':
-          model.set({
-            isFixed: mql.matches,
-          });
-          break;
-
-        case 'toolbar.wide':
-          model.set(
-            {
-              orientation:
-                mql.matches && !model.get('locked') ? 'horizontal' : 'vertical',
-            },
-            { validate: true },
-          );
-          // The tray orientation toggle visibility does not need to be
-          // validated.
-          model.set({
-            isTrayToggleVisible: mql.matches,
-          });
-          break;
-
-        default:
-          break;
-      }
-    },
-  };
-
-  /**
-   * A toggle is an interactive element often bound to a click handler.
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   */
-  Drupal.theme.toolbarOrientationToggle = function () {
-    return (
-      '<div class="toolbar-toggle-orientation"><div class="toolbar-lining">' +
-      '<button class="toolbar-icon" type="button"></button>' +
-      '</div></div>'
-    );
-  };
-
-  /**
-   * Ajax command to set the toolbar subtrees.
-   *
-   * @param {Drupal.Ajax} ajax
-   *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
-   * @param {object} response
-   *   JSON response from the Ajax request.
-   * @param {number} [status]
-   *   XMLHttpRequest status.
-   */
-  Drupal.AjaxCommands.prototype.setToolbarSubtrees = function (
-    ajax,
-    response,
-    status,
-  ) {
-    Drupal.toolbar.setSubtrees.resolve(response.subtrees);
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js
index f6cae64f00a1..017e91112a48 100644
--- a/core/modules/toolbar/js/toolbar.js
+++ b/core/modules/toolbar/js/toolbar.js
@@ -1,87 +1,167 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Defines the behavior of the Drupal administration toolbar.
+ */
 
 (function ($, Drupal, drupalSettings) {
-  const options = $.extend({
-    breakpoints: {
-      'toolbar.narrow': '',
-      'toolbar.standard': '',
-      'toolbar.wide': ''
-    }
-  }, drupalSettings.toolbar, {
-    strings: {
-      horizontal: Drupal.t('Horizontal orientation'),
-      vertical: Drupal.t('Vertical orientation')
-    }
-  });
+  // Merge run-time settings with the defaults.
+  const options = $.extend(
+    {
+      breakpoints: {
+        'toolbar.narrow': '',
+        'toolbar.standard': '',
+        'toolbar.wide': '',
+      },
+    },
+    drupalSettings.toolbar,
+    // Merge strings on top of drupalSettings so that they are not mutable.
+    {
+      strings: {
+        horizontal: Drupal.t('Horizontal orientation'),
+        vertical: Drupal.t('Vertical orientation'),
+      },
+    },
+  );
+
+  /**
+   * Registers tabs with the toolbar.
+   *
+   * The Drupal toolbar allows modules to register top-level tabs. These may
+   * point directly to a resource or toggle the visibility of a tray.
+   *
+   * Modules register tabs with hook_toolbar().
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the toolbar rendering functionality to the toolbar element.
+   */
   Drupal.behaviors.toolbar = {
     attach(context) {
+      // Verify that the user agent understands media queries. Complex admin
+      // toolbar layouts require media query support.
       if (!window.matchMedia('only screen').matches) {
         return;
       }
-
-      once('toolbar', '#toolbar-administration', context).forEach(toolbar => {
+      // Process the administrative toolbar.
+      once('toolbar', '#toolbar-administration', context).forEach((toolbar) => {
+        // Establish the toolbar models and views.
         const model = new Drupal.toolbar.ToolbarModel({
-          locked: JSON.parse(localStorage.getItem('Drupal.toolbar.trayVerticalLocked')),
-          activeTab: document.getElementById(JSON.parse(localStorage.getItem('Drupal.toolbar.activeTabID'))),
-          height: $('#toolbar-administration').outerHeight()
+          locked: JSON.parse(
+            localStorage.getItem('Drupal.toolbar.trayVerticalLocked'),
+          ),
+          activeTab: document.getElementById(
+            JSON.parse(localStorage.getItem('Drupal.toolbar.activeTabID')),
+          ),
+          height: $('#toolbar-administration').outerHeight(),
         });
+
         Drupal.toolbar.models.toolbarModel = model;
-        Object.keys(options.breakpoints).forEach(label => {
+
+        // Attach a listener to the configured media query breakpoints.
+        // Executes it before Drupal.toolbar.views to avoid extra rendering.
+        Object.keys(options.breakpoints).forEach((label) => {
           const mq = options.breakpoints[label];
           const mql = window.matchMedia(mq);
           Drupal.toolbar.mql[label] = mql;
-          mql.addListener(Drupal.toolbar.mediaQueryChangeHandler.bind(null, model, label));
+          // Curry the model and the label of the media query breakpoint to
+          // the mediaQueryChangeHandler function.
+          mql.addListener(
+            Drupal.toolbar.mediaQueryChangeHandler.bind(null, model, label),
+          );
+          // Fire the mediaQueryChangeHandler for each configured breakpoint
+          // so that they process once.
           Drupal.toolbar.mediaQueryChangeHandler.call(null, model, label, mql);
         });
-        Drupal.toolbar.views.toolbarVisualView = new Drupal.toolbar.ToolbarVisualView({
-          el: toolbar,
-          model,
-          strings: options.strings
-        });
-        Drupal.toolbar.views.toolbarAuralView = new Drupal.toolbar.ToolbarAuralView({
-          el: toolbar,
-          model,
-          strings: options.strings
-        });
-        Drupal.toolbar.views.bodyVisualView = new Drupal.toolbar.BodyVisualView({
-          el: toolbar,
-          model
-        });
+
+        Drupal.toolbar.views.toolbarVisualView =
+          new Drupal.toolbar.ToolbarVisualView({
+            el: toolbar,
+            model,
+            strings: options.strings,
+          });
+        Drupal.toolbar.views.toolbarAuralView =
+          new Drupal.toolbar.ToolbarAuralView({
+            el: toolbar,
+            model,
+            strings: options.strings,
+          });
+        Drupal.toolbar.views.bodyVisualView = new Drupal.toolbar.BodyVisualView(
+          {
+            el: toolbar,
+            model,
+          },
+        );
+
+        // Force layout render to fix mobile view. Only needed on load, not
+        // for every media query match.
         model.trigger('change:isFixed', model, model.get('isFixed'));
         model.trigger('change:activeTray', model, model.get('activeTray'));
+
+        // Render collapsible menus.
         const menuModel = new Drupal.toolbar.MenuModel();
         Drupal.toolbar.models.menuModel = menuModel;
-        Drupal.toolbar.views.menuVisualView = new Drupal.toolbar.MenuVisualView({
-          el: $(toolbar).find('.toolbar-menu-administration').get(0),
-          model: menuModel,
-          strings: options.strings
-        });
-        Drupal.toolbar.setSubtrees.done(subtrees => {
+        Drupal.toolbar.views.menuVisualView = new Drupal.toolbar.MenuVisualView(
+          {
+            el: $(toolbar).find('.toolbar-menu-administration').get(0),
+            model: menuModel,
+            strings: options.strings,
+          },
+        );
+
+        // Handle the resolution of Drupal.toolbar.setSubtrees.
+        // This is handled with a deferred so that the function may be invoked
+        // asynchronously.
+        Drupal.toolbar.setSubtrees.done((subtrees) => {
           menuModel.set('subtrees', subtrees);
           const theme = drupalSettings.ajaxPageState.theme;
-          localStorage.setItem(`Drupal.toolbar.subtrees.${theme}`, JSON.stringify(subtrees));
+          localStorage.setItem(
+            `Drupal.toolbar.subtrees.${theme}`,
+            JSON.stringify(subtrees),
+          );
+          // Indicate on the toolbarModel that subtrees are now loaded.
           model.set('areSubtreesLoaded', true);
         });
+
+        // Trigger an initial attempt to load menu subitems. This first attempt
+        // is made after the media query handlers have had an opportunity to
+        // process. The toolbar starts in the vertical orientation by default,
+        // unless the viewport is wide enough to accommodate a horizontal
+        // orientation. Thus we give the Toolbar a chance to determine if it
+        // should be set to horizontal orientation before attempting to load
+        // menu subtrees.
         Drupal.toolbar.views.toolbarVisualView.loadSubtrees();
-        $(document).on('drupalViewportOffsetChange.toolbar', (event, offsets) => {
-          model.set('offsets', offsets);
-        });
-        model.on('change:orientation', (model, orientation) => {
-          $(document).trigger('drupalToolbarOrientationChange', orientation);
-        }).on('change:activeTab', (model, tab) => {
-          $(document).trigger('drupalToolbarTabChange', tab);
-        }).on('change:activeTray', (model, tray) => {
-          $(document).trigger('drupalToolbarTrayChange', tray);
-        });
 
-        if (Drupal.toolbar.models.toolbarModel.get('orientation') === 'horizontal' && Drupal.toolbar.models.toolbarModel.get('activeTab') === null) {
+        $(document)
+          // Update the model when the viewport offset changes.
+          .on('drupalViewportOffsetChange.toolbar', (event, offsets) => {
+            model.set('offsets', offsets);
+          });
+
+        // Broadcast model changes to other modules.
+        model
+          .on('change:orientation', (model, orientation) => {
+            $(document).trigger('drupalToolbarOrientationChange', orientation);
+          })
+          .on('change:activeTab', (model, tab) => {
+            $(document).trigger('drupalToolbarTabChange', tab);
+          })
+          .on('change:activeTray', (model, tray) => {
+            $(document).trigger('drupalToolbarTrayChange', tray);
+          });
+
+        // If the toolbar's orientation is horizontal and no active tab is
+        // defined then show the tray of the first toolbar tab by default (but
+        // not the first 'Home' toolbar tab).
+        if (
+          Drupal.toolbar.models.toolbarModel.get('orientation') ===
+            'horizontal' &&
+          Drupal.toolbar.models.toolbarModel.get('activeTab') === null
+        ) {
           Drupal.toolbar.models.toolbarModel.set({
-            activeTab: $('.toolbar-bar .toolbar-tab:not(.home-toolbar-tab) a').get(0)
+            activeTab: $(
+              '.toolbar-bar .toolbar-tab:not(.home-toolbar-tab) a',
+            ).get(0),
           });
         }
 
@@ -90,76 +170,148 @@
             const $toolbar = $('#toolbar-bar');
             $toolbar.css('margin-top', '0');
 
+            // When off-canvas is positioned in top, toolbar has to be moved down.
             if (settings.drupalOffCanvasPosition === 'top') {
-              const height = Drupal.offCanvas.getContainer($element).outerHeight();
+              const height = Drupal.offCanvas
+                .getContainer($element)
+                .outerHeight();
               $toolbar.css('margin-top', `${height}px`);
+
               $element.on('dialogContentResize.off-canvas', () => {
-                const newHeight = Drupal.offCanvas.getContainer($element).outerHeight();
+                const newHeight = Drupal.offCanvas
+                  .getContainer($element)
+                  .outerHeight();
                 $toolbar.css('margin-top', `${newHeight}px`);
               });
             }
           },
           'dialog:beforeclose': () => {
             $('#toolbar-bar').css('margin-top', '0');
-          }
+          },
         });
       });
-    }
-
+    },
   };
+
+  /**
+   * Toolbar methods of Backbone objects.
+   *
+   * @namespace
+   */
   Drupal.toolbar = {
+    /**
+     * A hash of View instances.
+     *
+     * @type {object.<string, Backbone.View>}
+     */
     views: {},
+
+    /**
+     * A hash of Model instances.
+     *
+     * @type {object.<string, Backbone.Model>}
+     */
     models: {},
+
+    /**
+     * A hash of MediaQueryList objects tracked by the toolbar.
+     *
+     * @type {object.<string, object>}
+     */
     mql: {},
+
+    /**
+     * Accepts a list of subtree menu elements.
+     *
+     * A deferred object that is resolved by an inlined JavaScript callback.
+     *
+     * @type {jQuery.Deferred}
+     *
+     * @see toolbar_subtrees_jsonp().
+     */
     setSubtrees: new $.Deferred(),
 
+    /**
+     * Respond to configured narrow media query changes.
+     *
+     * @param {Drupal.toolbar.ToolbarModel} model
+     *   A toolbar model
+     * @param {string} label
+     *   Media query label.
+     * @param {object} mql
+     *   A MediaQueryList object.
+     */
     mediaQueryChangeHandler(model, label, mql) {
       switch (label) {
         case 'toolbar.narrow':
           model.set({
             isOriented: mql.matches,
-            isTrayToggleVisible: false
+            isTrayToggleVisible: false,
           });
-
+          // If the toolbar doesn't have an explicit orientation yet, or if the
+          // narrow media query doesn't match then set the orientation to
+          // vertical.
           if (!mql.matches || !model.get('orientation')) {
-            model.set({
-              orientation: 'vertical'
-            }, {
-              validate: true
-            });
+            model.set({ orientation: 'vertical' }, { validate: true });
           }
-
           break;
 
         case 'toolbar.standard':
           model.set({
-            isFixed: mql.matches
+            isFixed: mql.matches,
           });
           break;
 
         case 'toolbar.wide':
+          model.set(
+            {
+              orientation:
+                mql.matches && !model.get('locked') ? 'horizontal' : 'vertical',
+            },
+            { validate: true },
+          );
+          // The tray orientation toggle visibility does not need to be
+          // validated.
           model.set({
-            orientation: mql.matches && !model.get('locked') ? 'horizontal' : 'vertical'
-          }, {
-            validate: true
-          });
-          model.set({
-            isTrayToggleVisible: mql.matches
+            isTrayToggleVisible: mql.matches,
           });
           break;
 
         default:
           break;
       }
-    }
-
+    },
   };
 
+  /**
+   * A toggle is an interactive element often bound to a click handler.
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   */
   Drupal.theme.toolbarOrientationToggle = function () {
-    return '<div class="toolbar-toggle-orientation"><div class="toolbar-lining">' + '<button class="toolbar-icon" type="button"></button>' + '</div></div>';
+    return (
+      '<div class="toolbar-toggle-orientation"><div class="toolbar-lining">' +
+      '<button class="toolbar-icon" type="button"></button>' +
+      '</div></div>'
+    );
   };
 
-  Drupal.AjaxCommands.prototype.setToolbarSubtrees = function (ajax, response, status) {
+  /**
+   * Ajax command to set the toolbar subtrees.
+   *
+   * @param {Drupal.Ajax} ajax
+   *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
+   * @param {object} response
+   *   JSON response from the Ajax request.
+   * @param {number} [status]
+   *   XMLHttpRequest status.
+   */
+  Drupal.AjaxCommands.prototype.setToolbarSubtrees = function (
+    ajax,
+    response,
+    status,
+  ) {
     Drupal.toolbar.setSubtrees.resolve(response.subtrees);
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/toolbar/js/toolbar.menu.es6.js b/core/modules/toolbar/js/toolbar.menu.es6.js
deleted file mode 100644
index 56d6776a55a5..000000000000
--- a/core/modules/toolbar/js/toolbar.menu.es6.js
+++ /dev/null
@@ -1,204 +0,0 @@
-/**
- * @file
- * Builds a nested accordion widget.
- *
- * Invoke on an HTML list element with the jQuery plugin pattern.
- *
- * @example
- * $('.toolbar-menu').drupalToolbarMenu();
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Store the open menu tray.
-   */
-  let activeItem = Drupal.url(drupalSettings.path.currentPath);
-
-  $.fn.drupalToolbarMenu = function () {
-    const ui = {
-      handleOpen: Drupal.t('Extend'),
-      handleClose: Drupal.t('Collapse'),
-    };
-
-    /**
-     * Toggle the open/close state of a list is a menu.
-     *
-     * @param {jQuery} $item
-     *   The li item to be toggled.
-     *
-     * @param {Boolean} switcher
-     *   A flag that forces toggleClass to add or a remove a class, rather than
-     *   simply toggling its presence.
-     */
-    function toggleList($item, switcher) {
-      const $toggle = $item
-        .children('.toolbar-box')
-        .children('.toolbar-handle');
-      switcher =
-        typeof switcher !== 'undefined' ? switcher : !$item.hasClass('open');
-      // Toggle the item open state.
-      $item.toggleClass('open', switcher);
-      // Twist the toggle.
-      $toggle.toggleClass('open', switcher);
-      // Adjust the toggle text.
-      $toggle.find('.action').each((index, element) => {
-        // Expand Structure, Collapse Structure.
-        element.textContent = switcher ? ui.handleClose : ui.handleOpen;
-      });
-    }
-
-    /**
-     * Handle clicks from the disclosure button on an item with sub-items.
-     *
-     * @param {Object} event
-     *   A jQuery Event object.
-     */
-    function toggleClickHandler(event) {
-      const $toggle = $(event.target);
-      const $item = $toggle.closest('li');
-      // Toggle the list item.
-      toggleList($item);
-      // Close open sibling menus.
-      const $openItems = $item.siblings().filter('.open');
-      toggleList($openItems, false);
-    }
-
-    /**
-     * Handle clicks from a menu item link.
-     *
-     * @param {Object} event
-     *   A jQuery Event object.
-     */
-    function linkClickHandler(event) {
-      // If the toolbar is positioned fixed (and therefore hiding content
-      // underneath), then users expect clicks in the administration menu tray
-      // to take them to that destination but for the menu tray to be closed
-      // after clicking: otherwise the toolbar itself is obstructing the view
-      // of the destination they chose.
-      if (!Drupal.toolbar.models.toolbarModel.get('isFixed')) {
-        Drupal.toolbar.models.toolbarModel.set('activeTab', null);
-      }
-      // Stopping propagation to make sure that once a toolbar-box is clicked
-      // (the whitespace part), the page is not redirected anymore.
-      event.stopPropagation();
-    }
-
-    /**
-     * Add markup to the menu elements.
-     *
-     * Items with sub-elements have a list toggle attached to them. Menu item
-     * links and the corresponding list toggle are wrapped with in a div
-     * classed with .toolbar-box. The .toolbar-box div provides a positioning
-     * context for the item list toggle.
-     *
-     * @param {jQuery} $menu
-     *   The root of the menu to be initialized.
-     */
-    function initItems($menu) {
-      const options = {
-        class: 'toolbar-icon toolbar-handle',
-        action: ui.handleOpen,
-        text: '',
-      };
-      // Initialize items and their links.
-      $menu.find('li > a').wrap('<div class="toolbar-box">');
-      // Add a handle to each list item if it has a menu.
-      $menu.find('li').each((index, element) => {
-        const $item = $(element);
-        if ($item.children('ul.toolbar-menu').length) {
-          const $box = $item.children('.toolbar-box');
-          const $link = $box.find('a');
-          options.text = Drupal.t('@label', {
-            '@label': $link.length ? $link[0].textContent : '',
-          });
-          $item
-            .children('.toolbar-box')
-            .append(Drupal.theme('toolbarMenuItemToggle', options));
-        }
-      });
-    }
-
-    /**
-     * Adds a level class to each list based on its depth in the menu.
-     *
-     * This function is called recursively on each sub level of lists elements
-     * until the depth of the menu is exhausted.
-     *
-     * @param {jQuery} $lists
-     *   A jQuery object of ul elements.
-     *
-     * @param {number} level
-     *   The current level number to be assigned to the list elements.
-     */
-    function markListLevels($lists, level) {
-      level = !level ? 1 : level;
-      const $lis = $lists.children('li').addClass(`level-${level}`);
-      $lists = $lis.children('ul');
-      if ($lists.length) {
-        markListLevels($lists, level + 1);
-      }
-    }
-
-    /**
-     * On page load, open the active menu item.
-     *
-     * Marks the trail of the active link in the menu back to the root of the
-     * menu with .menu-item--active-trail.
-     *
-     * @param {jQuery} $menu
-     *   The root of the menu.
-     */
-    function openActiveItem($menu) {
-      const pathItem = $menu.find(`a[href="${window.location.pathname}"]`);
-      if (pathItem.length && !activeItem) {
-        activeItem = window.location.pathname;
-      }
-      if (activeItem) {
-        const $activeItem = $menu
-          .find(`a[href="${activeItem}"]`)
-          .addClass('menu-item--active');
-        const $activeTrail = $activeItem
-          .parentsUntil('.root', 'li')
-          .addClass('menu-item--active-trail');
-        toggleList($activeTrail, true);
-      }
-    }
-
-    // Return the jQuery object.
-    return this.each(function (selector) {
-      const menu = once('toolbar-menu', this);
-      if (menu.length) {
-        const $menu = $(menu);
-        // Bind event handlers.
-        $menu
-          .on('click.toolbar', '.toolbar-box', toggleClickHandler)
-          .on('click.toolbar', '.toolbar-box a', linkClickHandler);
-
-        $menu.addClass('root');
-        initItems($menu);
-        markListLevels($menu);
-        // Restore previous and active states.
-        openActiveItem($menu);
-      }
-    });
-  };
-
-  /**
-   * A toggle is an interactive element often bound to a click handler.
-   *
-   * @param {object} options
-   *   Options for the button.
-   * @param {string} options.class
-   *   Class to set on the button.
-   * @param {string} options.action
-   *   Action for the button.
-   * @param {string} options.text
-   *   Used as label for the button.
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   */
-  Drupal.theme.toolbarMenuItemToggle = function (options) {
-    return `<button class="${options.class}"><span class="action">${options.action}</span> <span class="label">${options.text}</span></button>`;
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/toolbar/js/toolbar.menu.js b/core/modules/toolbar/js/toolbar.menu.js
index 1b8d4b5045ef..56d6776a55a5 100644
--- a/core/modules/toolbar/js/toolbar.menu.js
+++ b/core/modules/toolbar/js/toolbar.menu.js
@@ -1,105 +1,204 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Builds a nested accordion widget.
+ *
+ * Invoke on an HTML list element with the jQuery plugin pattern.
+ *
+ * @example
+ * $('.toolbar-menu').drupalToolbarMenu();
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * Store the open menu tray.
+   */
   let activeItem = Drupal.url(drupalSettings.path.currentPath);
 
   $.fn.drupalToolbarMenu = function () {
     const ui = {
       handleOpen: Drupal.t('Extend'),
-      handleClose: Drupal.t('Collapse')
+      handleClose: Drupal.t('Collapse'),
     };
 
+    /**
+     * Toggle the open/close state of a list is a menu.
+     *
+     * @param {jQuery} $item
+     *   The li item to be toggled.
+     *
+     * @param {Boolean} switcher
+     *   A flag that forces toggleClass to add or a remove a class, rather than
+     *   simply toggling its presence.
+     */
     function toggleList($item, switcher) {
-      const $toggle = $item.children('.toolbar-box').children('.toolbar-handle');
-      switcher = typeof switcher !== 'undefined' ? switcher : !$item.hasClass('open');
+      const $toggle = $item
+        .children('.toolbar-box')
+        .children('.toolbar-handle');
+      switcher =
+        typeof switcher !== 'undefined' ? switcher : !$item.hasClass('open');
+      // Toggle the item open state.
       $item.toggleClass('open', switcher);
+      // Twist the toggle.
       $toggle.toggleClass('open', switcher);
+      // Adjust the toggle text.
       $toggle.find('.action').each((index, element) => {
+        // Expand Structure, Collapse Structure.
         element.textContent = switcher ? ui.handleClose : ui.handleOpen;
       });
     }
 
+    /**
+     * Handle clicks from the disclosure button on an item with sub-items.
+     *
+     * @param {Object} event
+     *   A jQuery Event object.
+     */
     function toggleClickHandler(event) {
       const $toggle = $(event.target);
       const $item = $toggle.closest('li');
+      // Toggle the list item.
       toggleList($item);
+      // Close open sibling menus.
       const $openItems = $item.siblings().filter('.open');
       toggleList($openItems, false);
     }
 
+    /**
+     * Handle clicks from a menu item link.
+     *
+     * @param {Object} event
+     *   A jQuery Event object.
+     */
     function linkClickHandler(event) {
+      // If the toolbar is positioned fixed (and therefore hiding content
+      // underneath), then users expect clicks in the administration menu tray
+      // to take them to that destination but for the menu tray to be closed
+      // after clicking: otherwise the toolbar itself is obstructing the view
+      // of the destination they chose.
       if (!Drupal.toolbar.models.toolbarModel.get('isFixed')) {
         Drupal.toolbar.models.toolbarModel.set('activeTab', null);
       }
-
+      // Stopping propagation to make sure that once a toolbar-box is clicked
+      // (the whitespace part), the page is not redirected anymore.
       event.stopPropagation();
     }
 
+    /**
+     * Add markup to the menu elements.
+     *
+     * Items with sub-elements have a list toggle attached to them. Menu item
+     * links and the corresponding list toggle are wrapped with in a div
+     * classed with .toolbar-box. The .toolbar-box div provides a positioning
+     * context for the item list toggle.
+     *
+     * @param {jQuery} $menu
+     *   The root of the menu to be initialized.
+     */
     function initItems($menu) {
       const options = {
         class: 'toolbar-icon toolbar-handle',
         action: ui.handleOpen,
-        text: ''
+        text: '',
       };
+      // Initialize items and their links.
       $menu.find('li > a').wrap('<div class="toolbar-box">');
+      // Add a handle to each list item if it has a menu.
       $menu.find('li').each((index, element) => {
         const $item = $(element);
-
         if ($item.children('ul.toolbar-menu').length) {
           const $box = $item.children('.toolbar-box');
           const $link = $box.find('a');
           options.text = Drupal.t('@label', {
-            '@label': $link.length ? $link[0].textContent : ''
+            '@label': $link.length ? $link[0].textContent : '',
           });
-          $item.children('.toolbar-box').append(Drupal.theme('toolbarMenuItemToggle', options));
+          $item
+            .children('.toolbar-box')
+            .append(Drupal.theme('toolbarMenuItemToggle', options));
         }
       });
     }
 
+    /**
+     * Adds a level class to each list based on its depth in the menu.
+     *
+     * This function is called recursively on each sub level of lists elements
+     * until the depth of the menu is exhausted.
+     *
+     * @param {jQuery} $lists
+     *   A jQuery object of ul elements.
+     *
+     * @param {number} level
+     *   The current level number to be assigned to the list elements.
+     */
     function markListLevels($lists, level) {
       level = !level ? 1 : level;
       const $lis = $lists.children('li').addClass(`level-${level}`);
       $lists = $lis.children('ul');
-
       if ($lists.length) {
         markListLevels($lists, level + 1);
       }
     }
 
+    /**
+     * On page load, open the active menu item.
+     *
+     * Marks the trail of the active link in the menu back to the root of the
+     * menu with .menu-item--active-trail.
+     *
+     * @param {jQuery} $menu
+     *   The root of the menu.
+     */
     function openActiveItem($menu) {
       const pathItem = $menu.find(`a[href="${window.location.pathname}"]`);
-
       if (pathItem.length && !activeItem) {
         activeItem = window.location.pathname;
       }
-
       if (activeItem) {
-        const $activeItem = $menu.find(`a[href="${activeItem}"]`).addClass('menu-item--active');
-        const $activeTrail = $activeItem.parentsUntil('.root', 'li').addClass('menu-item--active-trail');
+        const $activeItem = $menu
+          .find(`a[href="${activeItem}"]`)
+          .addClass('menu-item--active');
+        const $activeTrail = $activeItem
+          .parentsUntil('.root', 'li')
+          .addClass('menu-item--active-trail');
         toggleList($activeTrail, true);
       }
     }
 
+    // Return the jQuery object.
     return this.each(function (selector) {
       const menu = once('toolbar-menu', this);
-
       if (menu.length) {
         const $menu = $(menu);
-        $menu.on('click.toolbar', '.toolbar-box', toggleClickHandler).on('click.toolbar', '.toolbar-box a', linkClickHandler);
+        // Bind event handlers.
+        $menu
+          .on('click.toolbar', '.toolbar-box', toggleClickHandler)
+          .on('click.toolbar', '.toolbar-box a', linkClickHandler);
+
         $menu.addClass('root');
         initItems($menu);
         markListLevels($menu);
+        // Restore previous and active states.
         openActiveItem($menu);
       }
     });
   };
 
+  /**
+   * A toggle is an interactive element often bound to a click handler.
+   *
+   * @param {object} options
+   *   Options for the button.
+   * @param {string} options.class
+   *   Class to set on the button.
+   * @param {string} options.action
+   *   Action for the button.
+   * @param {string} options.text
+   *   Used as label for the button.
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   */
   Drupal.theme.toolbarMenuItemToggle = function (options) {
     return `<button class="${options.class}"><span class="action">${options.action}</span> <span class="label">${options.text}</span></button>`;
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/toolbar/js/views/BodyVisualView.es6.js b/core/modules/toolbar/js/views/BodyVisualView.es6.js
deleted file mode 100644
index f52d0f865341..000000000000
--- a/core/modules/toolbar/js/views/BodyVisualView.es6.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * @file
- * A Backbone view for the body element.
- */
-
-(function ($, Drupal, Backbone) {
-  Drupal.toolbar.BodyVisualView = Backbone.View.extend(
-    /** @lends Drupal.toolbar.BodyVisualView# */ {
-      /**
-       * Adjusts the body element with the toolbar position and dimension changes.
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       */
-      initialize() {
-        this.listenTo(this.model, 'change:activeTray ', this.render);
-        this.listenTo(
-          this.model,
-          'change:isFixed change:isViewportOverflowConstrained',
-          this.isToolbarFixed,
-        );
-      },
-
-      isToolbarFixed() {
-        // When the toolbar is fixed, it will not scroll with page scrolling.
-        const isViewportOverflowConstrained = this.model.get(
-          'isViewportOverflowConstrained',
-        );
-        $('body').toggleClass(
-          'toolbar-fixed',
-          isViewportOverflowConstrained || this.model.get('isFixed'),
-        );
-      },
-
-      /**
-       * {@inheritdoc}
-       */
-      render() {
-        $('body')
-          // Toggle the toolbar-tray-open class on the body element. The class is
-          // applied when a toolbar tray is active. Padding might be applied to
-          // the body element to prevent the tray from overlapping content.
-          .toggleClass('toolbar-tray-open', !!this.model.get('activeTray'));
-      },
-    },
-  );
-})(jQuery, Drupal, Backbone);
diff --git a/core/modules/toolbar/js/views/BodyVisualView.js b/core/modules/toolbar/js/views/BodyVisualView.js
index 93b029d208f9..f52d0f865341 100644
--- a/core/modules/toolbar/js/views/BodyVisualView.js
+++ b/core/modules/toolbar/js/views/BodyVisualView.js
@@ -1,25 +1,48 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone view for the body element.
+ */
 
 (function ($, Drupal, Backbone) {
-  Drupal.toolbar.BodyVisualView = Backbone.View.extend({
-    initialize() {
-      this.listenTo(this.model, 'change:activeTray ', this.render);
-      this.listenTo(this.model, 'change:isFixed change:isViewportOverflowConstrained', this.isToolbarFixed);
-    },
-
-    isToolbarFixed() {
-      const isViewportOverflowConstrained = this.model.get('isViewportOverflowConstrained');
-      $('body').toggleClass('toolbar-fixed', isViewportOverflowConstrained || this.model.get('isFixed'));
-    },
+  Drupal.toolbar.BodyVisualView = Backbone.View.extend(
+    /** @lends Drupal.toolbar.BodyVisualView# */ {
+      /**
+       * Adjusts the body element with the toolbar position and dimension changes.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       */
+      initialize() {
+        this.listenTo(this.model, 'change:activeTray ', this.render);
+        this.listenTo(
+          this.model,
+          'change:isFixed change:isViewportOverflowConstrained',
+          this.isToolbarFixed,
+        );
+      },
 
-    render() {
-      $('body').toggleClass('toolbar-tray-open', !!this.model.get('activeTray'));
-    }
+      isToolbarFixed() {
+        // When the toolbar is fixed, it will not scroll with page scrolling.
+        const isViewportOverflowConstrained = this.model.get(
+          'isViewportOverflowConstrained',
+        );
+        $('body').toggleClass(
+          'toolbar-fixed',
+          isViewportOverflowConstrained || this.model.get('isFixed'),
+        );
+      },
 
-  });
-})(jQuery, Drupal, Backbone);
\ No newline at end of file
+      /**
+       * {@inheritdoc}
+       */
+      render() {
+        $('body')
+          // Toggle the toolbar-tray-open class on the body element. The class is
+          // applied when a toolbar tray is active. Padding might be applied to
+          // the body element to prevent the tray from overlapping content.
+          .toggleClass('toolbar-tray-open', !!this.model.get('activeTray'));
+      },
+    },
+  );
+})(jQuery, Drupal, Backbone);
diff --git a/core/modules/toolbar/js/views/MenuVisualView.es6.js b/core/modules/toolbar/js/views/MenuVisualView.es6.js
deleted file mode 100644
index 916afb21a09c..000000000000
--- a/core/modules/toolbar/js/views/MenuVisualView.es6.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * @file
- * A Backbone view for the collapsible menus.
- */
-
-(function ($, Backbone, Drupal) {
-  Drupal.toolbar.MenuVisualView = Backbone.View.extend(
-    /** @lends Drupal.toolbar.MenuVisualView# */ {
-      /**
-       * Backbone View for collapsible menus.
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       */
-      initialize() {
-        this.listenTo(this.model, 'change:subtrees', this.render);
-      },
-
-      /**
-       * {@inheritdoc}
-       */
-      render() {
-        const subtrees = this.model.get('subtrees');
-        // Add subtrees.
-        Object.keys(subtrees || {}).forEach((id) => {
-          $(
-            once('toolbar-subtrees', this.$el.find(`#toolbar-link-${id}`)),
-          ).after(subtrees[id]);
-        });
-        // Render the main menu as a nested, collapsible accordion.
-        if ('drupalToolbarMenu' in $.fn) {
-          this.$el.children('.toolbar-menu').drupalToolbarMenu();
-        }
-      },
-    },
-  );
-})(jQuery, Backbone, Drupal);
diff --git a/core/modules/toolbar/js/views/MenuVisualView.js b/core/modules/toolbar/js/views/MenuVisualView.js
index 1eb9aa21b539..916afb21a09c 100644
--- a/core/modules/toolbar/js/views/MenuVisualView.js
+++ b/core/modules/toolbar/js/views/MenuVisualView.js
@@ -1,26 +1,38 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone view for the collapsible menus.
+ */
 
 (function ($, Backbone, Drupal) {
-  Drupal.toolbar.MenuVisualView = Backbone.View.extend({
-    initialize() {
-      this.listenTo(this.model, 'change:subtrees', this.render);
-    },
-
-    render() {
-      const subtrees = this.model.get('subtrees');
-      Object.keys(subtrees || {}).forEach(id => {
-        $(once('toolbar-subtrees', this.$el.find(`#toolbar-link-${id}`))).after(subtrees[id]);
-      });
+  Drupal.toolbar.MenuVisualView = Backbone.View.extend(
+    /** @lends Drupal.toolbar.MenuVisualView# */ {
+      /**
+       * Backbone View for collapsible menus.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       */
+      initialize() {
+        this.listenTo(this.model, 'change:subtrees', this.render);
+      },
 
-      if ('drupalToolbarMenu' in $.fn) {
-        this.$el.children('.toolbar-menu').drupalToolbarMenu();
-      }
-    }
-
-  });
-})(jQuery, Backbone, Drupal);
\ No newline at end of file
+      /**
+       * {@inheritdoc}
+       */
+      render() {
+        const subtrees = this.model.get('subtrees');
+        // Add subtrees.
+        Object.keys(subtrees || {}).forEach((id) => {
+          $(
+            once('toolbar-subtrees', this.$el.find(`#toolbar-link-${id}`)),
+          ).after(subtrees[id]);
+        });
+        // Render the main menu as a nested, collapsible accordion.
+        if ('drupalToolbarMenu' in $.fn) {
+          this.$el.children('.toolbar-menu').drupalToolbarMenu();
+        }
+      },
+    },
+  );
+})(jQuery, Backbone, Drupal);
diff --git a/core/modules/toolbar/js/views/ToolbarAuralView.es6.js b/core/modules/toolbar/js/views/ToolbarAuralView.es6.js
deleted file mode 100644
index c00e05893985..000000000000
--- a/core/modules/toolbar/js/views/ToolbarAuralView.es6.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * @file
- * A Backbone view for the aural feedback of the toolbar.
- */
-
-(function (Backbone, Drupal) {
-  Drupal.toolbar.ToolbarAuralView = Backbone.View.extend(
-    /** @lends Drupal.toolbar.ToolbarAuralView# */ {
-      /**
-       * Backbone view for the aural feedback of the toolbar.
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       *
-       * @param {object} options
-       *   Options for the view.
-       * @param {object} options.strings
-       *   Various strings to use in the view.
-       */
-      initialize(options) {
-        this.strings = options.strings;
-
-        this.listenTo(
-          this.model,
-          'change:orientation',
-          this.onOrientationChange,
-        );
-        this.listenTo(this.model, 'change:activeTray', this.onActiveTrayChange);
-      },
-
-      /**
-       * Announces an orientation change.
-       *
-       * @param {Drupal.toolbar.ToolbarModel} model
-       *   The toolbar model in question.
-       * @param {string} orientation
-       *   The new value of the orientation attribute in the model.
-       */
-      onOrientationChange(model, orientation) {
-        Drupal.announce(
-          Drupal.t('Tray orientation changed to @orientation.', {
-            '@orientation': orientation,
-          }),
-        );
-      },
-
-      /**
-       * Announces a changed active tray.
-       *
-       * @param {Drupal.toolbar.ToolbarModel} model
-       *   The toolbar model in question.
-       * @param {HTMLElement} tray
-       *   The new value of the tray attribute in the model.
-       */
-      onActiveTrayChange(model, tray) {
-        const relevantTray =
-          tray === null ? model.previous('activeTray') : tray;
-        // Current activeTray and previous activeTray are empty, no state change
-        // to announce.
-        if (!relevantTray) {
-          return;
-        }
-        const action = tray === null ? Drupal.t('closed') : Drupal.t('opened');
-        const trayNameElement =
-          relevantTray.querySelector('.toolbar-tray-name');
-        let text;
-        if (trayNameElement !== null) {
-          text = Drupal.t('Tray "@tray" @action.', {
-            '@tray': trayNameElement.textContent,
-            '@action': action,
-          });
-        } else {
-          text = Drupal.t('Tray @action.', { '@action': action });
-        }
-        Drupal.announce(text);
-      },
-    },
-  );
-})(Backbone, Drupal);
diff --git a/core/modules/toolbar/js/views/ToolbarAuralView.js b/core/modules/toolbar/js/views/ToolbarAuralView.js
index 5577eec4d5ba..c00e05893985 100644
--- a/core/modules/toolbar/js/views/ToolbarAuralView.js
+++ b/core/modules/toolbar/js/views/ToolbarAuralView.js
@@ -1,48 +1,80 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone view for the aural feedback of the toolbar.
+ */
 
 (function (Backbone, Drupal) {
-  Drupal.toolbar.ToolbarAuralView = Backbone.View.extend({
-    initialize(options) {
-      this.strings = options.strings;
-      this.listenTo(this.model, 'change:orientation', this.onOrientationChange);
-      this.listenTo(this.model, 'change:activeTray', this.onActiveTrayChange);
-    },
-
-    onOrientationChange(model, orientation) {
-      Drupal.announce(Drupal.t('Tray orientation changed to @orientation.', {
-        '@orientation': orientation
-      }));
-    },
-
-    onActiveTrayChange(model, tray) {
-      const relevantTray = tray === null ? model.previous('activeTray') : tray;
+  Drupal.toolbar.ToolbarAuralView = Backbone.View.extend(
+    /** @lends Drupal.toolbar.ToolbarAuralView# */ {
+      /**
+       * Backbone view for the aural feedback of the toolbar.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       *
+       * @param {object} options
+       *   Options for the view.
+       * @param {object} options.strings
+       *   Various strings to use in the view.
+       */
+      initialize(options) {
+        this.strings = options.strings;
 
-      if (!relevantTray) {
-        return;
-      }
+        this.listenTo(
+          this.model,
+          'change:orientation',
+          this.onOrientationChange,
+        );
+        this.listenTo(this.model, 'change:activeTray', this.onActiveTrayChange);
+      },
 
-      const action = tray === null ? Drupal.t('closed') : Drupal.t('opened');
-      const trayNameElement = relevantTray.querySelector('.toolbar-tray-name');
-      let text;
+      /**
+       * Announces an orientation change.
+       *
+       * @param {Drupal.toolbar.ToolbarModel} model
+       *   The toolbar model in question.
+       * @param {string} orientation
+       *   The new value of the orientation attribute in the model.
+       */
+      onOrientationChange(model, orientation) {
+        Drupal.announce(
+          Drupal.t('Tray orientation changed to @orientation.', {
+            '@orientation': orientation,
+          }),
+        );
+      },
 
-      if (trayNameElement !== null) {
-        text = Drupal.t('Tray "@tray" @action.', {
-          '@tray': trayNameElement.textContent,
-          '@action': action
-        });
-      } else {
-        text = Drupal.t('Tray @action.', {
-          '@action': action
-        });
-      }
-
-      Drupal.announce(text);
-    }
-
-  });
-})(Backbone, Drupal);
\ No newline at end of file
+      /**
+       * Announces a changed active tray.
+       *
+       * @param {Drupal.toolbar.ToolbarModel} model
+       *   The toolbar model in question.
+       * @param {HTMLElement} tray
+       *   The new value of the tray attribute in the model.
+       */
+      onActiveTrayChange(model, tray) {
+        const relevantTray =
+          tray === null ? model.previous('activeTray') : tray;
+        // Current activeTray and previous activeTray are empty, no state change
+        // to announce.
+        if (!relevantTray) {
+          return;
+        }
+        const action = tray === null ? Drupal.t('closed') : Drupal.t('opened');
+        const trayNameElement =
+          relevantTray.querySelector('.toolbar-tray-name');
+        let text;
+        if (trayNameElement !== null) {
+          text = Drupal.t('Tray "@tray" @action.', {
+            '@tray': trayNameElement.textContent,
+            '@action': action,
+          });
+        } else {
+          text = Drupal.t('Tray @action.', { '@action': action });
+        }
+        Drupal.announce(text);
+      },
+    },
+  );
+})(Backbone, Drupal);
diff --git a/core/modules/toolbar/js/views/ToolbarVisualView.es6.js b/core/modules/toolbar/js/views/ToolbarVisualView.es6.js
deleted file mode 100644
index 87c8fc5b3ffa..000000000000
--- a/core/modules/toolbar/js/views/ToolbarVisualView.es6.js
+++ /dev/null
@@ -1,387 +0,0 @@
-/**
- * @file
- * A Backbone view for the toolbar element. Listens to mouse & touch.
- */
-
-(function ($, Drupal, drupalSettings, Backbone) {
-  Drupal.toolbar.ToolbarVisualView = Backbone.View.extend(
-    /** @lends Drupal.toolbar.ToolbarVisualView# */ {
-      /**
-       * Event map for the `ToolbarVisualView`.
-       *
-       * @return {object}
-       *   A map of events.
-       */
-      events() {
-        // Prevents delay and simulated mouse events.
-        const touchEndToClick = function (event) {
-          event.preventDefault();
-          event.target.click();
-        };
-
-        return {
-          'click .toolbar-bar .toolbar-tab .trigger': 'onTabClick',
-          'click .toolbar-toggle-orientation button':
-            'onOrientationToggleClick',
-          'touchend .toolbar-bar .toolbar-tab .trigger': touchEndToClick,
-          'touchend .toolbar-toggle-orientation button': touchEndToClick,
-        };
-      },
-
-      /**
-       * Backbone view for the toolbar element. Listens to mouse & touch.
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       *
-       * @param {object} options
-       *   Options for the view object.
-       * @param {object} options.strings
-       *   Various strings to use in the view.
-       */
-      initialize(options) {
-        this.strings = options.strings;
-
-        this.listenTo(
-          this.model,
-          'change:activeTab change:orientation change:isOriented change:isTrayToggleVisible',
-          this.render,
-        );
-        this.listenTo(this.model, 'change:mqMatches', this.onMediaQueryChange);
-        this.listenTo(this.model, 'change:offsets', this.adjustPlacement);
-        this.listenTo(
-          this.model,
-          'change:activeTab change:orientation change:isOriented',
-          this.updateToolbarHeight,
-        );
-
-        // Add the tray orientation toggles, but only if there is a menu.
-        this.$el
-          .find('.toolbar-tray .toolbar-lining')
-          .has('.toolbar-menu')
-          .append(Drupal.theme('toolbarOrientationToggle'));
-
-        // Trigger an activeTab change so that listening scripts can respond on
-        // page load. This will call render.
-        this.model.trigger('change:activeTab');
-      },
-
-      /**
-       * Update the toolbar element height.
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       */
-      updateToolbarHeight() {
-        const toolbarTabOuterHeight =
-          $('#toolbar-bar').find('.toolbar-tab').outerHeight() || 0;
-        const toolbarTrayHorizontalOuterHeight =
-          $('.is-active.toolbar-tray-horizontal').outerHeight() || 0;
-        this.model.set(
-          'height',
-          toolbarTabOuterHeight + toolbarTrayHorizontalOuterHeight,
-        );
-
-        $('body').css({
-          'padding-top': this.model.get('height'),
-        });
-        $('html').css({
-          'scroll-padding-top': this.model.get('height'),
-        });
-
-        this.triggerDisplace();
-      },
-
-      // Trigger a recalculation of viewport displacing elements. Use setTimeout
-      // to ensure this recalculation happens after changes to visual elements
-      // have processed.
-      triggerDisplace() {
-        _.defer(() => {
-          Drupal.displace(true);
-        });
-      },
-
-      /**
-       * {@inheritdoc}
-       *
-       * @return {Drupal.toolbar.ToolbarVisualView}
-       *   The `ToolbarVisualView` instance.
-       */
-      render() {
-        this.updateTabs();
-        this.updateTrayOrientation();
-        this.updateBarAttributes();
-
-        $('body').removeClass('toolbar-loading');
-
-        // Load the subtrees if the orientation of the toolbar is changed to
-        // vertical. This condition responds to the case that the toolbar switches
-        // from horizontal to vertical orientation. The toolbar starts in a
-        // vertical orientation by default and then switches to horizontal during
-        // initialization if the media query conditions are met. Simply checking
-        // that the orientation is vertical here would result in the subtrees
-        // always being loaded, even when the toolbar initialization ultimately
-        // results in a horizontal orientation.
-        //
-        // @see Drupal.behaviors.toolbar.attach() where admin menu subtrees
-        // loading is invoked during initialization after media query conditions
-        // have been processed.
-        if (
-          this.model.changed.orientation === 'vertical' ||
-          this.model.changed.activeTab
-        ) {
-          this.loadSubtrees();
-        }
-
-        return this;
-      },
-
-      /**
-       * Responds to a toolbar tab click.
-       *
-       * @param {jQuery.Event} event
-       *   The event triggered.
-       */
-      onTabClick(event) {
-        // If this tab has a tray associated with it, it is considered an
-        // activatable tab.
-        if (event.currentTarget.hasAttribute('data-toolbar-tray')) {
-          const activeTab = this.model.get('activeTab');
-          const clickedTab = event.currentTarget;
-
-          // Set the event target as the active item if it is not already.
-          this.model.set(
-            'activeTab',
-            !activeTab || clickedTab !== activeTab ? clickedTab : null,
-          );
-
-          event.preventDefault();
-          event.stopPropagation();
-        }
-      },
-
-      /**
-       * Toggles the orientation of a toolbar tray.
-       *
-       * @param {jQuery.Event} event
-       *   The event triggered.
-       */
-      onOrientationToggleClick(event) {
-        const orientation = this.model.get('orientation');
-        // Determine the toggle-to orientation.
-        const antiOrientation =
-          orientation === 'vertical' ? 'horizontal' : 'vertical';
-        const locked = antiOrientation === 'vertical';
-        // Remember the locked state.
-        if (locked) {
-          localStorage.setItem('Drupal.toolbar.trayVerticalLocked', 'true');
-        } else {
-          localStorage.removeItem('Drupal.toolbar.trayVerticalLocked');
-        }
-        // Update the model.
-        this.model.set(
-          {
-            locked,
-            orientation: antiOrientation,
-          },
-          {
-            validate: true,
-            override: true,
-          },
-        );
-
-        event.preventDefault();
-        event.stopPropagation();
-      },
-
-      /**
-       * Updates the display of the tabs: toggles a tab and the associated tray.
-       */
-      updateTabs() {
-        const $tab = $(this.model.get('activeTab'));
-        // Deactivate the previous tab.
-        $(this.model.previous('activeTab'))
-          .removeClass('is-active')
-          .prop('aria-pressed', false);
-        // Deactivate the previous tray.
-        $(this.model.previous('activeTray')).removeClass('is-active');
-
-        // Activate the selected tab.
-        if ($tab.length > 0) {
-          $tab
-            .addClass('is-active')
-            // Mark the tab as pressed.
-            .prop('aria-pressed', true);
-          const name = $tab.attr('data-toolbar-tray');
-          // Store the active tab name or remove the setting.
-          const id = $tab.get(0).id;
-          if (id) {
-            localStorage.setItem(
-              'Drupal.toolbar.activeTabID',
-              JSON.stringify(id),
-            );
-          }
-          // Activate the associated tray.
-          const $tray = this.$el.find(
-            `[data-toolbar-tray="${name}"].toolbar-tray`,
-          );
-          if ($tray.length) {
-            $tray.addClass('is-active');
-            this.model.set('activeTray', $tray.get(0));
-          } else {
-            // There is no active tray.
-            this.model.set('activeTray', null);
-          }
-        } else {
-          // There is no active tray.
-          this.model.set('activeTray', null);
-          localStorage.removeItem('Drupal.toolbar.activeTabID');
-        }
-      },
-
-      /**
-       * Update the attributes of the toolbar bar element.
-       */
-      updateBarAttributes() {
-        const isOriented = this.model.get('isOriented');
-        if (isOriented) {
-          this.$el.find('.toolbar-bar').attr('data-offset-top', '');
-        } else {
-          this.$el.find('.toolbar-bar').removeAttr('data-offset-top');
-        }
-        // Toggle between a basic vertical view and a more sophisticated
-        // horizontal and vertical display of the toolbar bar and trays.
-        this.$el.toggleClass('toolbar-oriented', isOriented);
-      },
-
-      /**
-       * Updates the orientation of the active tray if necessary.
-       */
-      updateTrayOrientation() {
-        const orientation = this.model.get('orientation');
-
-        // The antiOrientation is used to render the view of action buttons like
-        // the tray orientation toggle.
-        const antiOrientation =
-          orientation === 'vertical' ? 'horizontal' : 'vertical';
-
-        // Toggle toolbar's parent classes before other toolbar classes to avoid
-        // potential flicker and re-rendering.
-        $('body')
-          .toggleClass('toolbar-vertical', orientation === 'vertical')
-          .toggleClass('toolbar-horizontal', orientation === 'horizontal');
-
-        const removeClass =
-          antiOrientation === 'horizontal'
-            ? 'toolbar-tray-horizontal'
-            : 'toolbar-tray-vertical';
-        const $trays = this.$el
-          .find('.toolbar-tray')
-          .removeClass(removeClass)
-          .addClass(`toolbar-tray-${orientation}`);
-
-        // Update the tray orientation toggle button.
-        const iconClass = `toolbar-icon-toggle-${orientation}`;
-        const iconAntiClass = `toolbar-icon-toggle-${antiOrientation}`;
-        const $orientationToggle = this.$el
-          .find('.toolbar-toggle-orientation')
-          .toggle(this.model.get('isTrayToggleVisible'));
-        const $orientationToggleButton = $orientationToggle.find('button');
-        $orientationToggleButton[0].value = antiOrientation;
-        $orientationToggleButton
-          .attr('title', this.strings[antiOrientation])
-          .removeClass(iconClass)
-          .addClass(iconAntiClass);
-        $orientationToggleButton[0].textContent = this.strings[antiOrientation];
-
-        // Update data offset attributes for the trays.
-        const dir = document.documentElement.dir;
-        const edge = dir === 'rtl' ? 'right' : 'left';
-        // Remove data-offset attributes from the trays so they can be refreshed.
-        $trays.removeAttr('data-offset-left data-offset-right data-offset-top');
-        // If an active vertical tray exists, mark it as an offset element.
-        $trays
-          .filter('.toolbar-tray-vertical.is-active')
-          .attr(`data-offset-${edge}`, '');
-        // If an active horizontal tray exists, mark it as an offset element.
-        $trays
-          .filter('.toolbar-tray-horizontal.is-active')
-          .attr('data-offset-top', '');
-      },
-
-      /**
-       * Sets the tops of the trays so that they align with the bottom of the bar.
-       */
-      adjustPlacement() {
-        const $trays = this.$el.find('.toolbar-tray');
-        if (!this.model.get('isOriented')) {
-          $trays
-            .removeClass('toolbar-tray-horizontal')
-            .addClass('toolbar-tray-vertical');
-        }
-      },
-
-      /**
-       * Calls the endpoint URI that builds an AJAX command with the rendered
-       * subtrees.
-       *
-       * The rendered admin menu subtrees HTML is cached on the client in
-       * localStorage until the cache of the admin menu subtrees on the server-
-       * side is invalidated. The subtreesHash is stored in localStorage as well
-       * and compared to the subtreesHash in drupalSettings to determine when the
-       * admin menu subtrees cache has been invalidated.
-       */
-      loadSubtrees() {
-        const $activeTab = $(this.model.get('activeTab'));
-        const orientation = this.model.get('orientation');
-        // Only load and render the admin menu subtrees if:
-        //   (1) They have not been loaded yet.
-        //   (2) The active tab is the administration menu tab, indicated by the
-        //       presence of the data-drupal-subtrees attribute.
-        //   (3) The orientation of the tray is vertical.
-        if (
-          !this.model.get('areSubtreesLoaded') &&
-          typeof $activeTab.data('drupal-subtrees') !== 'undefined' &&
-          orientation === 'vertical'
-        ) {
-          const subtreesHash = drupalSettings.toolbar.subtreesHash;
-          const theme = drupalSettings.ajaxPageState.theme;
-          const endpoint = Drupal.url(`toolbar/subtrees/${subtreesHash}`);
-          const cachedSubtreesHash = localStorage.getItem(
-            `Drupal.toolbar.subtreesHash.${theme}`,
-          );
-          const cachedSubtrees = JSON.parse(
-            localStorage.getItem(`Drupal.toolbar.subtrees.${theme}`),
-          );
-          const isVertical = this.model.get('orientation') === 'vertical';
-          // If we have the subtrees in localStorage and the subtree hash has not
-          // changed, then use the cached data.
-          if (
-            isVertical &&
-            subtreesHash === cachedSubtreesHash &&
-            cachedSubtrees
-          ) {
-            Drupal.toolbar.setSubtrees.resolve(cachedSubtrees);
-          }
-          // Only make the call to get the subtrees if the orientation of the
-          // toolbar is vertical.
-          else if (isVertical) {
-            // Remove the cached menu information.
-            localStorage.removeItem(`Drupal.toolbar.subtreesHash.${theme}`);
-            localStorage.removeItem(`Drupal.toolbar.subtrees.${theme}`);
-            // The AJAX response's command will trigger the resolve method of the
-            // Drupal.toolbar.setSubtrees Promise.
-            Drupal.ajax({ url: endpoint }).execute();
-            // Cache the hash for the subtrees locally.
-            localStorage.setItem(
-              `Drupal.toolbar.subtreesHash.${theme}`,
-              subtreesHash,
-            );
-          }
-        }
-      },
-    },
-  );
-})(jQuery, Drupal, drupalSettings, Backbone);
diff --git a/core/modules/toolbar/js/views/ToolbarVisualView.js b/core/modules/toolbar/js/views/ToolbarVisualView.js
index 49f523c3094e..87c8fc5b3ffa 100644
--- a/core/modules/toolbar/js/views/ToolbarVisualView.js
+++ b/core/modules/toolbar/js/views/ToolbarVisualView.js
@@ -1,192 +1,387 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * A Backbone view for the toolbar element. Listens to mouse & touch.
+ */
 
 (function ($, Drupal, drupalSettings, Backbone) {
-  Drupal.toolbar.ToolbarVisualView = Backbone.View.extend({
-    events() {
-      const touchEndToClick = function (event) {
-        event.preventDefault();
-        event.target.click();
-      };
-
-      return {
-        'click .toolbar-bar .toolbar-tab .trigger': 'onTabClick',
-        'click .toolbar-toggle-orientation button': 'onOrientationToggleClick',
-        'touchend .toolbar-bar .toolbar-tab .trigger': touchEndToClick,
-        'touchend .toolbar-toggle-orientation button': touchEndToClick
-      };
-    },
+  Drupal.toolbar.ToolbarVisualView = Backbone.View.extend(
+    /** @lends Drupal.toolbar.ToolbarVisualView# */ {
+      /**
+       * Event map for the `ToolbarVisualView`.
+       *
+       * @return {object}
+       *   A map of events.
+       */
+      events() {
+        // Prevents delay and simulated mouse events.
+        const touchEndToClick = function (event) {
+          event.preventDefault();
+          event.target.click();
+        };
 
-    initialize(options) {
-      this.strings = options.strings;
-      this.listenTo(this.model, 'change:activeTab change:orientation change:isOriented change:isTrayToggleVisible', this.render);
-      this.listenTo(this.model, 'change:mqMatches', this.onMediaQueryChange);
-      this.listenTo(this.model, 'change:offsets', this.adjustPlacement);
-      this.listenTo(this.model, 'change:activeTab change:orientation change:isOriented', this.updateToolbarHeight);
-      this.$el.find('.toolbar-tray .toolbar-lining').has('.toolbar-menu').append(Drupal.theme('toolbarOrientationToggle'));
-      this.model.trigger('change:activeTab');
-    },
+        return {
+          'click .toolbar-bar .toolbar-tab .trigger': 'onTabClick',
+          'click .toolbar-toggle-orientation button':
+            'onOrientationToggleClick',
+          'touchend .toolbar-bar .toolbar-tab .trigger': touchEndToClick,
+          'touchend .toolbar-toggle-orientation button': touchEndToClick,
+        };
+      },
 
-    updateToolbarHeight() {
-      const toolbarTabOuterHeight = $('#toolbar-bar').find('.toolbar-tab').outerHeight() || 0;
-      const toolbarTrayHorizontalOuterHeight = $('.is-active.toolbar-tray-horizontal').outerHeight() || 0;
-      this.model.set('height', toolbarTabOuterHeight + toolbarTrayHorizontalOuterHeight);
-      $('body').css({
-        'padding-top': this.model.get('height')
-      });
-      $('html').css({
-        'scroll-padding-top': this.model.get('height')
-      });
-      this.triggerDisplace();
-    },
+      /**
+       * Backbone view for the toolbar element. Listens to mouse & touch.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       *
+       * @param {object} options
+       *   Options for the view object.
+       * @param {object} options.strings
+       *   Various strings to use in the view.
+       */
+      initialize(options) {
+        this.strings = options.strings;
 
-    triggerDisplace() {
-      _.defer(() => {
-        Drupal.displace(true);
-      });
-    },
+        this.listenTo(
+          this.model,
+          'change:activeTab change:orientation change:isOriented change:isTrayToggleVisible',
+          this.render,
+        );
+        this.listenTo(this.model, 'change:mqMatches', this.onMediaQueryChange);
+        this.listenTo(this.model, 'change:offsets', this.adjustPlacement);
+        this.listenTo(
+          this.model,
+          'change:activeTab change:orientation change:isOriented',
+          this.updateToolbarHeight,
+        );
 
-    render() {
-      this.updateTabs();
-      this.updateTrayOrientation();
-      this.updateBarAttributes();
-      $('body').removeClass('toolbar-loading');
+        // Add the tray orientation toggles, but only if there is a menu.
+        this.$el
+          .find('.toolbar-tray .toolbar-lining')
+          .has('.toolbar-menu')
+          .append(Drupal.theme('toolbarOrientationToggle'));
 
-      if (this.model.changed.orientation === 'vertical' || this.model.changed.activeTab) {
-        this.loadSubtrees();
-      }
+        // Trigger an activeTab change so that listening scripts can respond on
+        // page load. This will call render.
+        this.model.trigger('change:activeTab');
+      },
 
-      return this;
-    },
+      /**
+       * Update the toolbar element height.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       */
+      updateToolbarHeight() {
+        const toolbarTabOuterHeight =
+          $('#toolbar-bar').find('.toolbar-tab').outerHeight() || 0;
+        const toolbarTrayHorizontalOuterHeight =
+          $('.is-active.toolbar-tray-horizontal').outerHeight() || 0;
+        this.model.set(
+          'height',
+          toolbarTabOuterHeight + toolbarTrayHorizontalOuterHeight,
+        );
 
-    onTabClick(event) {
-      if (event.currentTarget.hasAttribute('data-toolbar-tray')) {
-        const activeTab = this.model.get('activeTab');
-        const clickedTab = event.currentTarget;
-        this.model.set('activeTab', !activeTab || clickedTab !== activeTab ? clickedTab : null);
-        event.preventDefault();
-        event.stopPropagation();
-      }
-    },
+        $('body').css({
+          'padding-top': this.model.get('height'),
+        });
+        $('html').css({
+          'scroll-padding-top': this.model.get('height'),
+        });
 
-    onOrientationToggleClick(event) {
-      const orientation = this.model.get('orientation');
-      const antiOrientation = orientation === 'vertical' ? 'horizontal' : 'vertical';
-      const locked = antiOrientation === 'vertical';
-
-      if (locked) {
-        localStorage.setItem('Drupal.toolbar.trayVerticalLocked', 'true');
-      } else {
-        localStorage.removeItem('Drupal.toolbar.trayVerticalLocked');
-      }
-
-      this.model.set({
-        locked,
-        orientation: antiOrientation
-      }, {
-        validate: true,
-        override: true
-      });
-      event.preventDefault();
-      event.stopPropagation();
-    },
+        this.triggerDisplace();
+      },
 
-    updateTabs() {
-      const $tab = $(this.model.get('activeTab'));
-      $(this.model.previous('activeTab')).removeClass('is-active').prop('aria-pressed', false);
-      $(this.model.previous('activeTray')).removeClass('is-active');
+      // Trigger a recalculation of viewport displacing elements. Use setTimeout
+      // to ensure this recalculation happens after changes to visual elements
+      // have processed.
+      triggerDisplace() {
+        _.defer(() => {
+          Drupal.displace(true);
+        });
+      },
 
-      if ($tab.length > 0) {
-        $tab.addClass('is-active').prop('aria-pressed', true);
-        const name = $tab.attr('data-toolbar-tray');
-        const id = $tab.get(0).id;
+      /**
+       * {@inheritdoc}
+       *
+       * @return {Drupal.toolbar.ToolbarVisualView}
+       *   The `ToolbarVisualView` instance.
+       */
+      render() {
+        this.updateTabs();
+        this.updateTrayOrientation();
+        this.updateBarAttributes();
 
-        if (id) {
-          localStorage.setItem('Drupal.toolbar.activeTabID', JSON.stringify(id));
+        $('body').removeClass('toolbar-loading');
+
+        // Load the subtrees if the orientation of the toolbar is changed to
+        // vertical. This condition responds to the case that the toolbar switches
+        // from horizontal to vertical orientation. The toolbar starts in a
+        // vertical orientation by default and then switches to horizontal during
+        // initialization if the media query conditions are met. Simply checking
+        // that the orientation is vertical here would result in the subtrees
+        // always being loaded, even when the toolbar initialization ultimately
+        // results in a horizontal orientation.
+        //
+        // @see Drupal.behaviors.toolbar.attach() where admin menu subtrees
+        // loading is invoked during initialization after media query conditions
+        // have been processed.
+        if (
+          this.model.changed.orientation === 'vertical' ||
+          this.model.changed.activeTab
+        ) {
+          this.loadSubtrees();
         }
 
-        const $tray = this.$el.find(`[data-toolbar-tray="${name}"].toolbar-tray`);
+        return this;
+      },
+
+      /**
+       * Responds to a toolbar tab click.
+       *
+       * @param {jQuery.Event} event
+       *   The event triggered.
+       */
+      onTabClick(event) {
+        // If this tab has a tray associated with it, it is considered an
+        // activatable tab.
+        if (event.currentTarget.hasAttribute('data-toolbar-tray')) {
+          const activeTab = this.model.get('activeTab');
+          const clickedTab = event.currentTarget;
 
-        if ($tray.length) {
-          $tray.addClass('is-active');
-          this.model.set('activeTray', $tray.get(0));
+          // Set the event target as the active item if it is not already.
+          this.model.set(
+            'activeTab',
+            !activeTab || clickedTab !== activeTab ? clickedTab : null,
+          );
+
+          event.preventDefault();
+          event.stopPropagation();
+        }
+      },
+
+      /**
+       * Toggles the orientation of a toolbar tray.
+       *
+       * @param {jQuery.Event} event
+       *   The event triggered.
+       */
+      onOrientationToggleClick(event) {
+        const orientation = this.model.get('orientation');
+        // Determine the toggle-to orientation.
+        const antiOrientation =
+          orientation === 'vertical' ? 'horizontal' : 'vertical';
+        const locked = antiOrientation === 'vertical';
+        // Remember the locked state.
+        if (locked) {
+          localStorage.setItem('Drupal.toolbar.trayVerticalLocked', 'true');
         } else {
+          localStorage.removeItem('Drupal.toolbar.trayVerticalLocked');
+        }
+        // Update the model.
+        this.model.set(
+          {
+            locked,
+            orientation: antiOrientation,
+          },
+          {
+            validate: true,
+            override: true,
+          },
+        );
+
+        event.preventDefault();
+        event.stopPropagation();
+      },
+
+      /**
+       * Updates the display of the tabs: toggles a tab and the associated tray.
+       */
+      updateTabs() {
+        const $tab = $(this.model.get('activeTab'));
+        // Deactivate the previous tab.
+        $(this.model.previous('activeTab'))
+          .removeClass('is-active')
+          .prop('aria-pressed', false);
+        // Deactivate the previous tray.
+        $(this.model.previous('activeTray')).removeClass('is-active');
+
+        // Activate the selected tab.
+        if ($tab.length > 0) {
+          $tab
+            .addClass('is-active')
+            // Mark the tab as pressed.
+            .prop('aria-pressed', true);
+          const name = $tab.attr('data-toolbar-tray');
+          // Store the active tab name or remove the setting.
+          const id = $tab.get(0).id;
+          if (id) {
+            localStorage.setItem(
+              'Drupal.toolbar.activeTabID',
+              JSON.stringify(id),
+            );
+          }
+          // Activate the associated tray.
+          const $tray = this.$el.find(
+            `[data-toolbar-tray="${name}"].toolbar-tray`,
+          );
+          if ($tray.length) {
+            $tray.addClass('is-active');
+            this.model.set('activeTray', $tray.get(0));
+          } else {
+            // There is no active tray.
+            this.model.set('activeTray', null);
+          }
+        } else {
+          // There is no active tray.
           this.model.set('activeTray', null);
+          localStorage.removeItem('Drupal.toolbar.activeTabID');
         }
-      } else {
-        this.model.set('activeTray', null);
-        localStorage.removeItem('Drupal.toolbar.activeTabID');
-      }
-    },
+      },
 
-    updateBarAttributes() {
-      const isOriented = this.model.get('isOriented');
+      /**
+       * Update the attributes of the toolbar bar element.
+       */
+      updateBarAttributes() {
+        const isOriented = this.model.get('isOriented');
+        if (isOriented) {
+          this.$el.find('.toolbar-bar').attr('data-offset-top', '');
+        } else {
+          this.$el.find('.toolbar-bar').removeAttr('data-offset-top');
+        }
+        // Toggle between a basic vertical view and a more sophisticated
+        // horizontal and vertical display of the toolbar bar and trays.
+        this.$el.toggleClass('toolbar-oriented', isOriented);
+      },
 
-      if (isOriented) {
-        this.$el.find('.toolbar-bar').attr('data-offset-top', '');
-      } else {
-        this.$el.find('.toolbar-bar').removeAttr('data-offset-top');
-      }
+      /**
+       * Updates the orientation of the active tray if necessary.
+       */
+      updateTrayOrientation() {
+        const orientation = this.model.get('orientation');
 
-      this.$el.toggleClass('toolbar-oriented', isOriented);
-    },
+        // The antiOrientation is used to render the view of action buttons like
+        // the tray orientation toggle.
+        const antiOrientation =
+          orientation === 'vertical' ? 'horizontal' : 'vertical';
 
-    updateTrayOrientation() {
-      const orientation = this.model.get('orientation');
-      const antiOrientation = orientation === 'vertical' ? 'horizontal' : 'vertical';
-      $('body').toggleClass('toolbar-vertical', orientation === 'vertical').toggleClass('toolbar-horizontal', orientation === 'horizontal');
-      const removeClass = antiOrientation === 'horizontal' ? 'toolbar-tray-horizontal' : 'toolbar-tray-vertical';
-      const $trays = this.$el.find('.toolbar-tray').removeClass(removeClass).addClass(`toolbar-tray-${orientation}`);
-      const iconClass = `toolbar-icon-toggle-${orientation}`;
-      const iconAntiClass = `toolbar-icon-toggle-${antiOrientation}`;
-      const $orientationToggle = this.$el.find('.toolbar-toggle-orientation').toggle(this.model.get('isTrayToggleVisible'));
-      const $orientationToggleButton = $orientationToggle.find('button');
-      $orientationToggleButton[0].value = antiOrientation;
-      $orientationToggleButton.attr('title', this.strings[antiOrientation]).removeClass(iconClass).addClass(iconAntiClass);
-      $orientationToggleButton[0].textContent = this.strings[antiOrientation];
-      const dir = document.documentElement.dir;
-      const edge = dir === 'rtl' ? 'right' : 'left';
-      $trays.removeAttr('data-offset-left data-offset-right data-offset-top');
-      $trays.filter('.toolbar-tray-vertical.is-active').attr(`data-offset-${edge}`, '');
-      $trays.filter('.toolbar-tray-horizontal.is-active').attr('data-offset-top', '');
-    },
+        // Toggle toolbar's parent classes before other toolbar classes to avoid
+        // potential flicker and re-rendering.
+        $('body')
+          .toggleClass('toolbar-vertical', orientation === 'vertical')
+          .toggleClass('toolbar-horizontal', orientation === 'horizontal');
 
-    adjustPlacement() {
-      const $trays = this.$el.find('.toolbar-tray');
+        const removeClass =
+          antiOrientation === 'horizontal'
+            ? 'toolbar-tray-horizontal'
+            : 'toolbar-tray-vertical';
+        const $trays = this.$el
+          .find('.toolbar-tray')
+          .removeClass(removeClass)
+          .addClass(`toolbar-tray-${orientation}`);
 
-      if (!this.model.get('isOriented')) {
-        $trays.removeClass('toolbar-tray-horizontal').addClass('toolbar-tray-vertical');
-      }
-    },
+        // Update the tray orientation toggle button.
+        const iconClass = `toolbar-icon-toggle-${orientation}`;
+        const iconAntiClass = `toolbar-icon-toggle-${antiOrientation}`;
+        const $orientationToggle = this.$el
+          .find('.toolbar-toggle-orientation')
+          .toggle(this.model.get('isTrayToggleVisible'));
+        const $orientationToggleButton = $orientationToggle.find('button');
+        $orientationToggleButton[0].value = antiOrientation;
+        $orientationToggleButton
+          .attr('title', this.strings[antiOrientation])
+          .removeClass(iconClass)
+          .addClass(iconAntiClass);
+        $orientationToggleButton[0].textContent = this.strings[antiOrientation];
 
-    loadSubtrees() {
-      const $activeTab = $(this.model.get('activeTab'));
-      const orientation = this.model.get('orientation');
-
-      if (!this.model.get('areSubtreesLoaded') && typeof $activeTab.data('drupal-subtrees') !== 'undefined' && orientation === 'vertical') {
-        const subtreesHash = drupalSettings.toolbar.subtreesHash;
-        const theme = drupalSettings.ajaxPageState.theme;
-        const endpoint = Drupal.url(`toolbar/subtrees/${subtreesHash}`);
-        const cachedSubtreesHash = localStorage.getItem(`Drupal.toolbar.subtreesHash.${theme}`);
-        const cachedSubtrees = JSON.parse(localStorage.getItem(`Drupal.toolbar.subtrees.${theme}`));
-        const isVertical = this.model.get('orientation') === 'vertical';
-
-        if (isVertical && subtreesHash === cachedSubtreesHash && cachedSubtrees) {
-          Drupal.toolbar.setSubtrees.resolve(cachedSubtrees);
-        } else if (isVertical) {
-          localStorage.removeItem(`Drupal.toolbar.subtreesHash.${theme}`);
-          localStorage.removeItem(`Drupal.toolbar.subtrees.${theme}`);
-          Drupal.ajax({
-            url: endpoint
-          }).execute();
-          localStorage.setItem(`Drupal.toolbar.subtreesHash.${theme}`, subtreesHash);
+        // Update data offset attributes for the trays.
+        const dir = document.documentElement.dir;
+        const edge = dir === 'rtl' ? 'right' : 'left';
+        // Remove data-offset attributes from the trays so they can be refreshed.
+        $trays.removeAttr('data-offset-left data-offset-right data-offset-top');
+        // If an active vertical tray exists, mark it as an offset element.
+        $trays
+          .filter('.toolbar-tray-vertical.is-active')
+          .attr(`data-offset-${edge}`, '');
+        // If an active horizontal tray exists, mark it as an offset element.
+        $trays
+          .filter('.toolbar-tray-horizontal.is-active')
+          .attr('data-offset-top', '');
+      },
+
+      /**
+       * Sets the tops of the trays so that they align with the bottom of the bar.
+       */
+      adjustPlacement() {
+        const $trays = this.$el.find('.toolbar-tray');
+        if (!this.model.get('isOriented')) {
+          $trays
+            .removeClass('toolbar-tray-horizontal')
+            .addClass('toolbar-tray-vertical');
         }
-      }
-    }
+      },
 
-  });
-})(jQuery, Drupal, drupalSettings, Backbone);
\ No newline at end of file
+      /**
+       * Calls the endpoint URI that builds an AJAX command with the rendered
+       * subtrees.
+       *
+       * The rendered admin menu subtrees HTML is cached on the client in
+       * localStorage until the cache of the admin menu subtrees on the server-
+       * side is invalidated. The subtreesHash is stored in localStorage as well
+       * and compared to the subtreesHash in drupalSettings to determine when the
+       * admin menu subtrees cache has been invalidated.
+       */
+      loadSubtrees() {
+        const $activeTab = $(this.model.get('activeTab'));
+        const orientation = this.model.get('orientation');
+        // Only load and render the admin menu subtrees if:
+        //   (1) They have not been loaded yet.
+        //   (2) The active tab is the administration menu tab, indicated by the
+        //       presence of the data-drupal-subtrees attribute.
+        //   (3) The orientation of the tray is vertical.
+        if (
+          !this.model.get('areSubtreesLoaded') &&
+          typeof $activeTab.data('drupal-subtrees') !== 'undefined' &&
+          orientation === 'vertical'
+        ) {
+          const subtreesHash = drupalSettings.toolbar.subtreesHash;
+          const theme = drupalSettings.ajaxPageState.theme;
+          const endpoint = Drupal.url(`toolbar/subtrees/${subtreesHash}`);
+          const cachedSubtreesHash = localStorage.getItem(
+            `Drupal.toolbar.subtreesHash.${theme}`,
+          );
+          const cachedSubtrees = JSON.parse(
+            localStorage.getItem(`Drupal.toolbar.subtrees.${theme}`),
+          );
+          const isVertical = this.model.get('orientation') === 'vertical';
+          // If we have the subtrees in localStorage and the subtree hash has not
+          // changed, then use the cached data.
+          if (
+            isVertical &&
+            subtreesHash === cachedSubtreesHash &&
+            cachedSubtrees
+          ) {
+            Drupal.toolbar.setSubtrees.resolve(cachedSubtrees);
+          }
+          // Only make the call to get the subtrees if the orientation of the
+          // toolbar is vertical.
+          else if (isVertical) {
+            // Remove the cached menu information.
+            localStorage.removeItem(`Drupal.toolbar.subtreesHash.${theme}`);
+            localStorage.removeItem(`Drupal.toolbar.subtrees.${theme}`);
+            // The AJAX response's command will trigger the resolve method of the
+            // Drupal.toolbar.setSubtrees Promise.
+            Drupal.ajax({ url: endpoint }).execute();
+            // Cache the hash for the subtrees locally.
+            localStorage.setItem(
+              `Drupal.toolbar.subtreesHash.${theme}`,
+              subtreesHash,
+            );
+          }
+        }
+      },
+    },
+  );
+})(jQuery, Drupal, drupalSettings, Backbone);
diff --git a/core/modules/toolbar/tests/src/Nightwatch/Tests/toolbarTest.js b/core/modules/toolbar/tests/src/Nightwatch/Tests/toolbarTest.js
index 45c2afac2eb9..adab3f0212d3 100644
--- a/core/modules/toolbar/tests/src/Nightwatch/Tests/toolbarTest.js
+++ b/core/modules/toolbar/tests/src/Nightwatch/Tests/toolbarTest.js
@@ -157,10 +157,7 @@ module.exports = {
       itemAdministrationTray,
       'is-active toolbar-tray-horizontal',
     );
-    browser.assert.hasClass(
-      '#toolbar-administration',
-      'toolbar-oriented',
-    );
+    browser.assert.hasClass('#toolbar-administration', 'toolbar-oriented');
     browser.setWindowSize(263, 900);
     browser.assert.hasClass(
       itemAdministrationTray,
@@ -339,23 +336,14 @@ module.exports = {
     browser.assert.hasClass(itemUserTray, 'is-active');
     // Set orientation to vertical.
     browser.waitForElementPresent(userOrientationBtn);
-    browser.assert.hasClass(
-      itemUserTray,
-      'is-active toolbar-tray-horizontal',
-    );
+    browser.assert.hasClass(itemUserTray, 'is-active toolbar-tray-horizontal');
     browser.click(userOrientationBtn);
-    browser.assert.hasClass(
-      itemUserTray,
-      'is-active toolbar-tray-vertical',
-    );
+    browser.assert.hasClass(itemUserTray, 'is-active toolbar-tray-vertical');
     browser.refresh();
     // Check user tab is active.
     browser.assert.hasClass(itemUser, 'is-active');
     // Check tray is active and orientation is vertical.
-    browser.assert.hasClass(
-      itemUserTray,
-      'is-active toolbar-tray-vertical',
-    );
+    browser.assert.hasClass(itemUserTray, 'is-active toolbar-tray-vertical');
   },
   'Check toolbar overlap with page content': (browser) => {
     browser.assert.hasClass('body', 'toolbar-horizontal');
diff --git a/core/modules/tour/js/tour.es6.js b/core/modules/tour/js/tour.es6.js
deleted file mode 100644
index 96c66d9846cf..000000000000
--- a/core/modules/tour/js/tour.es6.js
+++ /dev/null
@@ -1,414 +0,0 @@
-/**
- * @file
- * Attaches behaviors for the Tour module's toolbar tab.
- */
-
-(($, Backbone, Drupal, settings, document, Shepherd) => {
-  const queryString = decodeURI(window.location.search);
-
-  /**
-   * Attaches the tour's toolbar tab behavior.
-   *
-   * It uses the query string for:
-   * - tour: When ?tour=1 is present, the tour will start automatically after
-   *   the page has loaded.
-   * - tips: Pass ?tips=class in the url to filter the available tips to the
-   *   subset which match the given class.
-   *
-   * @example
-   * http://example.com/foo?tour=1&tips=bar
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attach tour functionality on `tour` events.
-   */
-  Drupal.behaviors.tour = {
-    attach(context) {
-      once('tour', 'body').forEach(() => {
-        const model = new Drupal.tour.models.StateModel();
-        // eslint-disable-next-line no-new
-        new Drupal.tour.views.ToggleTourView({
-          el: $(context).find('#toolbar-tab-tour'),
-          model,
-        });
-
-        model
-          // Allow other scripts to respond to tour events.
-          .on('change:isActive', (tourModel, isActive) => {
-            $(document).trigger(
-              isActive ? 'drupalTourStarted' : 'drupalTourStopped',
-            );
-          });
-        // Initialization: check whether a tour is available on the current
-        // page.
-        if (settings._tour_internal) {
-          model.set('tour', settings._tour_internal);
-        }
-        // Start the tour immediately if toggled via query string.
-        if (/tour=?/i.test(queryString)) {
-          model.set('isActive', true);
-        }
-      });
-    },
-  };
-
-  /**
-   * @namespace
-   */
-  Drupal.tour = Drupal.tour || {
-    /**
-     * @namespace Drupal.tour.models
-     */
-    models: {},
-
-    /**
-     * @namespace Drupal.tour.views
-     */
-    views: {},
-  };
-
-  /**
-   * Backbone Model for tours.
-   *
-   * @constructor
-   *
-   * @augments Backbone.Model
-   */
-  Drupal.tour.models.StateModel = Backbone.Model.extend(
-    /** @lends Drupal.tour.models.StateModel# */ {
-      /**
-       * @type {object}
-       */
-      defaults: /** @lends Drupal.tour.models.StateModel# */ {
-        /**
-         * Indicates whether the Drupal root window has a tour.
-         *
-         * @type {Array}
-         */
-        tour: [],
-
-        /**
-         * Indicates whether the tour is currently running.
-         *
-         * @type {bool}
-         */
-        isActive: false,
-
-        /**
-         * Indicates which tour is the active one (necessary to cleanly stop).
-         *
-         * @type {Array}
-         */
-        activeTour: [],
-      },
-    },
-  );
-
-  Drupal.tour.views.ToggleTourView = Backbone.View.extend(
-    /** @lends Drupal.tour.views.ToggleTourView# */ {
-      /**
-       * @type {object}
-       */
-      events: { click: 'onClick' },
-
-      /**
-       * Handles edit mode toggle interactions.
-       *
-       * @constructs
-       *
-       * @augments Backbone.View
-       */
-      initialize() {
-        this.listenTo(this.model, 'change:tour change:isActive', this.render);
-        this.listenTo(this.model, 'change:isActive', this.toggleTour);
-      },
-
-      /**
-       * {@inheritdoc}
-       *
-       * @return {Drupal.tour.views.ToggleTourView}
-       *   The `ToggleTourView` view.
-       */
-      render() {
-        // Render the visibility.
-        this.$el.toggleClass('hidden', this._getTour().length === 0);
-        // Render the state.
-        const isActive = this.model.get('isActive');
-        this.$el
-          .find('button')
-          .toggleClass('is-active', isActive)
-          .attr('aria-pressed', isActive);
-        return this;
-      },
-
-      /**
-       * Model change handler; starts or stops the tour.
-       */
-      toggleTour() {
-        if (this.model.get('isActive')) {
-          this._removeIrrelevantTourItems(this._getTour());
-          const tourItems = this.model.get('tour');
-          const that = this;
-
-          if (tourItems.length) {
-            // If Joyride is positioned relative to the top or bottom of an
-            // element, and its secondary position is right or left, then the
-            // arrow is also positioned right or left. Shepherd defaults to
-            // center positioning the arrow.
-            //
-            // In most cases, this arrow positioning difference has
-            // little impact. However, tours built with Joyride may have tips
-            // using a higher level selector than the element the tip is
-            // expected to point to, and relied on Joyride's arrow positioning
-            // to align the arrow with the expected reference element. Joyride's
-            // arrow positioning behavior is replicated here to prevent those
-            // use cases from causing UI regressions.
-            //
-            // This modifier is provided here instead of TourViewBuilder (where
-            // most position modifications are) because it includes adding a
-            // JavaScript callback function.
-            settings.tourShepherdConfig.defaultStepOptions.popperOptions.modifiers.push(
-              {
-                name: 'moveArrowJoyridePosition',
-                enabled: true,
-                phase: 'write',
-                fn({ state }) {
-                  const { arrow } = state.elements;
-                  const { placement } = state;
-                  if (
-                    arrow &&
-                    /^top|bottom/.test(placement) &&
-                    /-start|-end$/.test(placement)
-                  ) {
-                    const horizontalPosition = placement.split('-')[1];
-                    const offset =
-                      horizontalPosition === 'start'
-                        ? 28
-                        : state.elements.popper.clientWidth - 56;
-                    arrow.style.transform = `translate3d(${offset}px, 0px, 0px)`;
-                  }
-                },
-              },
-            );
-            const shepherdTour = new Shepherd.Tour(settings.tourShepherdConfig);
-            shepherdTour.on('cancel', () => {
-              that.model.set('isActive', false);
-            });
-            shepherdTour.on('complete', () => {
-              that.model.set('isActive', false);
-            });
-
-            tourItems.forEach((tourStepConfig, index) => {
-              // Create the configuration for a given tour step by using values
-              // defined in TourViewBuilder.
-              // @see \Drupal\tour\TourViewBuilder::viewMultiple()
-              const tourItemOptions = {
-                title: tourStepConfig.title
-                  ? Drupal.checkPlain(tourStepConfig.title)
-                  : null,
-                text: () => Drupal.theme('tourItemContent', tourStepConfig),
-                attachTo: tourStepConfig.attachTo,
-                buttons: [Drupal.tour.nextButton(shepherdTour, tourStepConfig)],
-                classes: tourStepConfig.classes,
-                index,
-              };
-
-              tourItemOptions.when = {
-                show() {
-                  const nextButton =
-                    shepherdTour.currentStep.el.querySelector('footer button');
-
-                  // Drupal disables Shepherd's built in focus after item
-                  // creation functionality due to focus being set on the tour
-                  // item container after every scroll and resize event. In its
-                  // place, the 'next' button is focused here.
-                  nextButton.focus();
-
-                  // When Stable or Stable 9 are part of the active theme, the
-                  // Drupal.tour.convertToJoyrideMarkup() function is available.
-                  // This function converts Shepherd markup to Joyride markup,
-                  // facilitating the use of the Shepherd library that is
-                  // backwards compatible with customizations intended for
-                  // Joyride.
-                  // The Drupal.tour.convertToJoyrideMarkup() function is
-                  // internal, and will eventually be removed from Drupal core.
-                  if (Drupal.tour.hasOwnProperty('convertToJoyrideMarkup')) {
-                    Drupal.tour.convertToJoyrideMarkup(shepherdTour);
-                  }
-                },
-              };
-
-              shepherdTour.addStep(tourItemOptions);
-            });
-            shepherdTour.start();
-            this.model.set({ isActive: true, activeTour: shepherdTour });
-          }
-        } else {
-          this.model.get('activeTour').cancel();
-          this.model.set({ isActive: false, activeTour: [] });
-        }
-      },
-
-      /**
-       * Toolbar tab click event handler; toggles isActive.
-       *
-       * @param {jQuery.Event} event
-       *   The click event.
-       */
-      onClick(event) {
-        this.model.set('isActive', !this.model.get('isActive'));
-        event.preventDefault();
-        event.stopPropagation();
-      },
-
-      /**
-       * Gets the tour.
-       *
-       * @return {array}
-       *   An array of Shepherd tour item objects.
-       */
-      _getTour() {
-        return this.model.get('tour');
-      },
-
-      /**
-       * Removes tour items for elements that don't have matching page elements.
-       *
-       * Or that are explicitly filtered out via the 'tips' query string.
-       *
-       * @example
-       * <caption>This will filter out tips that do not have a matching
-       * page element or don't have the "bar" class.</caption>
-       * http://example.com/foo?tips=bar
-       *
-       * @param {Object[]} tourItems
-       *   An array containing tour Step config objects.
-       *   The object properties relevant to this function:
-       *   - classes {string}: A string of classes to be added to the tour step
-       *     when rendered.
-       *   - selector {string}: The selector a tour step is associated with.
-       */
-      _removeIrrelevantTourItems(tourItems) {
-        const tips = /tips=([^&]+)/.exec(queryString);
-        const filteredTour = tourItems.filter((tourItem) => {
-          // If the query parameter 'tips' is set, remove all tips that don't
-          // have the matching class. The `tourItem` variable is a step config
-          // object, and the 'classes' property is a ShepherdJS Step() config
-          // option that provides a string.
-          if (
-            tips &&
-            tourItem.hasOwnProperty('classes') &&
-            tourItem.classes.indexOf(tips[1]) === -1
-          ) {
-            return false;
-          }
-
-          // If a selector is configured but there isn't a matching element,
-          // return false.
-          return !(
-            tourItem.selector && !document.querySelector(tourItem.selector)
-          );
-        });
-
-        // If there are tours filtered, we'll have to update model.
-        if (tourItems.length !== filteredTour.length) {
-          filteredTour.forEach((filteredTourItem, filteredTourItemId) => {
-            filteredTour[filteredTourItemId].counter = Drupal.t(
-              '!tour_item of !total',
-              {
-                '!tour_item': filteredTourItemId + 1,
-                '!total': filteredTour.length,
-              },
-            );
-
-            if (filteredTourItemId === filteredTour.length - 1) {
-              filteredTour[filteredTourItemId].cancelText =
-                Drupal.t('End tour');
-            }
-          });
-          this.model.set('tour', filteredTour);
-        }
-      },
-    },
-  );
-
-  /**
-   * Provides an object that will become the tour item's 'next' button.
-   *
-   * Similar to a theme function, themes can override this function to customize
-   * the resulting button. Unlike a theme function, it returns an object instead
-   * of a string, which is why it is not part of Drupal.theme.
-   *
-   * @param {Tour} shepherdTour
-   *  A class representing a Shepherd site tour.
-   * @param {Object} tourStepConfig
-   *   An object generated in TourViewBuilder used for creating the options
-   *   passed to `Tour.addStep(options)`.
-   *   Contains the following properties:
-   *   - id {string}: The tour.tip ID specified by its config
-   *   - selector {string|null}: The selector of the element the tour step is
-   *     attaching to.
-   *   - module {string}: The module providing the tip plugin used by this step.
-   *   - counter {string}: A string indicating which tour step this is out of
-   *     how many total steps.
-   *   - attachTo {Object} This is directly mapped to the `attachTo` Step()
-   *     option. It has two properties:
-   *     - element {string}: The selector of the element the step attaches to.
-   *     - on {string}: a PopperJS compatible string to specify step position.
-   *   - classes {string}: Will be added to the class attribute of the step.
-   *   - body {string}: Markup that is mapped to the `text` Step() option. Will
-   *     become the step content.
-   *   - title {string}: is mapped to the `title` Step() option.
-   *
-   * @return {{classes: string, action: string, text: string}}
-   *    An object structured in the manner Shepherd requires to create the
-   *    'next' button.
-   *
-   * @see https://shepherdjs.dev/docs/Tour.html
-   * @see \Drupal\tour\TourViewBuilder::viewMultiple()
-   * @see https://shepherdjs.dev/docs/Step.html
-   */
-  Drupal.tour.nextButton = (shepherdTour, tourStepConfig) => {
-    return {
-      classes: 'button button--primary',
-      text: tourStepConfig.cancelText
-        ? tourStepConfig.cancelText
-        : Drupal.t('Next'),
-      action: tourStepConfig.cancelText
-        ? shepherdTour.cancel
-        : shepherdTour.next,
-    };
-  };
-
-  /**
-   * Theme function for tour item content.
-   *
-   * @param {Object} tourStepConfig
-   *   An object generated in TourViewBuilder used for creating the options
-   *   passed to `Tour.addStep(options)`.
-   *   Contains the following properties:
-   *   - id {string}: The tour.tip ID specified by its config
-   *   - selector {string|null}: The selector of the element the tour step is
-   *     attaching to.
-   *   - module {string}: The module providing the tip plugin used by this step.
-   *   - counter {string}: A string indicating which tour step this is out of
-   *     how many total steps.
-   *   - attachTo {Object} This is directly mapped to the `attachTo` Step()
-   *     option. It has two properties:
-   *     - element {string}: The selector of the element the step attaches to.
-   *     - on {string}: a PopperJS compatible string to specify step position.
-   *   - classes {string}: Will be added to the class attribute of the step.
-   *   - body {string}: Markup that is mapped to the `text` Step() option. Will
-   *     become the step content.
-   *   - title {string}: is mapped to the `title` Step() option.
-   *
-   * @return {string}
-   *   The tour item content markup.
-   *
-   * @see \Drupal\tour\TourViewBuilder::viewMultiple()
-   * @see https://shepherdjs.dev/docs/Step.html
-   */
-  Drupal.theme.tourItemContent = (tourStepConfig) =>
-    `${tourStepConfig.body}<div class="tour-progress">${tourStepConfig.counter}</div>`;
-})(jQuery, Backbone, Drupal, drupalSettings, document, window.Shepherd);
diff --git a/core/modules/tour/js/tour.js b/core/modules/tour/js/tour.js
index 5d76eae90097..96c66d9846cf 100644
--- a/core/modules/tour/js/tour.js
+++ b/core/modules/tour/js/tour.js
@@ -1,183 +1,414 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Attaches behaviors for the Tour module's toolbar tab.
+ */
 
 (($, Backbone, Drupal, settings, document, Shepherd) => {
   const queryString = decodeURI(window.location.search);
+
+  /**
+   * Attaches the tour's toolbar tab behavior.
+   *
+   * It uses the query string for:
+   * - tour: When ?tour=1 is present, the tour will start automatically after
+   *   the page has loaded.
+   * - tips: Pass ?tips=class in the url to filter the available tips to the
+   *   subset which match the given class.
+   *
+   * @example
+   * http://example.com/foo?tour=1&tips=bar
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach tour functionality on `tour` events.
+   */
   Drupal.behaviors.tour = {
     attach(context) {
       once('tour', 'body').forEach(() => {
         const model = new Drupal.tour.models.StateModel();
+        // eslint-disable-next-line no-new
         new Drupal.tour.views.ToggleTourView({
           el: $(context).find('#toolbar-tab-tour'),
-          model
-        });
-        model.on('change:isActive', (tourModel, isActive) => {
-          $(document).trigger(isActive ? 'drupalTourStarted' : 'drupalTourStopped');
+          model,
         });
 
+        model
+          // Allow other scripts to respond to tour events.
+          .on('change:isActive', (tourModel, isActive) => {
+            $(document).trigger(
+              isActive ? 'drupalTourStarted' : 'drupalTourStopped',
+            );
+          });
+        // Initialization: check whether a tour is available on the current
+        // page.
         if (settings._tour_internal) {
           model.set('tour', settings._tour_internal);
         }
-
+        // Start the tour immediately if toggled via query string.
         if (/tour=?/i.test(queryString)) {
           model.set('isActive', true);
         }
       });
-    }
-
+    },
   };
+
+  /**
+   * @namespace
+   */
   Drupal.tour = Drupal.tour || {
+    /**
+     * @namespace Drupal.tour.models
+     */
     models: {},
-    views: {}
+
+    /**
+     * @namespace Drupal.tour.views
+     */
+    views: {},
   };
-  Drupal.tour.models.StateModel = Backbone.Model.extend({
-    defaults: {
-      tour: [],
-      isActive: false,
-      activeTour: []
-    }
-  });
-  Drupal.tour.views.ToggleTourView = Backbone.View.extend({
-    events: {
-      click: 'onClick'
-    },
 
-    initialize() {
-      this.listenTo(this.model, 'change:tour change:isActive', this.render);
-      this.listenTo(this.model, 'change:isActive', this.toggleTour);
-    },
+  /**
+   * Backbone Model for tours.
+   *
+   * @constructor
+   *
+   * @augments Backbone.Model
+   */
+  Drupal.tour.models.StateModel = Backbone.Model.extend(
+    /** @lends Drupal.tour.models.StateModel# */ {
+      /**
+       * @type {object}
+       */
+      defaults: /** @lends Drupal.tour.models.StateModel# */ {
+        /**
+         * Indicates whether the Drupal root window has a tour.
+         *
+         * @type {Array}
+         */
+        tour: [],
+
+        /**
+         * Indicates whether the tour is currently running.
+         *
+         * @type {bool}
+         */
+        isActive: false,
 
-    render() {
-      this.$el.toggleClass('hidden', this._getTour().length === 0);
-      const isActive = this.model.get('isActive');
-      this.$el.find('button').toggleClass('is-active', isActive).attr('aria-pressed', isActive);
-      return this;
+        /**
+         * Indicates which tour is the active one (necessary to cleanly stop).
+         *
+         * @type {Array}
+         */
+        activeTour: [],
+      },
     },
+  );
 
-    toggleTour() {
-      if (this.model.get('isActive')) {
-        this._removeIrrelevantTourItems(this._getTour());
-
-        const tourItems = this.model.get('tour');
-        const that = this;
-
-        if (tourItems.length) {
-          settings.tourShepherdConfig.defaultStepOptions.popperOptions.modifiers.push({
-            name: 'moveArrowJoyridePosition',
-            enabled: true,
-            phase: 'write',
-
-            fn(_ref) {
-              let {
-                state
-              } = _ref;
-              const {
-                arrow
-              } = state.elements;
-              const {
-                placement
-              } = state;
-
-              if (arrow && /^top|bottom/.test(placement) && /-start|-end$/.test(placement)) {
-                const horizontalPosition = placement.split('-')[1];
-                const offset = horizontalPosition === 'start' ? 28 : state.elements.popper.clientWidth - 56;
-                arrow.style.transform = `translate3d(${offset}px, 0px, 0px)`;
-              }
-            }
+  Drupal.tour.views.ToggleTourView = Backbone.View.extend(
+    /** @lends Drupal.tour.views.ToggleTourView# */ {
+      /**
+       * @type {object}
+       */
+      events: { click: 'onClick' },
 
-          });
-          const shepherdTour = new Shepherd.Tour(settings.tourShepherdConfig);
-          shepherdTour.on('cancel', () => {
-            that.model.set('isActive', false);
-          });
-          shepherdTour.on('complete', () => {
-            that.model.set('isActive', false);
-          });
-          tourItems.forEach((tourStepConfig, index) => {
-            const tourItemOptions = {
-              title: tourStepConfig.title ? Drupal.checkPlain(tourStepConfig.title) : null,
-              text: () => Drupal.theme('tourItemContent', tourStepConfig),
-              attachTo: tourStepConfig.attachTo,
-              buttons: [Drupal.tour.nextButton(shepherdTour, tourStepConfig)],
-              classes: tourStepConfig.classes,
-              index
-            };
-            tourItemOptions.when = {
-              show() {
-                const nextButton = shepherdTour.currentStep.el.querySelector('footer button');
-                nextButton.focus();
-
-                if (Drupal.tour.hasOwnProperty('convertToJoyrideMarkup')) {
-                  Drupal.tour.convertToJoyrideMarkup(shepherdTour);
-                }
-              }
-
-            };
-            shepherdTour.addStep(tourItemOptions);
-          });
-          shepherdTour.start();
-          this.model.set({
-            isActive: true,
-            activeTour: shepherdTour
-          });
-        }
-      } else {
-        this.model.get('activeTour').cancel();
-        this.model.set({
-          isActive: false,
-          activeTour: []
-        });
-      }
-    },
+      /**
+       * Handles edit mode toggle interactions.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       */
+      initialize() {
+        this.listenTo(this.model, 'change:tour change:isActive', this.render);
+        this.listenTo(this.model, 'change:isActive', this.toggleTour);
+      },
 
-    onClick(event) {
-      this.model.set('isActive', !this.model.get('isActive'));
-      event.preventDefault();
-      event.stopPropagation();
-    },
+      /**
+       * {@inheritdoc}
+       *
+       * @return {Drupal.tour.views.ToggleTourView}
+       *   The `ToggleTourView` view.
+       */
+      render() {
+        // Render the visibility.
+        this.$el.toggleClass('hidden', this._getTour().length === 0);
+        // Render the state.
+        const isActive = this.model.get('isActive');
+        this.$el
+          .find('button')
+          .toggleClass('is-active', isActive)
+          .attr('aria-pressed', isActive);
+        return this;
+      },
 
-    _getTour() {
-      return this.model.get('tour');
-    },
+      /**
+       * Model change handler; starts or stops the tour.
+       */
+      toggleTour() {
+        if (this.model.get('isActive')) {
+          this._removeIrrelevantTourItems(this._getTour());
+          const tourItems = this.model.get('tour');
+          const that = this;
+
+          if (tourItems.length) {
+            // If Joyride is positioned relative to the top or bottom of an
+            // element, and its secondary position is right or left, then the
+            // arrow is also positioned right or left. Shepherd defaults to
+            // center positioning the arrow.
+            //
+            // In most cases, this arrow positioning difference has
+            // little impact. However, tours built with Joyride may have tips
+            // using a higher level selector than the element the tip is
+            // expected to point to, and relied on Joyride's arrow positioning
+            // to align the arrow with the expected reference element. Joyride's
+            // arrow positioning behavior is replicated here to prevent those
+            // use cases from causing UI regressions.
+            //
+            // This modifier is provided here instead of TourViewBuilder (where
+            // most position modifications are) because it includes adding a
+            // JavaScript callback function.
+            settings.tourShepherdConfig.defaultStepOptions.popperOptions.modifiers.push(
+              {
+                name: 'moveArrowJoyridePosition',
+                enabled: true,
+                phase: 'write',
+                fn({ state }) {
+                  const { arrow } = state.elements;
+                  const { placement } = state;
+                  if (
+                    arrow &&
+                    /^top|bottom/.test(placement) &&
+                    /-start|-end$/.test(placement)
+                  ) {
+                    const horizontalPosition = placement.split('-')[1];
+                    const offset =
+                      horizontalPosition === 'start'
+                        ? 28
+                        : state.elements.popper.clientWidth - 56;
+                    arrow.style.transform = `translate3d(${offset}px, 0px, 0px)`;
+                  }
+                },
+              },
+            );
+            const shepherdTour = new Shepherd.Tour(settings.tourShepherdConfig);
+            shepherdTour.on('cancel', () => {
+              that.model.set('isActive', false);
+            });
+            shepherdTour.on('complete', () => {
+              that.model.set('isActive', false);
+            });
+
+            tourItems.forEach((tourStepConfig, index) => {
+              // Create the configuration for a given tour step by using values
+              // defined in TourViewBuilder.
+              // @see \Drupal\tour\TourViewBuilder::viewMultiple()
+              const tourItemOptions = {
+                title: tourStepConfig.title
+                  ? Drupal.checkPlain(tourStepConfig.title)
+                  : null,
+                text: () => Drupal.theme('tourItemContent', tourStepConfig),
+                attachTo: tourStepConfig.attachTo,
+                buttons: [Drupal.tour.nextButton(shepherdTour, tourStepConfig)],
+                classes: tourStepConfig.classes,
+                index,
+              };
+
+              tourItemOptions.when = {
+                show() {
+                  const nextButton =
+                    shepherdTour.currentStep.el.querySelector('footer button');
+
+                  // Drupal disables Shepherd's built in focus after item
+                  // creation functionality due to focus being set on the tour
+                  // item container after every scroll and resize event. In its
+                  // place, the 'next' button is focused here.
+                  nextButton.focus();
+
+                  // When Stable or Stable 9 are part of the active theme, the
+                  // Drupal.tour.convertToJoyrideMarkup() function is available.
+                  // This function converts Shepherd markup to Joyride markup,
+                  // facilitating the use of the Shepherd library that is
+                  // backwards compatible with customizations intended for
+                  // Joyride.
+                  // The Drupal.tour.convertToJoyrideMarkup() function is
+                  // internal, and will eventually be removed from Drupal core.
+                  if (Drupal.tour.hasOwnProperty('convertToJoyrideMarkup')) {
+                    Drupal.tour.convertToJoyrideMarkup(shepherdTour);
+                  }
+                },
+              };
 
-    _removeIrrelevantTourItems(tourItems) {
-      const tips = /tips=([^&]+)/.exec(queryString);
-      const filteredTour = tourItems.filter(tourItem => {
-        if (tips && tourItem.hasOwnProperty('classes') && tourItem.classes.indexOf(tips[1]) === -1) {
-          return false;
+              shepherdTour.addStep(tourItemOptions);
+            });
+            shepherdTour.start();
+            this.model.set({ isActive: true, activeTour: shepherdTour });
+          }
+        } else {
+          this.model.get('activeTour').cancel();
+          this.model.set({ isActive: false, activeTour: [] });
         }
+      },
 
-        return !(tourItem.selector && !document.querySelector(tourItem.selector));
-      });
+      /**
+       * Toolbar tab click event handler; toggles isActive.
+       *
+       * @param {jQuery.Event} event
+       *   The click event.
+       */
+      onClick(event) {
+        this.model.set('isActive', !this.model.get('isActive'));
+        event.preventDefault();
+        event.stopPropagation();
+      },
 
-      if (tourItems.length !== filteredTour.length) {
-        filteredTour.forEach((filteredTourItem, filteredTourItemId) => {
-          filteredTour[filteredTourItemId].counter = Drupal.t('!tour_item of !total', {
-            '!tour_item': filteredTourItemId + 1,
-            '!total': filteredTour.length
-          });
+      /**
+       * Gets the tour.
+       *
+       * @return {array}
+       *   An array of Shepherd tour item objects.
+       */
+      _getTour() {
+        return this.model.get('tour');
+      },
 
-          if (filteredTourItemId === filteredTour.length - 1) {
-            filteredTour[filteredTourItemId].cancelText = Drupal.t('End tour');
+      /**
+       * Removes tour items for elements that don't have matching page elements.
+       *
+       * Or that are explicitly filtered out via the 'tips' query string.
+       *
+       * @example
+       * <caption>This will filter out tips that do not have a matching
+       * page element or don't have the "bar" class.</caption>
+       * http://example.com/foo?tips=bar
+       *
+       * @param {Object[]} tourItems
+       *   An array containing tour Step config objects.
+       *   The object properties relevant to this function:
+       *   - classes {string}: A string of classes to be added to the tour step
+       *     when rendered.
+       *   - selector {string}: The selector a tour step is associated with.
+       */
+      _removeIrrelevantTourItems(tourItems) {
+        const tips = /tips=([^&]+)/.exec(queryString);
+        const filteredTour = tourItems.filter((tourItem) => {
+          // If the query parameter 'tips' is set, remove all tips that don't
+          // have the matching class. The `tourItem` variable is a step config
+          // object, and the 'classes' property is a ShepherdJS Step() config
+          // option that provides a string.
+          if (
+            tips &&
+            tourItem.hasOwnProperty('classes') &&
+            tourItem.classes.indexOf(tips[1]) === -1
+          ) {
+            return false;
           }
+
+          // If a selector is configured but there isn't a matching element,
+          // return false.
+          return !(
+            tourItem.selector && !document.querySelector(tourItem.selector)
+          );
         });
-        this.model.set('tour', filteredTour);
-      }
-    }
 
-  });
+        // If there are tours filtered, we'll have to update model.
+        if (tourItems.length !== filteredTour.length) {
+          filteredTour.forEach((filteredTourItem, filteredTourItemId) => {
+            filteredTour[filteredTourItemId].counter = Drupal.t(
+              '!tour_item of !total',
+              {
+                '!tour_item': filteredTourItemId + 1,
+                '!total': filteredTour.length,
+              },
+            );
+
+            if (filteredTourItemId === filteredTour.length - 1) {
+              filteredTour[filteredTourItemId].cancelText =
+                Drupal.t('End tour');
+            }
+          });
+          this.model.set('tour', filteredTour);
+        }
+      },
+    },
+  );
 
+  /**
+   * Provides an object that will become the tour item's 'next' button.
+   *
+   * Similar to a theme function, themes can override this function to customize
+   * the resulting button. Unlike a theme function, it returns an object instead
+   * of a string, which is why it is not part of Drupal.theme.
+   *
+   * @param {Tour} shepherdTour
+   *  A class representing a Shepherd site tour.
+   * @param {Object} tourStepConfig
+   *   An object generated in TourViewBuilder used for creating the options
+   *   passed to `Tour.addStep(options)`.
+   *   Contains the following properties:
+   *   - id {string}: The tour.tip ID specified by its config
+   *   - selector {string|null}: The selector of the element the tour step is
+   *     attaching to.
+   *   - module {string}: The module providing the tip plugin used by this step.
+   *   - counter {string}: A string indicating which tour step this is out of
+   *     how many total steps.
+   *   - attachTo {Object} This is directly mapped to the `attachTo` Step()
+   *     option. It has two properties:
+   *     - element {string}: The selector of the element the step attaches to.
+   *     - on {string}: a PopperJS compatible string to specify step position.
+   *   - classes {string}: Will be added to the class attribute of the step.
+   *   - body {string}: Markup that is mapped to the `text` Step() option. Will
+   *     become the step content.
+   *   - title {string}: is mapped to the `title` Step() option.
+   *
+   * @return {{classes: string, action: string, text: string}}
+   *    An object structured in the manner Shepherd requires to create the
+   *    'next' button.
+   *
+   * @see https://shepherdjs.dev/docs/Tour.html
+   * @see \Drupal\tour\TourViewBuilder::viewMultiple()
+   * @see https://shepherdjs.dev/docs/Step.html
+   */
   Drupal.tour.nextButton = (shepherdTour, tourStepConfig) => {
     return {
       classes: 'button button--primary',
-      text: tourStepConfig.cancelText ? tourStepConfig.cancelText : Drupal.t('Next'),
-      action: tourStepConfig.cancelText ? shepherdTour.cancel : shepherdTour.next
+      text: tourStepConfig.cancelText
+        ? tourStepConfig.cancelText
+        : Drupal.t('Next'),
+      action: tourStepConfig.cancelText
+        ? shepherdTour.cancel
+        : shepherdTour.next,
     };
   };
 
-  Drupal.theme.tourItemContent = tourStepConfig => `${tourStepConfig.body}<div class="tour-progress">${tourStepConfig.counter}</div>`;
-})(jQuery, Backbone, Drupal, drupalSettings, document, window.Shepherd);
\ No newline at end of file
+  /**
+   * Theme function for tour item content.
+   *
+   * @param {Object} tourStepConfig
+   *   An object generated in TourViewBuilder used for creating the options
+   *   passed to `Tour.addStep(options)`.
+   *   Contains the following properties:
+   *   - id {string}: The tour.tip ID specified by its config
+   *   - selector {string|null}: The selector of the element the tour step is
+   *     attaching to.
+   *   - module {string}: The module providing the tip plugin used by this step.
+   *   - counter {string}: A string indicating which tour step this is out of
+   *     how many total steps.
+   *   - attachTo {Object} This is directly mapped to the `attachTo` Step()
+   *     option. It has two properties:
+   *     - element {string}: The selector of the element the step attaches to.
+   *     - on {string}: a PopperJS compatible string to specify step position.
+   *   - classes {string}: Will be added to the class attribute of the step.
+   *   - body {string}: Markup that is mapped to the `text` Step() option. Will
+   *     become the step content.
+   *   - title {string}: is mapped to the `title` Step() option.
+   *
+   * @return {string}
+   *   The tour item content markup.
+   *
+   * @see \Drupal\tour\TourViewBuilder::viewMultiple()
+   * @see https://shepherdjs.dev/docs/Step.html
+   */
+  Drupal.theme.tourItemContent = (tourStepConfig) =>
+    `${tourStepConfig.body}<div class="tour-progress">${tourStepConfig.counter}</div>`;
+})(jQuery, Backbone, Drupal, drupalSettings, document, window.Shepherd);
diff --git a/core/modules/tracker/js/tracker-history.es6.js b/core/modules/tracker/js/tracker-history.es6.js
deleted file mode 100644
index 934fb186a13c..000000000000
--- a/core/modules/tracker/js/tracker-history.es6.js
+++ /dev/null
@@ -1,149 +0,0 @@
-/**
- * Attaches behaviors for the Tracker module's History module integration.
- *
- * May only be loaded for authenticated users, with the History module enabled.
- */
-(function ($, Drupal, window) {
-  function processNodeNewIndicators(placeholders) {
-    const newNodeString = Drupal.t('new');
-    const updatedNodeString = Drupal.t('updated');
-
-    placeholders.forEach((placeholder) => {
-      const timestamp = parseInt(
-        placeholder.getAttribute('data-history-node-timestamp'),
-        10,
-      );
-      const nodeID = placeholder.getAttribute('data-history-node-id');
-      const lastViewTimestamp = Drupal.history.getLastRead(nodeID);
-
-      if (timestamp > lastViewTimestamp) {
-        const message =
-          lastViewTimestamp === 0 ? newNodeString : updatedNodeString;
-        $(placeholder).append(`<span class="marker">${message}</span>`);
-      }
-    });
-  }
-
-  function processNewRepliesIndicators(placeholders) {
-    // Figure out which placeholders need the "x new" replies links.
-    const placeholdersToUpdate = {};
-    placeholders.forEach((placeholder) => {
-      const timestamp = parseInt(
-        placeholder.getAttribute('data-history-node-last-comment-timestamp'),
-        10,
-      );
-      const nodeID = placeholder.previousSibling.previousSibling.getAttribute(
-        'data-history-node-id',
-      );
-      const lastViewTimestamp = Drupal.history.getLastRead(nodeID);
-
-      // Queue this placeholder's "X new" replies link to be downloaded from the
-      // server.
-      if (timestamp > lastViewTimestamp) {
-        placeholdersToUpdate[nodeID] = placeholder;
-      }
-    });
-
-    // Perform an AJAX request to retrieve node view timestamps.
-    const nodeIDs = Object.keys(placeholdersToUpdate);
-    if (nodeIDs.length === 0) {
-      return;
-    }
-    $.ajax({
-      url: Drupal.url('comments/render_new_comments_node_links'),
-      type: 'POST',
-      data: { 'node_ids[]': nodeIDs },
-      dataType: 'json',
-      success(results) {
-        Object.keys(results || {}).forEach((nodeID) => {
-          if (placeholdersToUpdate.hasOwnProperty(nodeID)) {
-            const url = results[nodeID].first_new_comment_link;
-            const text = Drupal.formatPlural(
-              results[nodeID].new_comment_count,
-              '1 new',
-              '@count new',
-            );
-            $(placeholdersToUpdate[nodeID]).append(
-              `<br /><a href="${url}">${text}</a>`,
-            );
-          }
-        });
-      },
-    });
-  }
-
-  /**
-   * Render "new" and "updated" node indicators, as well as "X new" replies links.
-   */
-  Drupal.behaviors.trackerHistory = {
-    attach(context) {
-      // Find all "new" comment indicator placeholders newer than 30 days ago that
-      // have not already been read after their last comment timestamp.
-      const nodeIDs = [];
-      const nodeNewPlaceholders = once(
-        'history',
-        '[data-history-node-timestamp]',
-        context,
-      ).filter((placeholder) => {
-        const nodeTimestamp = parseInt(
-          placeholder.getAttribute('data-history-node-timestamp'),
-          10,
-        );
-        const nodeID = placeholder.getAttribute('data-history-node-id');
-        if (Drupal.history.needsServerCheck(nodeID, nodeTimestamp)) {
-          nodeIDs.push(nodeID);
-          return true;
-        }
-
-        return false;
-      });
-
-      // Find all "new" comment indicator placeholders newer than 30 days ago that
-      // have not already been read after their last comment timestamp.
-      const newRepliesPlaceholders = once(
-        'history',
-        '[data-history-node-last-comment-timestamp]',
-        context,
-      ).filter((placeholder) => {
-        const lastCommentTimestamp = parseInt(
-          placeholder.getAttribute('data-history-node-last-comment-timestamp'),
-          10,
-        );
-        const nodeTimestamp = parseInt(
-          placeholder.previousSibling.previousSibling.getAttribute(
-            'data-history-node-timestamp',
-          ),
-          10,
-        );
-        // Discard placeholders that have zero comments.
-        if (lastCommentTimestamp === nodeTimestamp) {
-          return false;
-        }
-        const nodeID = placeholder.previousSibling.previousSibling.getAttribute(
-          'data-history-node-id',
-        );
-        if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) {
-          if (nodeIDs.indexOf(nodeID) === -1) {
-            nodeIDs.push(nodeID);
-          }
-          return true;
-        }
-
-        return false;
-      });
-
-      if (
-        nodeNewPlaceholders.length === 0 &&
-        newRepliesPlaceholders.length === 0
-      ) {
-        return;
-      }
-
-      // Fetch the node read timestamps from the server.
-      Drupal.history.fetchTimestamps(nodeIDs, () => {
-        processNodeNewIndicators(nodeNewPlaceholders);
-        processNewRepliesIndicators(newRepliesPlaceholders);
-      });
-    },
-  };
-})(jQuery, Drupal, window);
diff --git a/core/modules/tracker/js/tracker-history.js b/core/modules/tracker/js/tracker-history.js
index 520fec26f60f..934fb186a13c 100644
--- a/core/modules/tracker/js/tracker-history.js
+++ b/core/modules/tracker/js/tracker-history.js
@@ -1,71 +1,95 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * Attaches behaviors for the Tracker module's History module integration.
+ *
+ * May only be loaded for authenticated users, with the History module enabled.
+ */
 (function ($, Drupal, window) {
   function processNodeNewIndicators(placeholders) {
     const newNodeString = Drupal.t('new');
     const updatedNodeString = Drupal.t('updated');
-    placeholders.forEach(placeholder => {
-      const timestamp = parseInt(placeholder.getAttribute('data-history-node-timestamp'), 10);
+
+    placeholders.forEach((placeholder) => {
+      const timestamp = parseInt(
+        placeholder.getAttribute('data-history-node-timestamp'),
+        10,
+      );
       const nodeID = placeholder.getAttribute('data-history-node-id');
       const lastViewTimestamp = Drupal.history.getLastRead(nodeID);
 
       if (timestamp > lastViewTimestamp) {
-        const message = lastViewTimestamp === 0 ? newNodeString : updatedNodeString;
+        const message =
+          lastViewTimestamp === 0 ? newNodeString : updatedNodeString;
         $(placeholder).append(`<span class="marker">${message}</span>`);
       }
     });
   }
 
   function processNewRepliesIndicators(placeholders) {
+    // Figure out which placeholders need the "x new" replies links.
     const placeholdersToUpdate = {};
-    placeholders.forEach(placeholder => {
-      const timestamp = parseInt(placeholder.getAttribute('data-history-node-last-comment-timestamp'), 10);
-      const nodeID = placeholder.previousSibling.previousSibling.getAttribute('data-history-node-id');
+    placeholders.forEach((placeholder) => {
+      const timestamp = parseInt(
+        placeholder.getAttribute('data-history-node-last-comment-timestamp'),
+        10,
+      );
+      const nodeID = placeholder.previousSibling.previousSibling.getAttribute(
+        'data-history-node-id',
+      );
       const lastViewTimestamp = Drupal.history.getLastRead(nodeID);
 
+      // Queue this placeholder's "X new" replies link to be downloaded from the
+      // server.
       if (timestamp > lastViewTimestamp) {
         placeholdersToUpdate[nodeID] = placeholder;
       }
     });
-    const nodeIDs = Object.keys(placeholdersToUpdate);
 
+    // Perform an AJAX request to retrieve node view timestamps.
+    const nodeIDs = Object.keys(placeholdersToUpdate);
     if (nodeIDs.length === 0) {
       return;
     }
-
     $.ajax({
       url: Drupal.url('comments/render_new_comments_node_links'),
       type: 'POST',
-      data: {
-        'node_ids[]': nodeIDs
-      },
+      data: { 'node_ids[]': nodeIDs },
       dataType: 'json',
-
       success(results) {
-        Object.keys(results || {}).forEach(nodeID => {
+        Object.keys(results || {}).forEach((nodeID) => {
           if (placeholdersToUpdate.hasOwnProperty(nodeID)) {
             const url = results[nodeID].first_new_comment_link;
-            const text = Drupal.formatPlural(results[nodeID].new_comment_count, '1 new', '@count new');
-            $(placeholdersToUpdate[nodeID]).append(`<br /><a href="${url}">${text}</a>`);
+            const text = Drupal.formatPlural(
+              results[nodeID].new_comment_count,
+              '1 new',
+              '@count new',
+            );
+            $(placeholdersToUpdate[nodeID]).append(
+              `<br /><a href="${url}">${text}</a>`,
+            );
           }
         });
-      }
-
+      },
     });
   }
 
+  /**
+   * Render "new" and "updated" node indicators, as well as "X new" replies links.
+   */
   Drupal.behaviors.trackerHistory = {
     attach(context) {
+      // Find all "new" comment indicator placeholders newer than 30 days ago that
+      // have not already been read after their last comment timestamp.
       const nodeIDs = [];
-      const nodeNewPlaceholders = once('history', '[data-history-node-timestamp]', context).filter(placeholder => {
-        const nodeTimestamp = parseInt(placeholder.getAttribute('data-history-node-timestamp'), 10);
+      const nodeNewPlaceholders = once(
+        'history',
+        '[data-history-node-timestamp]',
+        context,
+      ).filter((placeholder) => {
+        const nodeTimestamp = parseInt(
+          placeholder.getAttribute('data-history-node-timestamp'),
+          10,
+        );
         const nodeID = placeholder.getAttribute('data-history-node-id');
-
         if (Drupal.history.needsServerCheck(nodeID, nodeTimestamp)) {
           nodeIDs.push(nodeID);
           return true;
@@ -73,36 +97,53 @@
 
         return false;
       });
-      const newRepliesPlaceholders = once('history', '[data-history-node-last-comment-timestamp]', context).filter(placeholder => {
-        const lastCommentTimestamp = parseInt(placeholder.getAttribute('data-history-node-last-comment-timestamp'), 10);
-        const nodeTimestamp = parseInt(placeholder.previousSibling.previousSibling.getAttribute('data-history-node-timestamp'), 10);
 
+      // Find all "new" comment indicator placeholders newer than 30 days ago that
+      // have not already been read after their last comment timestamp.
+      const newRepliesPlaceholders = once(
+        'history',
+        '[data-history-node-last-comment-timestamp]',
+        context,
+      ).filter((placeholder) => {
+        const lastCommentTimestamp = parseInt(
+          placeholder.getAttribute('data-history-node-last-comment-timestamp'),
+          10,
+        );
+        const nodeTimestamp = parseInt(
+          placeholder.previousSibling.previousSibling.getAttribute(
+            'data-history-node-timestamp',
+          ),
+          10,
+        );
+        // Discard placeholders that have zero comments.
         if (lastCommentTimestamp === nodeTimestamp) {
           return false;
         }
-
-        const nodeID = placeholder.previousSibling.previousSibling.getAttribute('data-history-node-id');
-
+        const nodeID = placeholder.previousSibling.previousSibling.getAttribute(
+          'data-history-node-id',
+        );
         if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) {
           if (nodeIDs.indexOf(nodeID) === -1) {
             nodeIDs.push(nodeID);
           }
-
           return true;
         }
 
         return false;
       });
 
-      if (nodeNewPlaceholders.length === 0 && newRepliesPlaceholders.length === 0) {
+      if (
+        nodeNewPlaceholders.length === 0 &&
+        newRepliesPlaceholders.length === 0
+      ) {
         return;
       }
 
+      // Fetch the node read timestamps from the server.
       Drupal.history.fetchTimestamps(nodeIDs, () => {
         processNodeNewIndicators(nodeNewPlaceholders);
         processNewRepliesIndicators(newRepliesPlaceholders);
       });
-    }
-
+    },
   };
-})(jQuery, Drupal, window);
\ No newline at end of file
+})(jQuery, Drupal, window);
diff --git a/core/modules/user/user.es6.js b/core/modules/user/user.es6.js
deleted file mode 100644
index 8652cc467d4e..000000000000
--- a/core/modules/user/user.es6.js
+++ /dev/null
@@ -1,370 +0,0 @@
-/**
- * @file
- * User behaviors.
- */
-
-(($, Drupal) => {
-  /**
-   * An object containing CSS classes used for password widget.
-   *
-   * @type {object}
-   * @prop {string} passwordParent - A CSS class for the parent element.
-   * @prop {string} passwordsMatch - A CSS class indicating password match.
-   * @prop {string} passwordsNotMatch - A CSS class indicating passwords
-   *   doesn't match.
-   * @prop {string} passwordWeak - A CSS class indicating weak password
-   *   strength.
-   * @prop {string} passwordFair - A CSS class indicating fair password
-   *   strength.
-   * @prop {string} passwordGood - A CSS class indicating good password
-   *   strength.
-   * @prop {string} passwordStrong - A CSS class indicating strong password
-   *   strength.
-   * @prop {string} widgetInitial - Initial CSS class that should be removed
-   *   on a state change.
-   * @prop {string} passwordEmpty - A CSS class indicating password has not
-   *   been filled.
-   * @prop {string} passwordFilled - A CSS class indicating password has
-   *   been filled.
-   * @prop {string} confirmEmpty - A CSS class indicating password
-   *   confirmation has not been filled.
-   * @prop {string} confirmFilled - A CSS class indicating password
-   *   confirmation has been filled.
-   */
-  Drupal.user = {
-    password: {
-      css: {
-        passwordParent: 'password-parent',
-        passwordsMatch: 'ok',
-        passwordsNotMatch: 'error',
-        passwordWeak: 'is-weak',
-        passwordFair: 'is-fair',
-        passwordGood: 'is-good',
-        passwordStrong: 'is-strong',
-        widgetInitial: '',
-        passwordEmpty: '',
-        passwordFilled: '',
-        confirmEmpty: '',
-        confirmFilled: '',
-      },
-    },
-  };
-
-  /**
-   * Attach handlers to evaluate the strength of any password fields and to
-   * check that its confirmation is correct.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches password strength indicator and other relevant validation to
-   *   password fields.
-   */
-  Drupal.behaviors.password = {
-    attach(context, settings) {
-      const cssClasses = Drupal.user.password.css;
-      once('password', 'input.js-password-field', context).forEach((value) => {
-        const $mainInput = $(value);
-        const $mainInputParent = $mainInput
-          .parent()
-          .addClass(cssClasses.passwordParent);
-        const $passwordWidget = $mainInput.closest(
-          '.js-form-type-password-confirm',
-        );
-        const $confirmInput = $passwordWidget.find('input.js-password-confirm');
-        const $passwordConfirmMessage = $(
-          Drupal.theme('passwordConfirmMessage', settings.password),
-        );
-
-        const $passwordMatchStatus = $passwordConfirmMessage
-          .find('[data-drupal-selector="password-match-status-text"]')
-          .first();
-
-        const $confirmInputParent = $confirmInput
-          .parent()
-          .addClass('confirm-parent')
-          .append($passwordConfirmMessage);
-
-        // List of classes to be removed from the strength bar on a state
-        // change.
-        const passwordStrengthBarClassesToRemove = [
-          cssClasses.passwordWeak || '',
-          cssClasses.passwordFair || '',
-          cssClasses.passwordGood || '',
-          cssClasses.passwordStrong || '',
-        ]
-          .join(' ')
-          .trim();
-
-        // List of classes to be removed from the text wrapper on a state
-        // change.
-        const confirmTextWrapperClassesToRemove = [
-          cssClasses.passwordsMatch || '',
-          cssClasses.passwordsNotMatch || '',
-        ]
-          .join(' ')
-          .trim();
-
-        // List of classes to be removed from the widget on a state change.
-        const widgetClassesToRemove = [
-          cssClasses.widgetInitial || '',
-          cssClasses.passwordEmpty || '',
-          cssClasses.passwordFilled || '',
-          cssClasses.confirmEmpty || '',
-          cssClasses.confirmFilled || '',
-        ]
-          .join(' ')
-          .trim();
-
-        const password = {};
-
-        // If the password strength indicator is enabled, add its markup.
-        if (settings.password.showStrengthIndicator) {
-          const $passwordStrength = $(
-            Drupal.theme('passwordStrength', settings.password),
-          );
-          password.$strengthBar = $passwordStrength
-            .find('[data-drupal-selector="password-strength-indicator"]')
-            .first();
-          password.$strengthTextWrapper = $passwordStrength
-            .find('[data-drupal-selector="password-strength-text"]')
-            .first();
-          password.$suggestions = $(
-            Drupal.theme('passwordSuggestions', settings.password, []),
-          );
-
-          password.$suggestions.hide();
-          $mainInputParent.append($passwordStrength);
-          $confirmInputParent.after(password.$suggestions);
-        }
-
-        /**
-         * Adds classes to the widget indicating if the elements are filled.
-         */
-        const addWidgetClasses = () => {
-          $passwordWidget
-            .addClass(
-              $mainInput[0].value
-                ? cssClasses.passwordFilled
-                : cssClasses.passwordEmpty,
-            )
-            .addClass(
-              $confirmInput[0].value
-                ? cssClasses.confirmFilled
-                : cssClasses.confirmEmpty,
-            );
-        };
-
-        /**
-         * Check that password and confirmation inputs match.
-         *
-         * @param {string} confirmInputVal
-         *   The value of the confirm input.
-         */
-        const passwordCheckMatch = (confirmInputVal) => {
-          const passwordsAreMatching = $mainInput[0].value === confirmInputVal;
-          const confirmClass = passwordsAreMatching
-            ? cssClasses.passwordsMatch
-            : cssClasses.passwordsNotMatch;
-          const confirmMessage = passwordsAreMatching
-            ? settings.password.confirmSuccess
-            : settings.password.confirmFailure;
-
-          // Update the success message and set the class if needed.
-          if (
-            !$passwordMatchStatus.hasClass(confirmClass) ||
-            !$passwordMatchStatus.html() === confirmMessage
-          ) {
-            if (confirmTextWrapperClassesToRemove) {
-              $passwordMatchStatus.removeClass(
-                confirmTextWrapperClassesToRemove,
-              );
-            }
-            $passwordMatchStatus.html(confirmMessage).addClass(confirmClass);
-          }
-        };
-
-        /**
-         * Checks the password strength.
-         */
-        const passwordCheck = () => {
-          if (settings.password.showStrengthIndicator) {
-            // Evaluate the password strength.
-            const result = Drupal.evaluatePasswordStrength(
-              $mainInput[0].value,
-              settings.password,
-            );
-            const $currentPasswordSuggestions = $(
-              Drupal.theme(
-                'passwordSuggestions',
-                settings.password,
-                result.messageTips,
-              ),
-            );
-
-            // Update the suggestions for how to improve the password if needed.
-            if (
-              password.$suggestions.html() !==
-              $currentPasswordSuggestions.html()
-            ) {
-              password.$suggestions.replaceWith($currentPasswordSuggestions);
-              password.$suggestions = $currentPasswordSuggestions.toggle(
-                // Only show the description box if a weakness exists in the
-                // password.
-                result.strength !== 100,
-              );
-            }
-
-            if (passwordStrengthBarClassesToRemove) {
-              password.$strengthBar.removeClass(
-                passwordStrengthBarClassesToRemove,
-              );
-            }
-            // Adjust the length of the strength indicator.
-            password.$strengthBar
-              .css('width', `${result.strength}%`)
-              .addClass(result.indicatorClass);
-
-            // Update the strength indication text.
-            password.$strengthTextWrapper.html(result.indicatorText);
-          }
-
-          // Check the value in the confirm input and show results.
-          if ($confirmInput[0].value) {
-            passwordCheckMatch($confirmInput[0].value);
-            $passwordConfirmMessage.css({ visibility: 'visible' });
-          } else {
-            $passwordConfirmMessage.css({ visibility: 'hidden' });
-          }
-
-          if (widgetClassesToRemove) {
-            $passwordWidget.removeClass(widgetClassesToRemove);
-            addWidgetClasses();
-          }
-        };
-
-        if (widgetClassesToRemove) {
-          addWidgetClasses();
-        }
-
-        // Monitor input events.
-        $mainInput.on('input', passwordCheck);
-        $confirmInput.on('input', passwordCheck);
-      });
-    },
-  };
-
-  /**
-   * Evaluate the strength of a user's password.
-   *
-   * Returns the estimated strength and the relevant output message.
-   *
-   * @param {string} password
-   *   The password to evaluate.
-   * @param {object} passwordSettings
-   *   A password settings object containing the text to display and the CSS
-   *   classes for each strength level.
-   *
-   * @return {object}
-   *   An object containing strength, message, indicatorText and indicatorClass.
-   */
-  Drupal.evaluatePasswordStrength = (password, passwordSettings) => {
-    password = password.trim();
-    let indicatorText;
-    let indicatorClass;
-    let weaknesses = 0;
-    let strength = 100;
-    let msg = [];
-
-    const hasLowercase = /[a-z]/.test(password);
-    const hasUppercase = /[A-Z]/.test(password);
-    const hasNumbers = /[0-9]/.test(password);
-    const hasPunctuation = /[^a-zA-Z0-9]/.test(password);
-
-    // If there is a username edit box on the page, compare password to that,
-    // otherwise use value from the database.
-    const $usernameBox = $('input.username');
-    const username =
-      $usernameBox.length > 0
-        ? $usernameBox[0].value
-        : passwordSettings.username;
-
-    // Lose 5 points for every character less than 12, plus a 30 point penalty.
-    if (password.length < 12) {
-      msg.push(passwordSettings.tooShort);
-      strength -= (12 - password.length) * 5 + 30;
-    }
-
-    // Count weaknesses.
-    if (!hasLowercase) {
-      msg.push(passwordSettings.addLowerCase);
-      weaknesses += 1;
-    }
-    if (!hasUppercase) {
-      msg.push(passwordSettings.addUpperCase);
-      weaknesses += 1;
-    }
-    if (!hasNumbers) {
-      msg.push(passwordSettings.addNumbers);
-      weaknesses += 1;
-    }
-    if (!hasPunctuation) {
-      msg.push(passwordSettings.addPunctuation);
-      weaknesses += 1;
-    }
-
-    // Apply penalty for each weakness (balanced against length penalty).
-    switch (weaknesses) {
-      case 1:
-        strength -= 12.5;
-        break;
-
-      case 2:
-        strength -= 25;
-        break;
-
-      case 3:
-      case 4:
-        strength -= 40;
-        break;
-    }
-
-    // Check if password is the same as the username.
-    if (password !== '' && password.toLowerCase() === username.toLowerCase()) {
-      msg.push(passwordSettings.sameAsUsername);
-      // Passwords the same as username are always very weak.
-      strength = 5;
-    }
-
-    const cssClasses = Drupal.user.password.css;
-
-    // Based on the strength, work out what text should be shown by the
-    // password strength meter.
-    if (strength < 60) {
-      indicatorText = passwordSettings.weak;
-      indicatorClass = cssClasses.passwordWeak;
-    } else if (strength < 70) {
-      indicatorText = passwordSettings.fair;
-      indicatorClass = cssClasses.passwordFair;
-    } else if (strength < 80) {
-      indicatorText = passwordSettings.good;
-      indicatorClass = cssClasses.passwordGood;
-    } else if (strength <= 100) {
-      indicatorText = passwordSettings.strong;
-      indicatorClass = cssClasses.passwordStrong;
-    }
-
-    // Assemble the final message while keeping the original message array.
-    const messageTips = msg;
-    msg = `${passwordSettings.hasWeaknesses}<ul><li>${msg.join(
-      '</li><li>',
-    )}</li></ul>`;
-
-    return {
-      strength,
-      indicatorText,
-      indicatorClass,
-      messageTips,
-    };
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/user/user.js b/core/modules/user/user.js
index d0ec474544b1..8652cc467d4e 100644
--- a/core/modules/user/user.js
+++ b/core/modules/user/user.js
@@ -1,11 +1,36 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * User behaviors.
+ */
 
 (($, Drupal) => {
+  /**
+   * An object containing CSS classes used for password widget.
+   *
+   * @type {object}
+   * @prop {string} passwordParent - A CSS class for the parent element.
+   * @prop {string} passwordsMatch - A CSS class indicating password match.
+   * @prop {string} passwordsNotMatch - A CSS class indicating passwords
+   *   doesn't match.
+   * @prop {string} passwordWeak - A CSS class indicating weak password
+   *   strength.
+   * @prop {string} passwordFair - A CSS class indicating fair password
+   *   strength.
+   * @prop {string} passwordGood - A CSS class indicating good password
+   *   strength.
+   * @prop {string} passwordStrong - A CSS class indicating strong password
+   *   strength.
+   * @prop {string} widgetInitial - Initial CSS class that should be removed
+   *   on a state change.
+   * @prop {string} passwordEmpty - A CSS class indicating password has not
+   *   been filled.
+   * @prop {string} passwordFilled - A CSS class indicating password has
+   *   been filled.
+   * @prop {string} confirmEmpty - A CSS class indicating password
+   *   confirmation has not been filled.
+   * @prop {string} confirmFilled - A CSS class indicating password
+   *   confirmation has been filled.
+   */
   Drupal.user = {
     password: {
       css: {
@@ -20,81 +45,196 @@
         passwordEmpty: '',
         passwordFilled: '',
         confirmEmpty: '',
-        confirmFilled: ''
-      }
-    }
+        confirmFilled: '',
+      },
+    },
   };
+
+  /**
+   * Attach handlers to evaluate the strength of any password fields and to
+   * check that its confirmation is correct.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches password strength indicator and other relevant validation to
+   *   password fields.
+   */
   Drupal.behaviors.password = {
     attach(context, settings) {
       const cssClasses = Drupal.user.password.css;
-      once('password', 'input.js-password-field', context).forEach(value => {
+      once('password', 'input.js-password-field', context).forEach((value) => {
         const $mainInput = $(value);
-        const $mainInputParent = $mainInput.parent().addClass(cssClasses.passwordParent);
-        const $passwordWidget = $mainInput.closest('.js-form-type-password-confirm');
+        const $mainInputParent = $mainInput
+          .parent()
+          .addClass(cssClasses.passwordParent);
+        const $passwordWidget = $mainInput.closest(
+          '.js-form-type-password-confirm',
+        );
         const $confirmInput = $passwordWidget.find('input.js-password-confirm');
-        const $passwordConfirmMessage = $(Drupal.theme('passwordConfirmMessage', settings.password));
-        const $passwordMatchStatus = $passwordConfirmMessage.find('[data-drupal-selector="password-match-status-text"]').first();
-        const $confirmInputParent = $confirmInput.parent().addClass('confirm-parent').append($passwordConfirmMessage);
-        const passwordStrengthBarClassesToRemove = [cssClasses.passwordWeak || '', cssClasses.passwordFair || '', cssClasses.passwordGood || '', cssClasses.passwordStrong || ''].join(' ').trim();
-        const confirmTextWrapperClassesToRemove = [cssClasses.passwordsMatch || '', cssClasses.passwordsNotMatch || ''].join(' ').trim();
-        const widgetClassesToRemove = [cssClasses.widgetInitial || '', cssClasses.passwordEmpty || '', cssClasses.passwordFilled || '', cssClasses.confirmEmpty || '', cssClasses.confirmFilled || ''].join(' ').trim();
+        const $passwordConfirmMessage = $(
+          Drupal.theme('passwordConfirmMessage', settings.password),
+        );
+
+        const $passwordMatchStatus = $passwordConfirmMessage
+          .find('[data-drupal-selector="password-match-status-text"]')
+          .first();
+
+        const $confirmInputParent = $confirmInput
+          .parent()
+          .addClass('confirm-parent')
+          .append($passwordConfirmMessage);
+
+        // List of classes to be removed from the strength bar on a state
+        // change.
+        const passwordStrengthBarClassesToRemove = [
+          cssClasses.passwordWeak || '',
+          cssClasses.passwordFair || '',
+          cssClasses.passwordGood || '',
+          cssClasses.passwordStrong || '',
+        ]
+          .join(' ')
+          .trim();
+
+        // List of classes to be removed from the text wrapper on a state
+        // change.
+        const confirmTextWrapperClassesToRemove = [
+          cssClasses.passwordsMatch || '',
+          cssClasses.passwordsNotMatch || '',
+        ]
+          .join(' ')
+          .trim();
+
+        // List of classes to be removed from the widget on a state change.
+        const widgetClassesToRemove = [
+          cssClasses.widgetInitial || '',
+          cssClasses.passwordEmpty || '',
+          cssClasses.passwordFilled || '',
+          cssClasses.confirmEmpty || '',
+          cssClasses.confirmFilled || '',
+        ]
+          .join(' ')
+          .trim();
+
         const password = {};
 
+        // If the password strength indicator is enabled, add its markup.
         if (settings.password.showStrengthIndicator) {
-          const $passwordStrength = $(Drupal.theme('passwordStrength', settings.password));
-          password.$strengthBar = $passwordStrength.find('[data-drupal-selector="password-strength-indicator"]').first();
-          password.$strengthTextWrapper = $passwordStrength.find('[data-drupal-selector="password-strength-text"]').first();
-          password.$suggestions = $(Drupal.theme('passwordSuggestions', settings.password, []));
+          const $passwordStrength = $(
+            Drupal.theme('passwordStrength', settings.password),
+          );
+          password.$strengthBar = $passwordStrength
+            .find('[data-drupal-selector="password-strength-indicator"]')
+            .first();
+          password.$strengthTextWrapper = $passwordStrength
+            .find('[data-drupal-selector="password-strength-text"]')
+            .first();
+          password.$suggestions = $(
+            Drupal.theme('passwordSuggestions', settings.password, []),
+          );
+
           password.$suggestions.hide();
           $mainInputParent.append($passwordStrength);
           $confirmInputParent.after(password.$suggestions);
         }
 
+        /**
+         * Adds classes to the widget indicating if the elements are filled.
+         */
         const addWidgetClasses = () => {
-          $passwordWidget.addClass($mainInput[0].value ? cssClasses.passwordFilled : cssClasses.passwordEmpty).addClass($confirmInput[0].value ? cssClasses.confirmFilled : cssClasses.confirmEmpty);
+          $passwordWidget
+            .addClass(
+              $mainInput[0].value
+                ? cssClasses.passwordFilled
+                : cssClasses.passwordEmpty,
+            )
+            .addClass(
+              $confirmInput[0].value
+                ? cssClasses.confirmFilled
+                : cssClasses.confirmEmpty,
+            );
         };
 
-        const passwordCheckMatch = confirmInputVal => {
+        /**
+         * Check that password and confirmation inputs match.
+         *
+         * @param {string} confirmInputVal
+         *   The value of the confirm input.
+         */
+        const passwordCheckMatch = (confirmInputVal) => {
           const passwordsAreMatching = $mainInput[0].value === confirmInputVal;
-          const confirmClass = passwordsAreMatching ? cssClasses.passwordsMatch : cssClasses.passwordsNotMatch;
-          const confirmMessage = passwordsAreMatching ? settings.password.confirmSuccess : settings.password.confirmFailure;
+          const confirmClass = passwordsAreMatching
+            ? cssClasses.passwordsMatch
+            : cssClasses.passwordsNotMatch;
+          const confirmMessage = passwordsAreMatching
+            ? settings.password.confirmSuccess
+            : settings.password.confirmFailure;
 
-          if (!$passwordMatchStatus.hasClass(confirmClass) || !$passwordMatchStatus.html() === confirmMessage) {
+          // Update the success message and set the class if needed.
+          if (
+            !$passwordMatchStatus.hasClass(confirmClass) ||
+            !$passwordMatchStatus.html() === confirmMessage
+          ) {
             if (confirmTextWrapperClassesToRemove) {
-              $passwordMatchStatus.removeClass(confirmTextWrapperClassesToRemove);
+              $passwordMatchStatus.removeClass(
+                confirmTextWrapperClassesToRemove,
+              );
             }
-
             $passwordMatchStatus.html(confirmMessage).addClass(confirmClass);
           }
         };
 
+        /**
+         * Checks the password strength.
+         */
         const passwordCheck = () => {
           if (settings.password.showStrengthIndicator) {
-            const result = Drupal.evaluatePasswordStrength($mainInput[0].value, settings.password);
-            const $currentPasswordSuggestions = $(Drupal.theme('passwordSuggestions', settings.password, result.messageTips));
+            // Evaluate the password strength.
+            const result = Drupal.evaluatePasswordStrength(
+              $mainInput[0].value,
+              settings.password,
+            );
+            const $currentPasswordSuggestions = $(
+              Drupal.theme(
+                'passwordSuggestions',
+                settings.password,
+                result.messageTips,
+              ),
+            );
 
-            if (password.$suggestions.html() !== $currentPasswordSuggestions.html()) {
+            // Update the suggestions for how to improve the password if needed.
+            if (
+              password.$suggestions.html() !==
+              $currentPasswordSuggestions.html()
+            ) {
               password.$suggestions.replaceWith($currentPasswordSuggestions);
-              password.$suggestions = $currentPasswordSuggestions.toggle(result.strength !== 100);
+              password.$suggestions = $currentPasswordSuggestions.toggle(
+                // Only show the description box if a weakness exists in the
+                // password.
+                result.strength !== 100,
+              );
             }
 
             if (passwordStrengthBarClassesToRemove) {
-              password.$strengthBar.removeClass(passwordStrengthBarClassesToRemove);
+              password.$strengthBar.removeClass(
+                passwordStrengthBarClassesToRemove,
+              );
             }
+            // Adjust the length of the strength indicator.
+            password.$strengthBar
+              .css('width', `${result.strength}%`)
+              .addClass(result.indicatorClass);
 
-            password.$strengthBar.css('width', `${result.strength}%`).addClass(result.indicatorClass);
+            // Update the strength indication text.
             password.$strengthTextWrapper.html(result.indicatorText);
           }
 
+          // Check the value in the confirm input and show results.
           if ($confirmInput[0].value) {
             passwordCheckMatch($confirmInput[0].value);
-            $passwordConfirmMessage.css({
-              visibility: 'visible'
-            });
+            $passwordConfirmMessage.css({ visibility: 'visible' });
           } else {
-            $passwordConfirmMessage.css({
-              visibility: 'hidden'
-            });
+            $passwordConfirmMessage.css({ visibility: 'hidden' });
           }
 
           if (widgetClassesToRemove) {
@@ -107,13 +247,27 @@
           addWidgetClasses();
         }
 
+        // Monitor input events.
         $mainInput.on('input', passwordCheck);
         $confirmInput.on('input', passwordCheck);
       });
-    }
-
+    },
   };
 
+  /**
+   * Evaluate the strength of a user's password.
+   *
+   * Returns the estimated strength and the relevant output message.
+   *
+   * @param {string} password
+   *   The password to evaluate.
+   * @param {object} passwordSettings
+   *   A password settings object containing the text to display and the CSS
+   *   classes for each strength level.
+   *
+   * @return {object}
+   *   An object containing strength, message, indicatorText and indicatorClass.
+   */
   Drupal.evaluatePasswordStrength = (password, passwordSettings) => {
     password = password.trim();
     let indicatorText;
@@ -121,38 +275,45 @@
     let weaknesses = 0;
     let strength = 100;
     let msg = [];
+
     const hasLowercase = /[a-z]/.test(password);
     const hasUppercase = /[A-Z]/.test(password);
     const hasNumbers = /[0-9]/.test(password);
     const hasPunctuation = /[^a-zA-Z0-9]/.test(password);
+
+    // If there is a username edit box on the page, compare password to that,
+    // otherwise use value from the database.
     const $usernameBox = $('input.username');
-    const username = $usernameBox.length > 0 ? $usernameBox[0].value : passwordSettings.username;
+    const username =
+      $usernameBox.length > 0
+        ? $usernameBox[0].value
+        : passwordSettings.username;
 
+    // Lose 5 points for every character less than 12, plus a 30 point penalty.
     if (password.length < 12) {
       msg.push(passwordSettings.tooShort);
       strength -= (12 - password.length) * 5 + 30;
     }
 
+    // Count weaknesses.
     if (!hasLowercase) {
       msg.push(passwordSettings.addLowerCase);
       weaknesses += 1;
     }
-
     if (!hasUppercase) {
       msg.push(passwordSettings.addUpperCase);
       weaknesses += 1;
     }
-
     if (!hasNumbers) {
       msg.push(passwordSettings.addNumbers);
       weaknesses += 1;
     }
-
     if (!hasPunctuation) {
       msg.push(passwordSettings.addPunctuation);
       weaknesses += 1;
     }
 
+    // Apply penalty for each weakness (balanced against length penalty).
     switch (weaknesses) {
       case 1:
         strength -= 12.5;
@@ -168,13 +329,17 @@
         break;
     }
 
+    // Check if password is the same as the username.
     if (password !== '' && password.toLowerCase() === username.toLowerCase()) {
       msg.push(passwordSettings.sameAsUsername);
+      // Passwords the same as username are always very weak.
       strength = 5;
     }
 
     const cssClasses = Drupal.user.password.css;
 
+    // Based on the strength, work out what text should be shown by the
+    // password strength meter.
     if (strength < 60) {
       indicatorText = passwordSettings.weak;
       indicatorClass = cssClasses.passwordWeak;
@@ -189,13 +354,17 @@
       indicatorClass = cssClasses.passwordStrong;
     }
 
+    // Assemble the final message while keeping the original message array.
     const messageTips = msg;
-    msg = `${passwordSettings.hasWeaknesses}<ul><li>${msg.join('</li><li>')}</li></ul>`;
+    msg = `${passwordSettings.hasWeaknesses}<ul><li>${msg.join(
+      '</li><li>',
+    )}</li></ul>`;
+
     return {
       strength,
       indicatorText,
       indicatorClass,
-      messageTips
+      messageTips,
     };
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/user/user.permissions.es6.js b/core/modules/user/user.permissions.es6.js
deleted file mode 100644
index ae22cbb5e3d9..000000000000
--- a/core/modules/user/user.permissions.es6.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * @file
- * User permission page behaviors.
- */
-
-(function ($, Drupal) {
-  /**
-   * Shows checked and disabled checkboxes for inherited permissions.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches functionality to the permissions table.
-   */
-  Drupal.behaviors.permissions = {
-    attach(context) {
-      once('permissions', 'table#permissions').forEach((table) => {
-        // On a site with many roles and permissions, this behavior initially
-        // has to perform thousands of DOM manipulations to inject checkboxes
-        // and hide them. By detaching the table from the DOM, all operations
-        // can be performed without triggering internal layout and re-rendering
-        // processes in the browser.
-        const $table = $(table);
-        let $ancestor;
-        let method;
-        if ($table.prev().length) {
-          $ancestor = $table.prev();
-          method = 'after';
-        } else {
-          $ancestor = $table.parent();
-          method = 'append';
-        }
-        $table.detach();
-
-        // Create dummy checkboxes. We use dummy checkboxes instead of reusing
-        // the existing checkboxes here because new checkboxes don't alter the
-        // submitted form. If we'd automatically check existing checkboxes, the
-        // permission table would be polluted with redundant entries. This is
-        // deliberate, but desirable when we automatically check them.
-        const $dummy = $(Drupal.theme('checkbox'))
-          .removeClass('form-checkbox')
-          .addClass('dummy-checkbox js-dummy-checkbox')
-          .attr('disabled', 'disabled')
-          .attr('checked', 'checked')
-          .attr(
-            'title',
-            Drupal.t(
-              'This permission is inherited from the authenticated user role.',
-            ),
-          )
-          .hide();
-
-        $table
-          .find('input[type="checkbox"]')
-          .not('.js-rid-anonymous, .js-rid-authenticated')
-          .addClass('real-checkbox js-real-checkbox')
-          .after($dummy);
-
-        // Initialize the authenticated user checkbox.
-        $table
-          .find('input[type=checkbox].js-rid-authenticated')
-          .on('click.permissions', this.toggle)
-          // .triggerHandler() cannot be used here, as it only affects the first
-          // element.
-          .each(this.toggle);
-
-        // Re-insert the table into the DOM.
-        $ancestor[method]($table);
-      });
-    },
-
-    /**
-     * Toggles all dummy checkboxes based on the checkboxes' state.
-     *
-     * If the "authenticated user" checkbox is checked, the checked and disabled
-     * checkboxes are shown, the real checkboxes otherwise.
-     */
-    toggle() {
-      const authCheckbox = this;
-      const $row = $(this).closest('tr');
-      // jQuery performs too many layout calculations for .hide() and .show(),
-      // leading to a major page rendering lag on sites with many roles and
-      // permissions. Therefore, we toggle visibility directly.
-      $row.find('.js-real-checkbox').each(function () {
-        this.style.display = authCheckbox.checked ? 'none' : '';
-      });
-      $row.find('.js-dummy-checkbox').each(function () {
-        this.style.display = authCheckbox.checked ? '' : 'none';
-      });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/user/user.permissions.js b/core/modules/user/user.permissions.js
index 0188fab28731..ae22cbb5e3d9 100644
--- a/core/modules/user/user.permissions.js
+++ b/core/modules/user/user.permissions.js
@@ -1,18 +1,28 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * User permission page behaviors.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Shows checked and disabled checkboxes for inherited permissions.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches functionality to the permissions table.
+   */
   Drupal.behaviors.permissions = {
     attach(context) {
-      once('permissions', 'table#permissions').forEach(table => {
+      once('permissions', 'table#permissions').forEach((table) => {
+        // On a site with many roles and permissions, this behavior initially
+        // has to perform thousands of DOM manipulations to inject checkboxes
+        // and hide them. By detaching the table from the DOM, all operations
+        // can be performed without triggering internal layout and re-rendering
+        // processes in the browser.
         const $table = $(table);
         let $ancestor;
         let method;
-
         if ($table.prev().length) {
           $ancestor = $table.prev();
           method = 'after';
@@ -20,25 +30,63 @@
           $ancestor = $table.parent();
           method = 'append';
         }
-
         $table.detach();
-        const $dummy = $(Drupal.theme('checkbox')).removeClass('form-checkbox').addClass('dummy-checkbox js-dummy-checkbox').attr('disabled', 'disabled').attr('checked', 'checked').attr('title', Drupal.t('This permission is inherited from the authenticated user role.')).hide();
-        $table.find('input[type="checkbox"]').not('.js-rid-anonymous, .js-rid-authenticated').addClass('real-checkbox js-real-checkbox').after($dummy);
-        $table.find('input[type=checkbox].js-rid-authenticated').on('click.permissions', this.toggle).each(this.toggle);
+
+        // Create dummy checkboxes. We use dummy checkboxes instead of reusing
+        // the existing checkboxes here because new checkboxes don't alter the
+        // submitted form. If we'd automatically check existing checkboxes, the
+        // permission table would be polluted with redundant entries. This is
+        // deliberate, but desirable when we automatically check them.
+        const $dummy = $(Drupal.theme('checkbox'))
+          .removeClass('form-checkbox')
+          .addClass('dummy-checkbox js-dummy-checkbox')
+          .attr('disabled', 'disabled')
+          .attr('checked', 'checked')
+          .attr(
+            'title',
+            Drupal.t(
+              'This permission is inherited from the authenticated user role.',
+            ),
+          )
+          .hide();
+
+        $table
+          .find('input[type="checkbox"]')
+          .not('.js-rid-anonymous, .js-rid-authenticated')
+          .addClass('real-checkbox js-real-checkbox')
+          .after($dummy);
+
+        // Initialize the authenticated user checkbox.
+        $table
+          .find('input[type=checkbox].js-rid-authenticated')
+          .on('click.permissions', this.toggle)
+          // .triggerHandler() cannot be used here, as it only affects the first
+          // element.
+          .each(this.toggle);
+
+        // Re-insert the table into the DOM.
         $ancestor[method]($table);
       });
     },
 
+    /**
+     * Toggles all dummy checkboxes based on the checkboxes' state.
+     *
+     * If the "authenticated user" checkbox is checked, the checked and disabled
+     * checkboxes are shown, the real checkboxes otherwise.
+     */
     toggle() {
       const authCheckbox = this;
       const $row = $(this).closest('tr');
+      // jQuery performs too many layout calculations for .hide() and .show(),
+      // leading to a major page rendering lag on sites with many roles and
+      // permissions. Therefore, we toggle visibility directly.
       $row.find('.js-real-checkbox').each(function () {
         this.style.display = authCheckbox.checked ? 'none' : '';
       });
       $row.find('.js-dummy-checkbox').each(function () {
         this.style.display = authCheckbox.checked ? '' : 'none';
       });
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/modules/user/user.theme.es6.js b/core/modules/user/user.theme.es6.js
deleted file mode 100644
index 7a12df970786..000000000000
--- a/core/modules/user/user.theme.es6.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * @file
- * Theme elements for user password forms.
- */
-
-((Drupal) => {
-  /**
-   * Constructs a password confirm message element.
-   *
-   * @param {object} passwordSettings
-   *   An object containing password related settings and translated text to
-   *   display.
-   * @param {string} passwordSettings.confirmTitle
-   *   The translated confirm description that labels the actual confirm text.
-   *
-   * @return {string}
-   *   Markup for the password confirm message.
-   */
-  Drupal.theme.passwordConfirmMessage = ({ confirmTitle }) => {
-    const confirmTextWrapper =
-      '<span data-drupal-selector="password-match-status-text"></span>';
-    return `<div aria-live="polite" aria-atomic="true" class="password-confirm-message" data-drupal-selector="password-confirm-message">${confirmTitle} ${confirmTextWrapper}</div>`;
-  };
-
-  /**
-   * Constructs a password strength message.
-   *
-   * @param {object} passwordSettings
-   *   An object containing password related settings and translated text to
-   *   display.
-   * @param {string} passwordSettings.strengthTitle
-   *   The title that precedes the strength text.
-   *
-   * @return {string}
-   *   Markup for password strength message.
-   */
-  Drupal.theme.passwordStrength = ({ strengthTitle }) => {
-    const strengthIndicator =
-      '<div class="password-strength__indicator" data-drupal-selector="password-strength-indicator"></div>';
-    const strengthText =
-      '<span class="password-strength__text" data-drupal-selector="password-strength-text"></span>';
-    return `
-      <div class="password-strength">
-        <div class="password-strength__meter" data-drupal-selector="password-strength-meter">${strengthIndicator}</div>
-        <div aria-live="polite" aria-atomic="true" class="password-strength__title">${strengthTitle} ${strengthText}</div>
-      </div>
-    `;
-  };
-
-  /**
-   * Constructs password suggestions tips.
-   *
-   * @param {object} passwordSettings
-   *   An object containing password related settings and translated text to
-   *   display.
-   * @param {string} passwordSettings.hasWeaknesses
-   *   The title that precedes tips.
-   * @param {Array.<string>} tips
-   *   Array containing the tips.
-   *
-   * @return {string}
-   *   Markup for password suggestions.
-   */
-  Drupal.theme.passwordSuggestions = ({ hasWeaknesses }, tips) =>
-    `<div class="password-suggestions">${
-      tips.length
-        ? `${hasWeaknesses}<ul><li>${tips.join('</li><li>')}</li></ul>`
-        : ''
-    }</div>`;
-})(Drupal);
diff --git a/core/modules/user/user.theme.js b/core/modules/user/user.theme.js
index 3bacd5b3218a..7a12df970786 100644
--- a/core/modules/user/user.theme.js
+++ b/core/modules/user/user.theme.js
@@ -1,25 +1,44 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Theme elements for user password forms.
+ */
 
-(Drupal => {
-  Drupal.theme.passwordConfirmMessage = _ref => {
-    let {
-      confirmTitle
-    } = _ref;
-    const confirmTextWrapper = '<span data-drupal-selector="password-match-status-text"></span>';
+((Drupal) => {
+  /**
+   * Constructs a password confirm message element.
+   *
+   * @param {object} passwordSettings
+   *   An object containing password related settings and translated text to
+   *   display.
+   * @param {string} passwordSettings.confirmTitle
+   *   The translated confirm description that labels the actual confirm text.
+   *
+   * @return {string}
+   *   Markup for the password confirm message.
+   */
+  Drupal.theme.passwordConfirmMessage = ({ confirmTitle }) => {
+    const confirmTextWrapper =
+      '<span data-drupal-selector="password-match-status-text"></span>';
     return `<div aria-live="polite" aria-atomic="true" class="password-confirm-message" data-drupal-selector="password-confirm-message">${confirmTitle} ${confirmTextWrapper}</div>`;
   };
 
-  Drupal.theme.passwordStrength = _ref2 => {
-    let {
-      strengthTitle
-    } = _ref2;
-    const strengthIndicator = '<div class="password-strength__indicator" data-drupal-selector="password-strength-indicator"></div>';
-    const strengthText = '<span class="password-strength__text" data-drupal-selector="password-strength-text"></span>';
+  /**
+   * Constructs a password strength message.
+   *
+   * @param {object} passwordSettings
+   *   An object containing password related settings and translated text to
+   *   display.
+   * @param {string} passwordSettings.strengthTitle
+   *   The title that precedes the strength text.
+   *
+   * @return {string}
+   *   Markup for password strength message.
+   */
+  Drupal.theme.passwordStrength = ({ strengthTitle }) => {
+    const strengthIndicator =
+      '<div class="password-strength__indicator" data-drupal-selector="password-strength-indicator"></div>';
+    const strengthText =
+      '<span class="password-strength__text" data-drupal-selector="password-strength-text"></span>';
     return `
       <div class="password-strength">
         <div class="password-strength__meter" data-drupal-selector="password-strength-meter">${strengthIndicator}</div>
@@ -28,10 +47,24 @@
     `;
   };
 
-  Drupal.theme.passwordSuggestions = (_ref3, tips) => {
-    let {
-      hasWeaknesses
-    } = _ref3;
-    return `<div class="password-suggestions">${tips.length ? `${hasWeaknesses}<ul><li>${tips.join('</li><li>')}</li></ul>` : ''}</div>`;
-  };
-})(Drupal);
\ No newline at end of file
+  /**
+   * Constructs password suggestions tips.
+   *
+   * @param {object} passwordSettings
+   *   An object containing password related settings and translated text to
+   *   display.
+   * @param {string} passwordSettings.hasWeaknesses
+   *   The title that precedes tips.
+   * @param {Array.<string>} tips
+   *   Array containing the tips.
+   *
+   * @return {string}
+   *   Markup for password suggestions.
+   */
+  Drupal.theme.passwordSuggestions = ({ hasWeaknesses }, tips) =>
+    `<div class="password-suggestions">${
+      tips.length
+        ? `${hasWeaknesses}<ul><li>${tips.join('</li><li>')}</li></ul>`
+        : ''
+    }</div>`;
+})(Drupal);
diff --git a/core/modules/views/js/ajax_view.es6.js b/core/modules/views/js/ajax_view.es6.js
deleted file mode 100644
index 9423bb1d6412..000000000000
--- a/core/modules/views/js/ajax_view.es6.js
+++ /dev/null
@@ -1,236 +0,0 @@
-/**
- * @file
- * Handles AJAX fetching of views, including filter submission and response.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Attaches the AJAX behavior to exposed filters forms and key View links.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches ajaxView functionality to relevant elements.
-   */
-  Drupal.behaviors.ViewsAjaxView = {};
-  Drupal.behaviors.ViewsAjaxView.attach = function (context, settings) {
-    if (settings && settings.views && settings.views.ajaxViews) {
-      const {
-        views: { ajaxViews },
-      } = settings;
-      Object.keys(ajaxViews || {}).forEach((i) => {
-        Drupal.views.instances[i] = new Drupal.views.ajaxView(ajaxViews[i]);
-      });
-    }
-  };
-  Drupal.behaviors.ViewsAjaxView.detach = (context, settings, trigger) => {
-    if (trigger === 'unload') {
-      if (settings && settings.views && settings.views.ajaxViews) {
-        const {
-          views: { ajaxViews },
-        } = settings;
-        Object.keys(ajaxViews || {}).forEach((i) => {
-          const selector = `.js-view-dom-id-${ajaxViews[i].view_dom_id}`;
-          if ($(selector, context).length) {
-            delete Drupal.views.instances[i];
-            delete settings.views.ajaxViews[i];
-          }
-        });
-      }
-    }
-  };
-
-  /**
-   * @namespace
-   */
-  Drupal.views = {};
-
-  /**
-   * @type {object.<string, Drupal.views.ajaxView>}
-   */
-  Drupal.views.instances = {};
-
-  /**
-   * JavaScript object for a certain view.
-   *
-   * @constructor
-   *
-   * @param {object} settings
-   *   Settings object for the ajax view.
-   * @param {string} settings.view_dom_id
-   *   The DOM id of the view.
-   */
-  Drupal.views.ajaxView = function (settings) {
-    const selector = `.js-view-dom-id-${settings.view_dom_id}`;
-    this.$view = $(selector);
-
-    // Retrieve the path to use for views' ajax.
-    let ajaxPath = drupalSettings.views.ajax_path;
-
-    // If there are multiple views this might've ended up showing up multiple
-    // times.
-    if (ajaxPath.constructor.toString().indexOf('Array') !== -1) {
-      ajaxPath = ajaxPath[0];
-    }
-
-    // Check if there are any GET parameters to send to views.
-    let queryString = window.location.search || '';
-    if (queryString !== '') {
-      // Remove the question mark and Drupal path component if any.
-      queryString = queryString
-        .slice(1)
-        .replace(/q=[^&]+&?|&?render=[^&]+/, '');
-      if (queryString !== '') {
-        // If there is a '?' in ajaxPath, clean url are on and & should be
-        // used to add parameters.
-        queryString = (/\?/.test(ajaxPath) ? '&' : '?') + queryString;
-      }
-    }
-
-    this.element_settings = {
-      url: ajaxPath + queryString,
-      submit: settings,
-      setClick: true,
-      event: 'click',
-      selector,
-      progress: { type: 'fullscreen' },
-    };
-
-    this.settings = settings;
-
-    // Add the ajax to exposed forms.
-    this.$exposed_form = $(
-      `form#views-exposed-form-${settings.view_name.replace(
-        /_/g,
-        '-',
-      )}-${settings.view_display_id.replace(/_/g, '-')}`,
-    );
-    once('exposed-form', this.$exposed_form).forEach(
-      $.proxy(this.attachExposedFormAjax, this),
-    );
-
-    // Add the ajax to pagers.
-    once(
-      'ajax-pager',
-      this.$view
-        // Don't attach to nested views. Doing so would attach multiple behaviors
-        // to a given element.
-        .filter($.proxy(this.filterNestedViews, this)),
-    ).forEach($.proxy(this.attachPagerAjax, this));
-
-    // Add a trigger to update this view specifically. In order to trigger a
-    // refresh use the following code.
-    //
-    // @code
-    // $('.view-name').trigger('RefreshView');
-    // @endcode
-    const selfSettings = $.extend({}, this.element_settings, {
-      event: 'RefreshView',
-      base: this.selector,
-      element: this.$view.get(0),
-    });
-    this.refreshViewAjax = Drupal.ajax(selfSettings);
-  };
-
-  /**
-   * @method
-   */
-  Drupal.views.ajaxView.prototype.attachExposedFormAjax = function () {
-    const that = this;
-    this.exposedFormAjax = [];
-    // Exclude the reset buttons so no AJAX behaviors are bound. Many things
-    // break during the form reset phase if using AJAX.
-    $(
-      'input[type=submit], button[type=submit], input[type=image]',
-      this.$exposed_form,
-    )
-      .not('[data-drupal-selector=edit-reset]')
-      .each(function (index) {
-        const selfSettings = $.extend({}, that.element_settings, {
-          base: $(this).attr('id'),
-          element: this,
-        });
-        that.exposedFormAjax[index] = Drupal.ajax(selfSettings);
-      });
-  };
-
-  /**
-   * @return {bool}
-   *   If there is at least one parent with a view class return false.
-   */
-  Drupal.views.ajaxView.prototype.filterNestedViews = function () {
-    // If there is at least one parent with a view class, this view
-    // is nested (e.g., an attachment). Bail.
-    return !this.$view.parents('.view').length;
-  };
-
-  /**
-   * Attach the ajax behavior to each link.
-   */
-  Drupal.views.ajaxView.prototype.attachPagerAjax = function () {
-    this.$view
-      .find(
-        'ul.js-pager__items > li > a, th.views-field a, .attachment .views-summary a',
-      )
-      .each($.proxy(this.attachPagerLinkAjax, this));
-  };
-
-  /**
-   * Attach the ajax behavior to a singe link.
-   *
-   * @param {string} [id]
-   *   The ID of the link.
-   * @param {HTMLElement} link
-   *   The link element.
-   */
-  Drupal.views.ajaxView.prototype.attachPagerLinkAjax = function (id, link) {
-    const $link = $(link);
-    const viewData = {};
-    const href = $link.attr('href');
-    // Construct an object using the settings defaults and then overriding
-    // with data specific to the link.
-    $.extend(
-      viewData,
-      this.settings,
-      Drupal.Views.parseQueryString(href),
-      // Extract argument data from the URL.
-      Drupal.Views.parseViewArgs(href, this.settings.view_base_path),
-    );
-
-    const selfSettings = $.extend({}, this.element_settings, {
-      submit: viewData,
-      base: false,
-      element: link,
-    });
-    this.pagerAjax = Drupal.ajax(selfSettings);
-  };
-
-  /**
-   * Views scroll to top ajax command.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   A {@link Drupal.ajax} object.
-   * @param {object} response
-   *   Ajax response.
-   * @param {string} response.selector
-   *   Selector to use.
-   */
-  Drupal.AjaxCommands.prototype.viewsScrollTop = function (ajax, response) {
-    // Scroll to the top of the view. This will allow users
-    // to browse newly loaded content after e.g. clicking a pager
-    // link.
-    const offset = $(response.selector).offset();
-    // We can't guarantee that the scrollable object should be
-    // the body, as the view could be embedded in something
-    // more complex such as a modal popup. Recurse up the DOM
-    // and scroll the first element that has a non-zero top.
-    let scrollTarget = response.selector;
-    while ($(scrollTarget).scrollTop() === 0 && $(scrollTarget).parent()) {
-      scrollTarget = $(scrollTarget).parent();
-    }
-    // Only scroll upward.
-    if (offset.top - 10 < $(scrollTarget).scrollTop()) {
-      $(scrollTarget).animate({ scrollTop: offset.top - 10 }, 500);
-    }
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/views/js/ajax_view.js b/core/modules/views/js/ajax_view.js
index 6589f202459e..9423bb1d6412 100644
--- a/core/modules/views/js/ajax_view.js
+++ b/core/modules/views/js/ajax_view.js
@@ -1,37 +1,36 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Handles AJAX fetching of views, including filter submission and response.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * Attaches the AJAX behavior to exposed filters forms and key View links.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches ajaxView functionality to relevant elements.
+   */
   Drupal.behaviors.ViewsAjaxView = {};
-
   Drupal.behaviors.ViewsAjaxView.attach = function (context, settings) {
     if (settings && settings.views && settings.views.ajaxViews) {
       const {
-        views: {
-          ajaxViews
-        }
+        views: { ajaxViews },
       } = settings;
-      Object.keys(ajaxViews || {}).forEach(i => {
+      Object.keys(ajaxViews || {}).forEach((i) => {
         Drupal.views.instances[i] = new Drupal.views.ajaxView(ajaxViews[i]);
       });
     }
   };
-
   Drupal.behaviors.ViewsAjaxView.detach = (context, settings, trigger) => {
     if (trigger === 'unload') {
       if (settings && settings.views && settings.views.ajaxViews) {
         const {
-          views: {
-            ajaxViews
-          }
+          views: { ajaxViews },
         } = settings;
-        Object.keys(ajaxViews || {}).forEach(i => {
+        Object.keys(ajaxViews || {}).forEach((i) => {
           const selector = `.js-view-dom-id-${ajaxViews[i].view_dom_id}`;
-
           if ($(selector, context).length) {
             delete Drupal.views.instances[i];
             delete settings.views.ajaxViews[i];
@@ -41,24 +40,49 @@
     }
   };
 
+  /**
+   * @namespace
+   */
   Drupal.views = {};
+
+  /**
+   * @type {object.<string, Drupal.views.ajaxView>}
+   */
   Drupal.views.instances = {};
 
+  /**
+   * JavaScript object for a certain view.
+   *
+   * @constructor
+   *
+   * @param {object} settings
+   *   Settings object for the ajax view.
+   * @param {string} settings.view_dom_id
+   *   The DOM id of the view.
+   */
   Drupal.views.ajaxView = function (settings) {
     const selector = `.js-view-dom-id-${settings.view_dom_id}`;
     this.$view = $(selector);
+
+    // Retrieve the path to use for views' ajax.
     let ajaxPath = drupalSettings.views.ajax_path;
 
+    // If there are multiple views this might've ended up showing up multiple
+    // times.
     if (ajaxPath.constructor.toString().indexOf('Array') !== -1) {
       ajaxPath = ajaxPath[0];
     }
 
+    // Check if there are any GET parameters to send to views.
     let queryString = window.location.search || '';
-
     if (queryString !== '') {
-      queryString = queryString.slice(1).replace(/q=[^&]+&?|&?render=[^&]+/, '');
-
+      // Remove the question mark and Drupal path component if any.
+      queryString = queryString
+        .slice(1)
+        .replace(/q=[^&]+&?|&?render=[^&]+/, '');
       if (queryString !== '') {
+        // If there is a '?' in ajaxPath, clean url are on and & should be
+        // used to add parameters.
         queryString = (/\?/.test(ajaxPath) ? '&' : '?') + queryString;
       }
     }
@@ -69,67 +93,144 @@
       setClick: true,
       event: 'click',
       selector,
-      progress: {
-        type: 'fullscreen'
-      }
+      progress: { type: 'fullscreen' },
     };
+
     this.settings = settings;
-    this.$exposed_form = $(`form#views-exposed-form-${settings.view_name.replace(/_/g, '-')}-${settings.view_display_id.replace(/_/g, '-')}`);
-    once('exposed-form', this.$exposed_form).forEach($.proxy(this.attachExposedFormAjax, this));
-    once('ajax-pager', this.$view.filter($.proxy(this.filterNestedViews, this))).forEach($.proxy(this.attachPagerAjax, this));
+
+    // Add the ajax to exposed forms.
+    this.$exposed_form = $(
+      `form#views-exposed-form-${settings.view_name.replace(
+        /_/g,
+        '-',
+      )}-${settings.view_display_id.replace(/_/g, '-')}`,
+    );
+    once('exposed-form', this.$exposed_form).forEach(
+      $.proxy(this.attachExposedFormAjax, this),
+    );
+
+    // Add the ajax to pagers.
+    once(
+      'ajax-pager',
+      this.$view
+        // Don't attach to nested views. Doing so would attach multiple behaviors
+        // to a given element.
+        .filter($.proxy(this.filterNestedViews, this)),
+    ).forEach($.proxy(this.attachPagerAjax, this));
+
+    // Add a trigger to update this view specifically. In order to trigger a
+    // refresh use the following code.
+    //
+    // @code
+    // $('.view-name').trigger('RefreshView');
+    // @endcode
     const selfSettings = $.extend({}, this.element_settings, {
       event: 'RefreshView',
       base: this.selector,
-      element: this.$view.get(0)
+      element: this.$view.get(0),
     });
     this.refreshViewAjax = Drupal.ajax(selfSettings);
   };
 
+  /**
+   * @method
+   */
   Drupal.views.ajaxView.prototype.attachExposedFormAjax = function () {
     const that = this;
     this.exposedFormAjax = [];
-    $('input[type=submit], button[type=submit], input[type=image]', this.$exposed_form).not('[data-drupal-selector=edit-reset]').each(function (index) {
-      const selfSettings = $.extend({}, that.element_settings, {
-        base: $(this).attr('id'),
-        element: this
+    // Exclude the reset buttons so no AJAX behaviors are bound. Many things
+    // break during the form reset phase if using AJAX.
+    $(
+      'input[type=submit], button[type=submit], input[type=image]',
+      this.$exposed_form,
+    )
+      .not('[data-drupal-selector=edit-reset]')
+      .each(function (index) {
+        const selfSettings = $.extend({}, that.element_settings, {
+          base: $(this).attr('id'),
+          element: this,
+        });
+        that.exposedFormAjax[index] = Drupal.ajax(selfSettings);
       });
-      that.exposedFormAjax[index] = Drupal.ajax(selfSettings);
-    });
   };
 
+  /**
+   * @return {bool}
+   *   If there is at least one parent with a view class return false.
+   */
   Drupal.views.ajaxView.prototype.filterNestedViews = function () {
+    // If there is at least one parent with a view class, this view
+    // is nested (e.g., an attachment). Bail.
     return !this.$view.parents('.view').length;
   };
 
+  /**
+   * Attach the ajax behavior to each link.
+   */
   Drupal.views.ajaxView.prototype.attachPagerAjax = function () {
-    this.$view.find('ul.js-pager__items > li > a, th.views-field a, .attachment .views-summary a').each($.proxy(this.attachPagerLinkAjax, this));
+    this.$view
+      .find(
+        'ul.js-pager__items > li > a, th.views-field a, .attachment .views-summary a',
+      )
+      .each($.proxy(this.attachPagerLinkAjax, this));
   };
 
+  /**
+   * Attach the ajax behavior to a singe link.
+   *
+   * @param {string} [id]
+   *   The ID of the link.
+   * @param {HTMLElement} link
+   *   The link element.
+   */
   Drupal.views.ajaxView.prototype.attachPagerLinkAjax = function (id, link) {
     const $link = $(link);
     const viewData = {};
     const href = $link.attr('href');
-    $.extend(viewData, this.settings, Drupal.Views.parseQueryString(href), Drupal.Views.parseViewArgs(href, this.settings.view_base_path));
+    // Construct an object using the settings defaults and then overriding
+    // with data specific to the link.
+    $.extend(
+      viewData,
+      this.settings,
+      Drupal.Views.parseQueryString(href),
+      // Extract argument data from the URL.
+      Drupal.Views.parseViewArgs(href, this.settings.view_base_path),
+    );
+
     const selfSettings = $.extend({}, this.element_settings, {
       submit: viewData,
       base: false,
-      element: link
+      element: link,
     });
     this.pagerAjax = Drupal.ajax(selfSettings);
   };
 
+  /**
+   * Views scroll to top ajax command.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   A {@link Drupal.ajax} object.
+   * @param {object} response
+   *   Ajax response.
+   * @param {string} response.selector
+   *   Selector to use.
+   */
   Drupal.AjaxCommands.prototype.viewsScrollTop = function (ajax, response) {
+    // Scroll to the top of the view. This will allow users
+    // to browse newly loaded content after e.g. clicking a pager
+    // link.
     const offset = $(response.selector).offset();
+    // We can't guarantee that the scrollable object should be
+    // the body, as the view could be embedded in something
+    // more complex such as a modal popup. Recurse up the DOM
+    // and scroll the first element that has a non-zero top.
     let scrollTarget = response.selector;
-
     while ($(scrollTarget).scrollTop() === 0 && $(scrollTarget).parent()) {
       scrollTarget = $(scrollTarget).parent();
     }
-
+    // Only scroll upward.
     if (offset.top - 10 < $(scrollTarget).scrollTop()) {
-      $(scrollTarget).animate({
-        scrollTop: offset.top - 10
-      }, 500);
+      $(scrollTarget).animate({ scrollTop: offset.top - 10 }, 500);
     }
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/views/js/base.es6.js b/core/modules/views/js/base.es6.js
deleted file mode 100644
index 5838e64b3fe0..000000000000
--- a/core/modules/views/js/base.es6.js
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * @file
- * Some basic behaviors and utility functions for Views.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * @namespace
-   */
-  Drupal.Views = {};
-
-  /**
-   * Helper function to parse a querystring.
-   *
-   * @param {string} query
-   *   The querystring to parse.
-   *
-   * @return {object}
-   *   A map of query parameters.
-   */
-  Drupal.Views.parseQueryString = function (query) {
-    const args = {};
-    const pos = query.indexOf('?');
-    if (pos !== -1) {
-      query = query.substring(pos + 1);
-    }
-    let pair;
-    const pairs = query.split('&');
-    for (let i = 0; i < pairs.length; i++) {
-      pair = pairs[i].split('=');
-      // Ignore the 'q' path argument, if present.
-      if (pair[0] !== 'q' && pair[1]) {
-        args[decodeURIComponent(pair[0].replace(/\+/g, ' '))] =
-          decodeURIComponent(pair[1].replace(/\+/g, ' '));
-      }
-    }
-    return args;
-  };
-
-  /**
-   * Helper function to return a view's arguments based on a path.
-   *
-   * @param {string} href
-   *   The href to check.
-   * @param {string} viewPath
-   *   The views path to check.
-   *
-   * @return {object}
-   *   An object containing `view_args` and `view_path`.
-   */
-  Drupal.Views.parseViewArgs = function (href, viewPath) {
-    const returnObj = {};
-    const path = Drupal.Views.getPath(href);
-    // Get viewPath url without baseUrl portion.
-    const viewHref = Drupal.url(viewPath).substring(
-      drupalSettings.path.baseUrl.length,
-    );
-    // Ensure we have a correct path.
-    if (viewHref && path.substring(0, viewHref.length + 1) === `${viewHref}/`) {
-      returnObj.view_args = decodeURIComponent(
-        path.substring(viewHref.length + 1, path.length),
-      );
-      returnObj.view_path = path;
-    }
-    return returnObj;
-  };
-
-  /**
-   * Strip off the protocol plus domain from an href.
-   *
-   * @param {string} href
-   *   The href to strip.
-   *
-   * @return {string}
-   *   The href without the protocol and domain.
-   */
-  Drupal.Views.pathPortion = function (href) {
-    // Remove e.g. http://example.com if present.
-    const protocol = window.location.protocol;
-    if (href.substring(0, protocol.length) === protocol) {
-      // 2 is the length of the '//' that normally follows the protocol.
-      href = href.substring(href.indexOf('/', protocol.length + 2));
-    }
-    return href;
-  };
-
-  /**
-   * Return the Drupal path portion of an href.
-   *
-   * @param {string} href
-   *   The href to check.
-   *
-   * @return {string}
-   *   An internal path.
-   */
-  Drupal.Views.getPath = function (href) {
-    href = Drupal.Views.pathPortion(href);
-    href = href.substring(drupalSettings.path.baseUrl.length, href.length);
-    // 3 is the length of the '?q=' added to the url without clean urls.
-    if (href.substring(0, 3) === '?q=') {
-      href = href.substring(3, href.length);
-    }
-    const chars = ['#', '?', '&'];
-    for (let i = 0; i < chars.length; i++) {
-      if (href.indexOf(chars[i]) > -1) {
-        href = href.substr(0, href.indexOf(chars[i]));
-      }
-    }
-    return href;
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/views/js/base.js b/core/modules/views/js/base.js
index 7a4076be62fc..5838e64b3fe0 100644
--- a/core/modules/views/js/base.js
+++ b/core/modules/views/js/base.js
@@ -1,74 +1,111 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Some basic behaviors and utility functions for Views.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * @namespace
+   */
   Drupal.Views = {};
 
+  /**
+   * Helper function to parse a querystring.
+   *
+   * @param {string} query
+   *   The querystring to parse.
+   *
+   * @return {object}
+   *   A map of query parameters.
+   */
   Drupal.Views.parseQueryString = function (query) {
     const args = {};
     const pos = query.indexOf('?');
-
     if (pos !== -1) {
       query = query.substring(pos + 1);
     }
-
     let pair;
     const pairs = query.split('&');
-
     for (let i = 0; i < pairs.length; i++) {
       pair = pairs[i].split('=');
-
+      // Ignore the 'q' path argument, if present.
       if (pair[0] !== 'q' && pair[1]) {
-        args[decodeURIComponent(pair[0].replace(/\+/g, ' '))] = decodeURIComponent(pair[1].replace(/\+/g, ' '));
+        args[decodeURIComponent(pair[0].replace(/\+/g, ' '))] =
+          decodeURIComponent(pair[1].replace(/\+/g, ' '));
       }
     }
-
     return args;
   };
 
+  /**
+   * Helper function to return a view's arguments based on a path.
+   *
+   * @param {string} href
+   *   The href to check.
+   * @param {string} viewPath
+   *   The views path to check.
+   *
+   * @return {object}
+   *   An object containing `view_args` and `view_path`.
+   */
   Drupal.Views.parseViewArgs = function (href, viewPath) {
     const returnObj = {};
     const path = Drupal.Views.getPath(href);
-    const viewHref = Drupal.url(viewPath).substring(drupalSettings.path.baseUrl.length);
-
+    // Get viewPath url without baseUrl portion.
+    const viewHref = Drupal.url(viewPath).substring(
+      drupalSettings.path.baseUrl.length,
+    );
+    // Ensure we have a correct path.
     if (viewHref && path.substring(0, viewHref.length + 1) === `${viewHref}/`) {
-      returnObj.view_args = decodeURIComponent(path.substring(viewHref.length + 1, path.length));
+      returnObj.view_args = decodeURIComponent(
+        path.substring(viewHref.length + 1, path.length),
+      );
       returnObj.view_path = path;
     }
-
     return returnObj;
   };
 
+  /**
+   * Strip off the protocol plus domain from an href.
+   *
+   * @param {string} href
+   *   The href to strip.
+   *
+   * @return {string}
+   *   The href without the protocol and domain.
+   */
   Drupal.Views.pathPortion = function (href) {
+    // Remove e.g. http://example.com if present.
     const protocol = window.location.protocol;
-
     if (href.substring(0, protocol.length) === protocol) {
+      // 2 is the length of the '//' that normally follows the protocol.
       href = href.substring(href.indexOf('/', protocol.length + 2));
     }
-
     return href;
   };
 
+  /**
+   * Return the Drupal path portion of an href.
+   *
+   * @param {string} href
+   *   The href to check.
+   *
+   * @return {string}
+   *   An internal path.
+   */
   Drupal.Views.getPath = function (href) {
     href = Drupal.Views.pathPortion(href);
     href = href.substring(drupalSettings.path.baseUrl.length, href.length);
-
+    // 3 is the length of the '?q=' added to the url without clean urls.
     if (href.substring(0, 3) === '?q=') {
       href = href.substring(3, href.length);
     }
-
     const chars = ['#', '?', '&'];
-
     for (let i = 0; i < chars.length; i++) {
       if (href.indexOf(chars[i]) > -1) {
         href = href.substr(0, href.indexOf(chars[i]));
       }
     }
-
     return href;
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/views/tests/modules/views_test_data/views_cache.test.es6.js b/core/modules/views/tests/modules/views_test_data/views_cache.test.es6.js
deleted file mode 100644
index 4089267f9a5c..000000000000
--- a/core/modules/views/tests/modules/views_test_data/views_cache.test.es6.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * @file
- * Just a placeholder file for the test.
- *
- * @see ViewsCacheTest::testHeaderStorage
- *
- * @ignore
- */
diff --git a/core/modules/views/tests/modules/views_test_data/views_cache.test.js b/core/modules/views/tests/modules/views_test_data/views_cache.test.js
index 9d11a7c1c32d..4089267f9a5c 100644
--- a/core/modules/views/tests/modules/views_test_data/views_cache.test.js
+++ b/core/modules/views/tests/modules/views_test_data/views_cache.test.js
@@ -1,6 +1,8 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
\ No newline at end of file
+ * @file
+ * Just a placeholder file for the test.
+ *
+ * @see ViewsCacheTest::testHeaderStorage
+ *
+ * @ignore
+ */
diff --git a/core/modules/views_ui/js/ajax.es6.js b/core/modules/views_ui/js/ajax.es6.js
deleted file mode 100644
index 9448f5132913..000000000000
--- a/core/modules/views_ui/js/ajax.es6.js
+++ /dev/null
@@ -1,293 +0,0 @@
-/**
- * @file
- * Handles AJAX submission and response in Views UI.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * Ajax command for highlighting elements.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   An Ajax object.
-   * @param {object} response
-   *   The Ajax response.
-   * @param {string} response.selector
-   *   The selector in question.
-   * @param {number} [status]
-   *   The HTTP status code.
-   */
-  Drupal.AjaxCommands.prototype.viewsHighlight = function (
-    ajax,
-    response,
-    status,
-  ) {
-    $('.hilited').removeClass('hilited');
-    $(response.selector).addClass('hilited');
-  };
-
-  /**
-   * Ajax command to set the form submit action in the views modal edit form.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   An Ajax object.
-   * @param {object} response
-   *   The Ajax response. Contains .url
-   * @param {string} [status]
-   *   The XHR status code?
-   */
-  Drupal.AjaxCommands.prototype.viewsSetForm = function (
-    ajax,
-    response,
-    status,
-  ) {
-    const $form = $('.js-views-ui-dialog form');
-    // Identify the button that was clicked so that .ajaxSubmit() can use it.
-    // We need to do this for both .click() and .mousedown() since JavaScript
-    // code might trigger either behavior.
-    const $submitButtons = $(
-      once(
-        'views-ajax-submit',
-        $form.find('input[type=submit].js-form-submit, button.js-form-submit'),
-      ),
-    );
-    $submitButtons.on('click mousedown', function () {
-      this.form.clk = this;
-    });
-    once('views-ajax-submit', $form).forEach((form) => {
-      const $form = $(form);
-      const elementSettings = {
-        url: response.url,
-        event: 'submit',
-        base: $form.attr('id'),
-        element: form,
-      };
-      const ajaxForm = Drupal.ajax(elementSettings);
-      ajaxForm.$form = $form;
-    });
-  };
-
-  /**
-   * Ajax command to show certain buttons in the views edit form.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   An Ajax object.
-   * @param {object} response
-   *   The Ajax response.
-   * @param {bool} response.changed
-   *   Whether the state changed for the buttons or not.
-   * @param {number} [status]
-   *   The HTTP status code.
-   */
-  Drupal.AjaxCommands.prototype.viewsShowButtons = function (
-    ajax,
-    response,
-    status,
-  ) {
-    $('div.views-edit-view div.form-actions').removeClass('js-hide');
-    if (response.changed) {
-      $('div.views-edit-view div.view-changed.messages').removeClass('js-hide');
-    }
-  };
-
-  /**
-   * Ajax command for triggering preview.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   An Ajax object.
-   * @param {object} [response]
-   *   The Ajax response.
-   * @param {number} [status]
-   *   The HTTP status code.
-   */
-  Drupal.AjaxCommands.prototype.viewsTriggerPreview = function (
-    ajax,
-    response,
-    status,
-  ) {
-    if ($('input#edit-displays-live-preview').is(':checked')) {
-      $('#preview-submit').trigger('click');
-    }
-  };
-
-  /**
-   * Ajax command to replace the title of a page.
-   *
-   * @param {Drupal.Ajax} [ajax]
-   *   An Ajax object.
-   * @param {object} response
-   *   The Ajax response.
-   * @param {string} response.siteName
-   *   The site name.
-   * @param {string} response.title
-   *   The new page title.
-   * @param {number} [status]
-   *   The HTTP status code.
-   */
-  Drupal.AjaxCommands.prototype.viewsReplaceTitle = function (
-    ajax,
-    response,
-    status,
-  ) {
-    const doc = document;
-    // For the <title> element, make a best-effort attempt to replace the page
-    // title and leave the site name alone. If the theme doesn't use the site
-    // name in the <title> element, this will fail.
-    const oldTitle = doc.title;
-    // Escape the site name, in case it has special characters in it, so we can
-    // use it in our regex.
-    const escapedSiteName = response.siteName.replace(
-      /[-[\]{}()*+?.,\\^$|#\s]/g,
-      '\\$&',
-    );
-    const re = new RegExp(`.+ (.) ${escapedSiteName}`);
-    doc.title = oldTitle.replace(
-      re,
-      `${response.title} $1 ${response.siteName}`,
-    );
-    document.querySelectorAll('h1.page-title').forEach((item) => {
-      item.textContent = response.title;
-    });
-  };
-
-  /**
-   * Get rid of irritating tabledrag messages.
-   *
-   * @return {Array}
-   *   An array of messages. Always empty array, to get rid of the messages.
-   */
-  Drupal.theme.tableDragChangedWarning = function () {
-    return [];
-  };
-
-  /**
-   * Trigger preview when the "live preview" checkbox is checked.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to trigger live preview if the live preview option is
-   *   checked.
-   */
-  Drupal.behaviors.livePreview = {
-    attach(context) {
-      $(once('views-ajax', 'input#edit-displays-live-preview', context)).on(
-        'click',
-        function () {
-          if ($(this).is(':checked')) {
-            $('#preview-submit').trigger('click');
-          }
-        },
-      );
-    },
-  };
-
-  /**
-   * Sync preview display.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to sync the preview display when needed.
-   */
-  Drupal.behaviors.syncPreviewDisplay = {
-    attach(context) {
-      $(once('views-ajax', '#views-tabset a')).on('click', function () {
-        const href = $(this).attr('href');
-        // Cut of #views-tabset.
-        const displayId = href.substr(11);
-        const viewsPreviewId = document.querySelector(
-          '#views-live-preview #preview-display-id',
-        );
-        if (viewsPreviewId) {
-          // Set the form element if it is present.
-          viewsPreviewId.value = displayId;
-        }
-      });
-    },
-  };
-
-  /**
-   * Ajax behaviors for the views_ui module.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches ajax behaviors to the elements with the classes in question.
-   */
-  Drupal.behaviors.viewsAjax = {
-    collapseReplaced: false,
-    attach(context, settings) {
-      const baseElementSettings = {
-        event: 'click',
-        progress: { type: 'fullscreen' },
-      };
-      // Bind AJAX behaviors to all items showing the class.
-      once('views-ajax', 'a.views-ajax-link', context).forEach((link) => {
-        const $link = $(link);
-        const elementSettings = baseElementSettings;
-        elementSettings.base = $link.attr('id');
-        elementSettings.element = link;
-        // Set the URL to go to the anchor.
-        if ($link.attr('href')) {
-          elementSettings.url = $link.attr('href');
-        }
-        Drupal.ajax(elementSettings);
-      });
-
-      once('views-ajax', 'div#views-live-preview a').forEach((link) => {
-        const $link = $(link);
-        // We don't bind to links without a URL.
-        if (!$link.attr('href')) {
-          return true;
-        }
-
-        const elementSettings = baseElementSettings;
-        // Set the URL to go to the anchor.
-        elementSettings.url = $link.attr('href');
-        if (
-          Drupal.Views.getPath(elementSettings.url).substring(0, 21) !==
-          'admin/structure/views'
-        ) {
-          return true;
-        }
-
-        elementSettings.wrapper = 'views-preview-wrapper';
-        elementSettings.method = 'replaceWith';
-        elementSettings.base = link.id;
-        elementSettings.element = link;
-        Drupal.ajax(elementSettings);
-      });
-
-      // Within a live preview, make exposed widget form buttons re-trigger the
-      // Preview button.
-      // @todo Revisit this after fixing Views UI to display a Preview outside
-      //   of the main Edit form.
-      once('views-ajax', 'div#views-live-preview input[type=submit]').forEach(
-        (submit) => {
-          const $submit = $(submit);
-          $submit.on('click', function () {
-            this.form.clk = this;
-            return true;
-          });
-          const elementSettings = baseElementSettings;
-          // Set the URL to go to the anchor.
-          elementSettings.url = $(submit.form).attr('action');
-          if (
-            Drupal.Views.getPath(elementSettings.url).substring(0, 21) !==
-            'admin/structure/views'
-          ) {
-            return true;
-          }
-
-          elementSettings.wrapper = 'views-preview-wrapper';
-          elementSettings.method = 'replaceWith';
-          elementSettings.event = 'click';
-          elementSettings.base = submit.id;
-          elementSettings.element = submit;
-
-          Drupal.ajax(elementSettings);
-        },
-      );
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/views_ui/js/ajax.js b/core/modules/views_ui/js/ajax.js
index 265684a5eed8..9448f5132913 100644
--- a/core/modules/views_ui/js/ajax.js
+++ b/core/modules/views_ui/js/ajax.js
@@ -1,121 +1,253 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Handles AJAX submission and response in Views UI.
+ */
 
 (function ($, Drupal, drupalSettings) {
-  Drupal.AjaxCommands.prototype.viewsHighlight = function (ajax, response, status) {
+  /**
+   * Ajax command for highlighting elements.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   An Ajax object.
+   * @param {object} response
+   *   The Ajax response.
+   * @param {string} response.selector
+   *   The selector in question.
+   * @param {number} [status]
+   *   The HTTP status code.
+   */
+  Drupal.AjaxCommands.prototype.viewsHighlight = function (
+    ajax,
+    response,
+    status,
+  ) {
     $('.hilited').removeClass('hilited');
     $(response.selector).addClass('hilited');
   };
 
-  Drupal.AjaxCommands.prototype.viewsSetForm = function (ajax, response, status) {
+  /**
+   * Ajax command to set the form submit action in the views modal edit form.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   An Ajax object.
+   * @param {object} response
+   *   The Ajax response. Contains .url
+   * @param {string} [status]
+   *   The XHR status code?
+   */
+  Drupal.AjaxCommands.prototype.viewsSetForm = function (
+    ajax,
+    response,
+    status,
+  ) {
     const $form = $('.js-views-ui-dialog form');
-    const $submitButtons = $(once('views-ajax-submit', $form.find('input[type=submit].js-form-submit, button.js-form-submit')));
+    // Identify the button that was clicked so that .ajaxSubmit() can use it.
+    // We need to do this for both .click() and .mousedown() since JavaScript
+    // code might trigger either behavior.
+    const $submitButtons = $(
+      once(
+        'views-ajax-submit',
+        $form.find('input[type=submit].js-form-submit, button.js-form-submit'),
+      ),
+    );
     $submitButtons.on('click mousedown', function () {
       this.form.clk = this;
     });
-    once('views-ajax-submit', $form).forEach(form => {
+    once('views-ajax-submit', $form).forEach((form) => {
       const $form = $(form);
       const elementSettings = {
         url: response.url,
         event: 'submit',
         base: $form.attr('id'),
-        element: form
+        element: form,
       };
       const ajaxForm = Drupal.ajax(elementSettings);
       ajaxForm.$form = $form;
     });
   };
 
-  Drupal.AjaxCommands.prototype.viewsShowButtons = function (ajax, response, status) {
+  /**
+   * Ajax command to show certain buttons in the views edit form.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   An Ajax object.
+   * @param {object} response
+   *   The Ajax response.
+   * @param {bool} response.changed
+   *   Whether the state changed for the buttons or not.
+   * @param {number} [status]
+   *   The HTTP status code.
+   */
+  Drupal.AjaxCommands.prototype.viewsShowButtons = function (
+    ajax,
+    response,
+    status,
+  ) {
     $('div.views-edit-view div.form-actions').removeClass('js-hide');
-
     if (response.changed) {
       $('div.views-edit-view div.view-changed.messages').removeClass('js-hide');
     }
   };
 
-  Drupal.AjaxCommands.prototype.viewsTriggerPreview = function (ajax, response, status) {
+  /**
+   * Ajax command for triggering preview.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   An Ajax object.
+   * @param {object} [response]
+   *   The Ajax response.
+   * @param {number} [status]
+   *   The HTTP status code.
+   */
+  Drupal.AjaxCommands.prototype.viewsTriggerPreview = function (
+    ajax,
+    response,
+    status,
+  ) {
     if ($('input#edit-displays-live-preview').is(':checked')) {
       $('#preview-submit').trigger('click');
     }
   };
 
-  Drupal.AjaxCommands.prototype.viewsReplaceTitle = function (ajax, response, status) {
+  /**
+   * Ajax command to replace the title of a page.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   An Ajax object.
+   * @param {object} response
+   *   The Ajax response.
+   * @param {string} response.siteName
+   *   The site name.
+   * @param {string} response.title
+   *   The new page title.
+   * @param {number} [status]
+   *   The HTTP status code.
+   */
+  Drupal.AjaxCommands.prototype.viewsReplaceTitle = function (
+    ajax,
+    response,
+    status,
+  ) {
     const doc = document;
+    // For the <title> element, make a best-effort attempt to replace the page
+    // title and leave the site name alone. If the theme doesn't use the site
+    // name in the <title> element, this will fail.
     const oldTitle = doc.title;
-    const escapedSiteName = response.siteName.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
+    // Escape the site name, in case it has special characters in it, so we can
+    // use it in our regex.
+    const escapedSiteName = response.siteName.replace(
+      /[-[\]{}()*+?.,\\^$|#\s]/g,
+      '\\$&',
+    );
     const re = new RegExp(`.+ (.) ${escapedSiteName}`);
-    doc.title = oldTitle.replace(re, `${response.title} $1 ${response.siteName}`);
-    document.querySelectorAll('h1.page-title').forEach(item => {
+    doc.title = oldTitle.replace(
+      re,
+      `${response.title} $1 ${response.siteName}`,
+    );
+    document.querySelectorAll('h1.page-title').forEach((item) => {
       item.textContent = response.title;
     });
   };
 
+  /**
+   * Get rid of irritating tabledrag messages.
+   *
+   * @return {Array}
+   *   An array of messages. Always empty array, to get rid of the messages.
+   */
   Drupal.theme.tableDragChangedWarning = function () {
     return [];
   };
 
+  /**
+   * Trigger preview when the "live preview" checkbox is checked.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to trigger live preview if the live preview option is
+   *   checked.
+   */
   Drupal.behaviors.livePreview = {
     attach(context) {
-      $(once('views-ajax', 'input#edit-displays-live-preview', context)).on('click', function () {
-        if ($(this).is(':checked')) {
-          $('#preview-submit').trigger('click');
-        }
-      });
-    }
-
+      $(once('views-ajax', 'input#edit-displays-live-preview', context)).on(
+        'click',
+        function () {
+          if ($(this).is(':checked')) {
+            $('#preview-submit').trigger('click');
+          }
+        },
+      );
+    },
   };
+
+  /**
+   * Sync preview display.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to sync the preview display when needed.
+   */
   Drupal.behaviors.syncPreviewDisplay = {
     attach(context) {
       $(once('views-ajax', '#views-tabset a')).on('click', function () {
         const href = $(this).attr('href');
+        // Cut of #views-tabset.
         const displayId = href.substr(11);
-        const viewsPreviewId = document.querySelector('#views-live-preview #preview-display-id');
-
+        const viewsPreviewId = document.querySelector(
+          '#views-live-preview #preview-display-id',
+        );
         if (viewsPreviewId) {
+          // Set the form element if it is present.
           viewsPreviewId.value = displayId;
         }
       });
-    }
-
+    },
   };
+
+  /**
+   * Ajax behaviors for the views_ui module.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches ajax behaviors to the elements with the classes in question.
+   */
   Drupal.behaviors.viewsAjax = {
     collapseReplaced: false,
-
     attach(context, settings) {
       const baseElementSettings = {
         event: 'click',
-        progress: {
-          type: 'fullscreen'
-        }
+        progress: { type: 'fullscreen' },
       };
-      once('views-ajax', 'a.views-ajax-link', context).forEach(link => {
+      // Bind AJAX behaviors to all items showing the class.
+      once('views-ajax', 'a.views-ajax-link', context).forEach((link) => {
         const $link = $(link);
         const elementSettings = baseElementSettings;
         elementSettings.base = $link.attr('id');
         elementSettings.element = link;
-
+        // Set the URL to go to the anchor.
         if ($link.attr('href')) {
           elementSettings.url = $link.attr('href');
         }
-
         Drupal.ajax(elementSettings);
       });
-      once('views-ajax', 'div#views-live-preview a').forEach(link => {
-        const $link = $(link);
 
+      once('views-ajax', 'div#views-live-preview a').forEach((link) => {
+        const $link = $(link);
+        // We don't bind to links without a URL.
         if (!$link.attr('href')) {
           return true;
         }
 
         const elementSettings = baseElementSettings;
+        // Set the URL to go to the anchor.
         elementSettings.url = $link.attr('href');
-
-        if (Drupal.Views.getPath(elementSettings.url).substring(0, 21) !== 'admin/structure/views') {
+        if (
+          Drupal.Views.getPath(elementSettings.url).substring(0, 21) !==
+          'admin/structure/views'
+        ) {
           return true;
         }
 
@@ -125,27 +257,37 @@
         elementSettings.element = link;
         Drupal.ajax(elementSettings);
       });
-      once('views-ajax', 'div#views-live-preview input[type=submit]').forEach(submit => {
-        const $submit = $(submit);
-        $submit.on('click', function () {
-          this.form.clk = this;
-          return true;
-        });
-        const elementSettings = baseElementSettings;
-        elementSettings.url = $(submit.form).attr('action');
 
-        if (Drupal.Views.getPath(elementSettings.url).substring(0, 21) !== 'admin/structure/views') {
-          return true;
-        }
+      // Within a live preview, make exposed widget form buttons re-trigger the
+      // Preview button.
+      // @todo Revisit this after fixing Views UI to display a Preview outside
+      //   of the main Edit form.
+      once('views-ajax', 'div#views-live-preview input[type=submit]').forEach(
+        (submit) => {
+          const $submit = $(submit);
+          $submit.on('click', function () {
+            this.form.clk = this;
+            return true;
+          });
+          const elementSettings = baseElementSettings;
+          // Set the URL to go to the anchor.
+          elementSettings.url = $(submit.form).attr('action');
+          if (
+            Drupal.Views.getPath(elementSettings.url).substring(0, 21) !==
+            'admin/structure/views'
+          ) {
+            return true;
+          }
 
-        elementSettings.wrapper = 'views-preview-wrapper';
-        elementSettings.method = 'replaceWith';
-        elementSettings.event = 'click';
-        elementSettings.base = submit.id;
-        elementSettings.element = submit;
-        Drupal.ajax(elementSettings);
-      });
-    }
+          elementSettings.wrapper = 'views-preview-wrapper';
+          elementSettings.method = 'replaceWith';
+          elementSettings.event = 'click';
+          elementSettings.base = submit.id;
+          elementSettings.element = submit;
 
+          Drupal.ajax(elementSettings);
+        },
+      );
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/views_ui/js/dialog.views.es6.js b/core/modules/views_ui/js/dialog.views.es6.js
deleted file mode 100644
index b5cbb91fbb5b..000000000000
--- a/core/modules/views_ui/js/dialog.views.es6.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @file
- * Views dialog behaviors.
- */
-
-(function ($, Drupal, drupalSettings) {
-  function handleDialogResize(e) {
-    const $modal = $(e.currentTarget);
-    const $viewsOverride = $modal.find('[data-drupal-views-offset]');
-    const $scroll = $modal.find('[data-drupal-views-scroll]');
-    let offset = 0;
-    let modalHeight;
-    if ($scroll.length) {
-      // Add a class to do some styles adjustments.
-      $modal.closest('.views-ui-dialog').addClass('views-ui-dialog-scroll');
-      // Let scroll element take all the height available.
-      $scroll.css({ overflow: 'visible', height: 'auto' });
-      modalHeight = $modal.height();
-      $viewsOverride.each(function () {
-        offset += $(this).outerHeight();
-      });
-
-      // Take internal padding into account.
-      const scrollOffset = $scroll.outerHeight() - $scroll.height();
-      $scroll.height(modalHeight - offset - scrollOffset);
-      // Reset scrolling properties.
-      $modal.css('overflow', 'hidden');
-      $scroll.css('overflow', 'auto');
-    }
-  }
-
-  /**
-   * Functionality for views modals.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches modal functionality for views.
-   * @prop {Drupal~behaviorDetach} detach
-   *   Detaches the modal functionality.
-   */
-  Drupal.behaviors.viewsModalContent = {
-    attach(context) {
-      $(once('viewsDialog', 'body')).on(
-        'dialogContentResize.viewsDialog',
-        '.ui-dialog-content',
-        handleDialogResize,
-      );
-      // When expanding details, make sure the modal is resized.
-      $(once('detailsUpdate', '.scroll', context)).on(
-        'click',
-        'summary',
-        (e) => {
-          $(e.currentTarget).trigger('dialogContentResize');
-        },
-      );
-    },
-    detach(context, settings, trigger) {
-      if (trigger === 'unload') {
-        $(once.remove('viewsDialog', 'body')).off('.viewsDialog');
-      }
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/views_ui/js/dialog.views.js b/core/modules/views_ui/js/dialog.views.js
index 45dee992c15d..b5cbb91fbb5b 100644
--- a/core/modules/views_ui/js/dialog.views.js
+++ b/core/modules/views_ui/js/dialog.views.js
@@ -1,9 +1,7 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Views dialog behaviors.
+ */
 
 (function ($, Drupal, drupalSettings) {
   function handleDialogResize(e) {
@@ -12,37 +10,55 @@
     const $scroll = $modal.find('[data-drupal-views-scroll]');
     let offset = 0;
     let modalHeight;
-
     if ($scroll.length) {
+      // Add a class to do some styles adjustments.
       $modal.closest('.views-ui-dialog').addClass('views-ui-dialog-scroll');
-      $scroll.css({
-        overflow: 'visible',
-        height: 'auto'
-      });
+      // Let scroll element take all the height available.
+      $scroll.css({ overflow: 'visible', height: 'auto' });
       modalHeight = $modal.height();
       $viewsOverride.each(function () {
         offset += $(this).outerHeight();
       });
+
+      // Take internal padding into account.
       const scrollOffset = $scroll.outerHeight() - $scroll.height();
       $scroll.height(modalHeight - offset - scrollOffset);
+      // Reset scrolling properties.
       $modal.css('overflow', 'hidden');
       $scroll.css('overflow', 'auto');
     }
   }
 
+  /**
+   * Functionality for views modals.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches modal functionality for views.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches the modal functionality.
+   */
   Drupal.behaviors.viewsModalContent = {
     attach(context) {
-      $(once('viewsDialog', 'body')).on('dialogContentResize.viewsDialog', '.ui-dialog-content', handleDialogResize);
-      $(once('detailsUpdate', '.scroll', context)).on('click', 'summary', e => {
-        $(e.currentTarget).trigger('dialogContentResize');
-      });
+      $(once('viewsDialog', 'body')).on(
+        'dialogContentResize.viewsDialog',
+        '.ui-dialog-content',
+        handleDialogResize,
+      );
+      // When expanding details, make sure the modal is resized.
+      $(once('detailsUpdate', '.scroll', context)).on(
+        'click',
+        'summary',
+        (e) => {
+          $(e.currentTarget).trigger('dialogContentResize');
+        },
+      );
     },
-
     detach(context, settings, trigger) {
       if (trigger === 'unload') {
         $(once.remove('viewsDialog', 'body')).off('.viewsDialog');
       }
-    }
-
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/views_ui/js/views-admin.es6.js b/core/modules/views_ui/js/views-admin.es6.js
deleted file mode 100644
index 3cc2795d455a..000000000000
--- a/core/modules/views_ui/js/views-admin.es6.js
+++ /dev/null
@@ -1,1337 +0,0 @@
-/**
- * @file
- * Some basic behaviors and utility functions for Views UI.
- */
-
-(function ($, Drupal, drupalSettings) {
-  /**
-   * @namespace
-   */
-  Drupal.viewsUi = {};
-
-  /**
-   * Improve the user experience of the views edit interface.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches toggling of SQL rewrite warning on the corresponding checkbox.
-   */
-  Drupal.behaviors.viewsUiEditView = {
-    attach() {
-      // Only show the SQL rewrite warning when the user has chosen the
-      // corresponding checkbox.
-      $('[data-drupal-selector="edit-query-options-disable-sql-rewrite"]').on(
-        'click',
-        () => {
-          $('.sql-rewrite-warning').toggleClass('js-hide');
-        },
-      );
-    },
-  };
-
-  /**
-   * In the add view wizard, use the view name to prepopulate form fields such
-   * as page title and menu link.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior for prepopulating page title and menu links, based on
-   *   view name.
-   */
-  Drupal.behaviors.viewsUiAddView = {
-    attach(context) {
-      const $context = $(context);
-      // Set up regular expressions to allow only numbers, letters, and dashes.
-      const exclude = new RegExp('[^a-z0-9\\-]+', 'g');
-      const replace = '-';
-      let suffix;
-
-      // The page title, block title, and menu link fields can all be
-      // prepopulated with the view name - no regular expression needed.
-      const $fields = $context.find(
-        '[id^="edit-page-title"], [id^="edit-block-title"], [id^="edit-page-link-properties-title"]',
-      );
-      if ($fields.length) {
-        if (!this.fieldsFiller) {
-          this.fieldsFiller = new Drupal.viewsUi.FormFieldFiller($fields);
-        } else {
-          // After an AJAX response, this.fieldsFiller will still have event
-          // handlers bound to the old version of the form fields (which don't
-          // exist anymore). The event handlers need to be unbound and then
-          // rebound to the new markup. Note that jQuery.live is difficult to
-          // make work in this case because the IDs of the form fields change
-          // on every AJAX response.
-          this.fieldsFiller.rebind($fields);
-        }
-      }
-
-      // Prepopulate the path field with a URLified version of the view name.
-      const $pathField = $context.find('[id^="edit-page-path"]');
-      if ($pathField.length) {
-        if (!this.pathFiller) {
-          this.pathFiller = new Drupal.viewsUi.FormFieldFiller(
-            $pathField,
-            exclude,
-            replace,
-          );
-        } else {
-          this.pathFiller.rebind($pathField);
-        }
-      }
-
-      // Populate the RSS feed field with a URLified version of the view name,
-      // and an .xml suffix (to make it unique).
-      const $feedField = $context.find(
-        '[id^="edit-page-feed-properties-path"]',
-      );
-      if ($feedField.length) {
-        if (!this.feedFiller) {
-          suffix = '.xml';
-          this.feedFiller = new Drupal.viewsUi.FormFieldFiller(
-            $feedField,
-            exclude,
-            replace,
-            suffix,
-          );
-        } else {
-          this.feedFiller.rebind($feedField);
-        }
-      }
-    },
-  };
-
-  /**
-   * Constructor for the {@link Drupal.viewsUi.FormFieldFiller} object.
-   *
-   * Prepopulates a form field based on the view name.
-   *
-   * @constructor
-   *
-   * @param {jQuery} $target
-   *   A jQuery object representing the form field or fields to prepopulate.
-   * @param {bool} [exclude=false]
-   *   A regular expression representing characters to exclude from
-   *   the target field.
-   * @param {string} [replace='']
-   *   A string to use as the replacement value for disallowed characters.
-   * @param {string} [suffix='']
-   *   A suffix to append at the end of the target field content.
-   */
-  Drupal.viewsUi.FormFieldFiller = function (
-    $target,
-    exclude,
-    replace,
-    suffix,
-  ) {
-    /**
-     *
-     * @type {jQuery}
-     */
-    this.source = $('#edit-label');
-
-    /**
-     *
-     * @type {jQuery}
-     */
-    this.target = $target;
-
-    /**
-     *
-     * @type {bool}
-     */
-    this.exclude = exclude || false;
-
-    /**
-     *
-     * @type {string}
-     */
-    this.replace = replace || '';
-
-    /**
-     *
-     * @type {string}
-     */
-    this.suffix = suffix || '';
-
-    // Create bound versions of this instance's object methods to use as event
-    // handlers. This will let us easily unbind those specific handlers later
-    // on. NOTE: jQuery.proxy will not work for this because it assumes we want
-    // only one bound version of an object method, whereas we need one version
-    // per object instance.
-    const self = this;
-
-    /**
-     * Populate the target form field with the altered source field value.
-     *
-     * @return {*}
-     *   The result of the _populate call, which should be undefined.
-     */
-    this.populate = function () {
-      return self._populate.call(self);
-    };
-
-    /**
-     * Stop prepopulating the form fields.
-     *
-     * @return {*}
-     *   The result of the _unbind call, which should be undefined.
-     */
-    this.unbind = function () {
-      return self._unbind.call(self);
-    };
-
-    this.bind();
-    // Object constructor; no return value.
-  };
-
-  $.extend(
-    Drupal.viewsUi.FormFieldFiller.prototype,
-    /** @lends Drupal.viewsUi.FormFieldFiller# */ {
-      /**
-       * Bind the form-filling behavior.
-       */
-      bind() {
-        this.unbind();
-        // Populate the form field when the source changes.
-        this.source.on('keyup.viewsUi change.viewsUi', this.populate);
-        // Quit populating the field as soon as it gets focus.
-        this.target.on('focus.viewsUi', this.unbind);
-      },
-
-      /**
-       * Get the source form field value as altered by the passed-in parameters.
-       *
-       * @return {string}
-       *   The source form field value.
-       */
-      getTransliterated() {
-        let from = this.source.length ? this.source[0].value : '';
-        if (this.exclude) {
-          from = from.toLowerCase().replace(this.exclude, this.replace);
-        }
-        return from;
-      },
-
-      /**
-       * Populate the target form field with the altered source field value.
-       */
-      _populate() {
-        const transliterated = this.getTransliterated();
-        const suffix = this.suffix;
-        this.target.each(function (i) {
-          // Ensure that the maxlength is not exceeded by prepopulating the field.
-          const maxlength = $(this).attr('maxlength') - suffix.length;
-          this.value = transliterated.substr(0, maxlength) + suffix;
-        });
-      },
-
-      /**
-       * Stop prepopulating the form fields.
-       */
-      _unbind() {
-        this.source.off('keyup.viewsUi change.viewsUi', this.populate);
-        this.target.off('focus.viewsUi', this.unbind);
-      },
-
-      /**
-       * Bind event handlers to new form fields, after they're replaced via Ajax.
-       *
-       * @param {jQuery} $fields
-       *   Fields to rebind functionality to.
-       */
-      rebind($fields) {
-        this.target = $fields;
-        this.bind();
-      },
-    },
-  );
-
-  /**
-   * Adds functionality for the add item form.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the functionality in {@link Drupal.viewsUi.AddItemForm} to the
-   *   forms in question.
-   */
-  Drupal.behaviors.addItemForm = {
-    attach(context) {
-      const $context = $(context);
-      let $form = $context;
-      // The add handler form may have an id of views-ui-add-handler-form--n.
-      if (!$context.is('form[id^="views-ui-add-handler-form"]')) {
-        $form = $context.find('form[id^="views-ui-add-handler-form"]');
-      }
-      if (once('views-ui-add-handler-form', $form).length) {
-        // If we have an unprocessed views-ui-add-handler-form, let's
-        // instantiate.
-        new Drupal.viewsUi.AddItemForm($form);
-      }
-    },
-  };
-
-  /**
-   * Constructs a new AddItemForm.
-   *
-   * @constructor
-   *
-   * @param {jQuery} $form
-   *   The form element used.
-   */
-  Drupal.viewsUi.AddItemForm = function ($form) {
-    /**
-     *
-     * @type {jQuery}
-     */
-    this.$form = $form;
-    this.$form
-      .find('.views-filterable-options :checkbox')
-      .on('click', $.proxy(this.handleCheck, this));
-
-    /**
-     * Find the wrapper of the displayed text.
-     */
-    this.$selected_div = this.$form.find('.views-selected-options').parent();
-    this.$selected_div.hide();
-
-    /**
-     *
-     * @type {Array}
-     */
-    this.checkedItems = [];
-  };
-
-  /**
-   * Handles a checkbox check.
-   *
-   * @param {jQuery.Event} event
-   *   The event triggered.
-   */
-  Drupal.viewsUi.AddItemForm.prototype.handleCheck = function (event) {
-    const $target = $(event.target);
-    const label = $target.closest('td').next().html().trim();
-    // Add/remove the checked item to the list.
-    if ($target.is(':checked')) {
-      this.$selected_div.show().css('display', 'block');
-      this.checkedItems.push(label);
-    } else {
-      const position = $.inArray(label, this.checkedItems);
-      // Delete the item from the list and make sure that the list doesn't have
-      // undefined items left.
-      for (let i = 0; i < this.checkedItems.length; i++) {
-        if (i === position) {
-          this.checkedItems.splice(i, 1);
-          i--;
-          break;
-        }
-      }
-      // Hide it again if none item is selected.
-      if (this.checkedItems.length === 0) {
-        this.$selected_div.hide();
-      }
-    }
-    this.refreshCheckedItems();
-  };
-
-  /**
-   * Refresh the display of the checked items.
-   */
-  Drupal.viewsUi.AddItemForm.prototype.refreshCheckedItems = function () {
-    // Perhaps we should precache the text div, too.
-    this.$selected_div
-      .find('.views-selected-options')
-      .html(this.checkedItems.join(', '))
-      .trigger('dialogContentResize');
-  };
-
-  /**
-   * The input field items that add displays must be rendered as `<input>`
-   * elements. The following behavior detaches the `<input>` elements from the
-   * DOM, wraps them in an unordered list, then appends them to the list of
-   * tabs.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Fixes the input elements needed.
-   */
-  Drupal.behaviors.viewsUiRenderAddViewButton = {
-    attach(context) {
-      // Build the add display menu and pull the display input buttons into it.
-      const menu = once(
-        'views-ui-render-add-view-button',
-        '#views-display-menu-tabs',
-        context,
-      );
-      if (!menu.length) {
-        return;
-      }
-      const $menu = $(menu);
-
-      const $addDisplayDropdown = $(
-        `<li class="add"><a href="#"><span class="icon add"></span>${Drupal.t(
-          'Add',
-        )}</a><ul class="action-list" style="display:none;"></ul></li>`,
-      );
-      const $displayButtons = $menu.nextAll('input.add-display').detach();
-      $displayButtons
-        .appendTo($addDisplayDropdown.find('.action-list'))
-        .wrap('<li>')
-        .parent()
-        .eq(0)
-        .addClass('first')
-        .end()
-        .eq(-1)
-        .addClass('last');
-      $displayButtons.each(function () {
-        const $this = $(this);
-        this.value = $this.attr('data-drupal-dropdown-label');
-      });
-      $addDisplayDropdown.appendTo($menu);
-
-      // Add the click handler for the add display button.
-      $menu.find('li.add > a').on('click', function (event) {
-        event.preventDefault();
-        const $trigger = $(this);
-        Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
-      });
-      // Add a mouseleave handler to close the dropdown when the user mouses
-      // away from the item. We use mouseleave instead of mouseout because
-      // the user is going to trigger mouseout when moving away from the trigger
-      // link to the sub menu items.
-      // We use the live binder because the open class on this item will be
-      // toggled on and off and we want the handler to take effect in the cases
-      // that the class is present, but not when it isn't.
-      $('li.add', $menu).on('mouseleave', function (event) {
-        const $this = $(this);
-        const $trigger = $this.children('a[href="#"]');
-        if ($this.children('.action-list').is(':visible')) {
-          Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
-        }
-      });
-    },
-  };
-
-  /**
-   * Toggle menu visibility.
-   *
-   * @param {jQuery} $trigger
-   *   The element where the toggle was triggered.
-   *
-   *
-   * @note [@jessebeach] I feel like the following should be a more generic
-   *   function and not written specifically for this UI, but I'm not sure
-   *   where to put it.
-   */
-  Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu = function ($trigger) {
-    $trigger.parent().toggleClass('open');
-    $trigger.next().slideToggle('fast');
-  };
-
-  /**
-   * Add search options to the views ui.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches {@link Drupal.viewsUi.OptionsSearch} to the views ui filter
-   *   options.
-   */
-  Drupal.behaviors.viewsUiSearchOptions = {
-    attach(context) {
-      const $context = $(context);
-      let $form = $context;
-      // The add handler form may have an id of views-ui-add-handler-form--n.
-      if (!$context.is('form[id^="views-ui-add-handler-form"]')) {
-        $form = $context.find('form[id^="views-ui-add-handler-form"]');
-      }
-      // Make sure we don't add more than one event handler to the same form.
-      if (once('views-ui-filter-options', $form).length) {
-        new Drupal.viewsUi.OptionsSearch($form);
-      }
-    },
-  };
-
-  /**
-   * Constructor for the viewsUi.OptionsSearch object.
-   *
-   * The OptionsSearch object filters the available options on a form according
-   * to the user's search term. Typing in "taxonomy" will show only those
-   * options containing "taxonomy" in their label.
-   *
-   * @constructor
-   *
-   * @param {jQuery} $form
-   *   The form element.
-   */
-  Drupal.viewsUi.OptionsSearch = function ($form) {
-    /**
-     *
-     * @type {jQuery}
-     */
-    this.$form = $form;
-
-    // Click on the title checks the box.
-    this.$form.on('click', 'td.title', (event) => {
-      const $target = $(event.currentTarget);
-      $target.closest('tr').find('input').trigger('click');
-    });
-
-    const searchBoxSelector =
-      '[data-drupal-selector="edit-override-controls-options-search"]';
-    const controlGroupSelector =
-      '[data-drupal-selector="edit-override-controls-group"]';
-    this.$form.on(
-      'formUpdated',
-      `${searchBoxSelector},${controlGroupSelector}`,
-      $.proxy(this.handleFilter, this),
-    );
-
-    this.$searchBox = this.$form.find(searchBoxSelector);
-    this.$controlGroup = this.$form.find(controlGroupSelector);
-
-    /**
-     * Get a list of option labels and their corresponding divs and maintain it
-     * in memory, so we have as little overhead as possible at keyup time.
-     */
-    this.options = this.getOptions(this.$form.find('.filterable-option'));
-
-    // Trap the ENTER key in the search box so that it doesn't submit the form.
-    this.$searchBox.on('keypress', (event) => {
-      if (event.which === 13) {
-        event.preventDefault();
-      }
-    });
-  };
-
-  $.extend(
-    Drupal.viewsUi.OptionsSearch.prototype,
-    /** @lends Drupal.viewsUi.OptionsSearch# */ {
-      /**
-       * Assemble a list of all the filterable options on the form.
-       *
-       * @param {jQuery} $allOptions
-       *   A jQuery object representing the rows of filterable options to be
-       *   shown and hidden depending on the user's search terms.
-       *
-       * @return {Array}
-       *   An array of all the filterable options.
-       */
-      getOptions($allOptions) {
-        let $title;
-        let $description;
-        let $option;
-        const options = [];
-        const length = $allOptions.length;
-        for (let i = 0; i < length; i++) {
-          $option = $($allOptions[i]);
-          $title = $option.find('.title');
-          $description = $option.find('.description');
-          options[i] = {
-            // Search on the lowercase version of the title text + description.
-            searchText: `${$title[0].textContent.toLowerCase()} ${$description[0].textContent.toLowerCase()}
-              .toLowerCase()}`,
-            // Maintain a reference to the jQuery object for each row, so we don't
-            // have to create a new object inside the performance-sensitive keyup
-            // handler.
-            $div: $option,
-          };
-        }
-        return options;
-      },
-
-      /**
-       * Filter handler for the search box and type select that hides or shows the relevant
-       * options.
-       *
-       * @param {jQuery.Event} event
-       *   The formUpdated event.
-       */
-      handleFilter(event) {
-        // Determine the user's search query. The search text has been converted
-        // to lowercase.
-        const search = this.$searchBox[0].value.toLowerCase();
-        const words = search.split(' ');
-        // Get selected Group
-        const group = this.$controlGroup[0].value;
-
-        // Search through the search texts in the form for matching text.
-        this.options.forEach((option) => {
-          function hasWord(word) {
-            return option.searchText.indexOf(word) !== -1;
-          }
-
-          let found = true;
-          // Each word in the search string has to match the item in order for the
-          // item to be shown.
-          if (search) {
-            found = words.every(hasWord);
-          }
-          if (found && group !== 'all') {
-            found = option.$div.hasClass(group);
-          }
-
-          option.$div.toggle(found);
-        });
-
-        // Adapt dialog to content size.
-        $(event.target).trigger('dialogContentResize');
-      },
-    },
-  );
-
-  /**
-   * Preview functionality in the views edit form.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the preview functionality to the view edit form.
-   */
-  Drupal.behaviors.viewsUiPreview = {
-    attach(context) {
-      // Only act on the edit view form.
-      const $contextualFiltersBucket = $(context).find(
-        '.views-display-column .views-ui-display-tab-bucket.argument',
-      );
-      if ($contextualFiltersBucket.length === 0) {
-        return;
-      }
-
-      // If the display has no contextual filters, hide the form where you
-      // enter the contextual filters for the live preview. If it has contextual
-      // filters, show the form.
-      const $contextualFilters = $contextualFiltersBucket.find(
-        '.views-display-setting a',
-      );
-      if ($contextualFilters.length) {
-        $('#preview-args').parent().show();
-      } else {
-        $('#preview-args').parent().hide();
-      }
-
-      // Executes an initial preview.
-      if (
-        $(once('edit-displays-live-preview', '#edit-displays-live-preview')).is(
-          ':checked',
-        )
-      ) {
-        $(once('edit-displays-live-preview', '#preview-submit')).trigger(
-          'click',
-        );
-      }
-    },
-  };
-
-  /**
-   * Improve the UI of the rearrange filters dialog box.
-   *
-   * @constructor
-   *
-   * @param {jQuery} $table
-   *   The table in the filter form.
-   * @param {jQuery} $operator
-   *   The filter groups operator element.
-   */
-  Drupal.viewsUi.RearrangeFilterHandler = function ($table, $operator) {
-    /**
-     * Keep a reference to the `<table>` being altered and to the div containing
-     * the filter groups operator dropdown (if it exists).
-     */
-    this.table = $table;
-
-    /**
-     *
-     * @type {jQuery}
-     */
-    this.operator = $operator;
-
-    /**
-     *
-     * @type {bool}
-     */
-    this.hasGroupOperator = this.operator.length > 0;
-
-    /**
-     * Keep a reference to all draggable rows within the table.
-     *
-     * @type {jQuery}
-     */
-    this.draggableRows = $table.find('.draggable');
-
-    /**
-     * Keep a reference to the buttons for adding and removing filter groups.
-     *
-     * @type {jQuery}
-     */
-    this.addGroupButton = $('#views-add-group');
-
-    /**
-     * @type {jQuery}
-     */
-    this.removeGroupButtons = $table.find('.views-remove-group');
-
-    // Add links that duplicate the functionality of the (hidden) add and remove
-    // buttons.
-    this.insertAddRemoveFilterGroupLinks();
-
-    // When there is a filter groups operator dropdown on the page, create
-    // duplicates of the dropdown between each pair of filter groups.
-    if (this.hasGroupOperator) {
-      /**
-       * @type {jQuery}
-       */
-      this.dropdowns = this.duplicateGroupsOperator();
-      this.syncGroupsOperators();
-    }
-
-    // Add methods to the tableDrag instance to account for operator cells
-    // (which span multiple rows), the operator labels next to each filter
-    // (e.g., "And" or "Or"), the filter groups, and other special aspects of
-    // this tableDrag instance.
-    this.modifyTableDrag();
-
-    // Initialize the operator labels (e.g., "And" or "Or") that are displayed
-    // next to the filters in each group, and bind a handler so that they change
-    // based on the values of the operator dropdown within that group.
-    this.redrawOperatorLabels();
-    $(
-      once(
-        'views-rearrange-filter-handler',
-        $table.find('.views-group-title select'),
-      ),
-    ).on(
-      'change.views-rearrange-filter-handler',
-      $.proxy(this, 'redrawOperatorLabels'),
-    );
-
-    // Bind handlers so that when a "Remove" link is clicked, we:
-    // - Update the rowspans of cells containing an operator dropdown (since
-    //   they need to change to reflect the number of rows in each group).
-    // - Redraw the operator labels next to the filters in the group (since the
-    //   filter that is currently displayed last in each group is not supposed
-    //   to have a label display next to it).
-    $(
-      once(
-        'views-rearrange-filter-handler',
-        $table.find('a.views-groups-remove-link'),
-      ),
-    )
-      .on(
-        'click.views-rearrange-filter-handler',
-        $.proxy(this, 'updateRowspans'),
-      )
-      .on(
-        'click.views-rearrange-filter-handler',
-        $.proxy(this, 'redrawOperatorLabels'),
-      );
-  };
-
-  $.extend(
-    Drupal.viewsUi.RearrangeFilterHandler.prototype,
-    /** @lends Drupal.viewsUi.RearrangeFilterHandler# */ {
-      /**
-       * Insert links that allow filter groups to be added and removed.
-       */
-      insertAddRemoveFilterGroupLinks() {
-        // Insert a link for adding a new group at the top of the page, and make
-        // it match the action link styling used in a typical page.html.twig.
-        // Since Drupal does not provide a theme function for this markup this is
-        // the best we can do.
-        $(
-          once(
-            'views-rearrange-filter-handler',
-            // When the link is clicked, dynamically click the hidden form
-            // button for adding a new filter group.
-            $(
-              `<ul class="action-links"><li><a id="views-add-group-link" href="#">${this.addGroupButton[0].value}</a></li></ul>`,
-            ).prependTo(this.table.parent()),
-          ),
-        )
-          .find('#views-add-group-link')
-          .on(
-            'click.views-rearrange-filter-handler',
-            $.proxy(this, 'clickAddGroupButton'),
-          );
-
-        // Find each (visually hidden) button for removing a filter group and
-        // insert a link next to it.
-        const length = this.removeGroupButtons.length;
-        let i;
-        for (i = 0; i < length; i++) {
-          const $removeGroupButton = $(this.removeGroupButtons[i]);
-          const buttonId = $removeGroupButton.attr('id');
-          $(
-            once(
-              'views-rearrange-filter-handler',
-              // When the link is clicked, dynamically click the corresponding form
-              // button.
-              $(
-                `<a href="#" class="views-remove-group-link">${Drupal.t(
-                  'Remove group',
-                )}</a>`,
-              ).insertBefore($removeGroupButton),
-            ),
-          ).on(
-            'click.views-rearrange-filter-handler',
-            { buttonId },
-            $.proxy(this, 'clickRemoveGroupButton'),
-          );
-        }
-      },
-
-      /**
-       * Dynamically click the button that adds a new filter group.
-       *
-       * @param {jQuery.Event} event
-       *   The event triggered.
-       */
-      clickAddGroupButton(event) {
-        this.addGroupButton.trigger('mousedown');
-        event.preventDefault();
-      },
-
-      /**
-       * Dynamically click a button for removing a filter group.
-       *
-       * @param {jQuery.Event} event
-       *   Event being triggered, with event.data.buttonId set to the ID of the
-       *   form button that should be clicked.
-       */
-      clickRemoveGroupButton(event) {
-        this.table.find(`#${event.data.buttonId}`).trigger('mousedown');
-        event.preventDefault();
-      },
-
-      /**
-       * Move the groups operator so that it's between the first two groups, and
-       * duplicate it between any subsequent groups.
-       *
-       * @return {jQuery}
-       *   An operator element.
-       */
-      duplicateGroupsOperator() {
-        let newRow;
-        let titleRow;
-
-        const titleRows = once(
-          'duplicateGroupsOperator',
-          'tr.views-group-title',
-        );
-
-        if (!titleRows.length) {
-          return this.operator;
-        }
-
-        // Get rid of the explanatory text around the operator; its placement is
-        // explanatory enough.
-        this.operator
-          .find('label')
-          .add('div.description')
-          .addClass('visually-hidden');
-        this.operator.find('select').addClass('form-select');
-
-        // Keep a list of the operator dropdowns, so we can sync their behavior
-        // later.
-        const dropdowns = this.operator;
-
-        // Move the operator to a new row just above the second group.
-        titleRow = $('tr#views-group-title-2');
-        newRow = $(
-          '<tr class="filter-group-operator-row"><td colspan="5"></td></tr>',
-        );
-        newRow.find('td').append(this.operator);
-        newRow.insertBefore(titleRow);
-        const length = titleRows.length;
-        // Starting with the third group, copy the operator to a new row above the
-        // group title.
-        for (let i = 2; i < length; i++) {
-          titleRow = $(titleRows[i]);
-          // Make a copy of the operator dropdown and put it in a new table row.
-          const fakeOperator = this.operator.clone();
-          fakeOperator.attr('id', '');
-          newRow = $(
-            '<tr class="filter-group-operator-row"><td colspan="5"></td></tr>',
-          );
-          newRow.find('td').append(fakeOperator);
-          newRow.insertBefore(titleRow);
-          dropdowns.add(fakeOperator);
-        }
-
-        return dropdowns;
-      },
-
-      /**
-       * Make the duplicated groups operators change in sync with each other.
-       */
-      syncGroupsOperators() {
-        if (this.dropdowns.length < 2) {
-          // We only have one dropdown (or none at all), so there's nothing to
-          // sync.
-          return;
-        }
-
-        this.dropdowns.on('change', $.proxy(this, 'operatorChangeHandler'));
-      },
-
-      /**
-       * Click handler for the operators that appear between filter groups.
-       *
-       * Forces all operator dropdowns to have the same value.
-       *
-       * @param {jQuery.Event} event
-       *   The event triggered.
-       */
-      operatorChangeHandler(event) {
-        const $target = $(event.target);
-        const operators = this.dropdowns.find('select').not($target);
-
-        // Change the other operators to match this new value.
-        operators.each(function (index, item) {
-          item.value = $target[0].value;
-        });
-      },
-
-      /**
-       * @method
-       */
-      modifyTableDrag() {
-        const tableDrag = Drupal.tableDrag['views-rearrange-filters'];
-        const filterHandler = this;
-
-        /**
-         * Override the row.onSwap method from tabledrag.js.
-         *
-         * When a row is dragged to another place in the table, several things
-         * need to occur.
-         * - The row needs to be moved so that it's within one of the filter
-         * groups.
-         * - The operator cells that span multiple rows need their rowspan
-         * attributes updated to reflect the number of rows in each group.
-         * - The operator labels that are displayed next to each filter need to
-         * be redrawn, to account for the row's new location.
-         */
-        tableDrag.row.prototype.onSwap = function () {
-          if (filterHandler.hasGroupOperator) {
-            // Make sure the row that just got moved (this.group) is inside one
-            // of the filter groups (i.e. below an empty marker row or a
-            // draggable). If it isn't, move it down one.
-            const thisRow = $(this.group);
-            const previousRow = thisRow.prev('tr');
-            if (
-              previousRow.length &&
-              !previousRow.hasClass('group-message') &&
-              !previousRow.hasClass('draggable')
-            ) {
-              // Move the dragged row down one.
-              const next = thisRow.next();
-              if (next.is('tr')) {
-                this.swap('after', next);
-              }
-            }
-            filterHandler.updateRowspans();
-          }
-          // Redraw the operator labels that are displayed next to each filter, to
-          // account for the row's new location.
-          filterHandler.redrawOperatorLabels();
-        };
-
-        /**
-         * Override the onDrop method from tabledrag.js.
-         */
-        tableDrag.onDrop = function () {
-          // If the tabledrag change marker (i.e., the "*") has been inserted
-          // inside a row after the operator label (i.e., "And" or "Or")
-          // rearrange the items so the operator label continues to appear last.
-          const changeMarker = $(this.oldRowElement).find('.tabledrag-changed');
-          if (changeMarker.length) {
-            // Search for occurrences of the operator label before the change
-            // marker, and reverse them.
-            const operatorLabel = changeMarker.prevAll('.views-operator-label');
-            if (operatorLabel.length) {
-              operatorLabel.insertAfter(changeMarker);
-            }
-          }
-
-          // Make sure the "group" dropdown is properly updated when rows are
-          // dragged into an empty filter group. This is borrowed heavily from
-          // the block.js implementation of tableDrag.onDrop().
-          const groupRow = $(this.rowObject.element)
-            .prevAll('tr.group-message')
-            .get(0);
-          const groupName = groupRow.className.replace(
-            /([^ ]+[ ]+)*group-([^ ]+)-message([ ]+[^ ]+)*/,
-            '$2',
-          );
-          const groupField = $(
-            'select.views-group-select',
-            this.rowObject.element,
-          );
-          if (!groupField.is(`.views-group-select-${groupName}`)) {
-            const oldGroupName = groupField
-              .attr('class')
-              .replace(
-                /([^ ]+[ ]+)*views-group-select-([^ ]+)([ ]+[^ ]+)*/,
-                '$2',
-              );
-            groupField
-              .removeClass(`views-group-select-${oldGroupName}`)
-              .addClass(`views-group-select-${groupName}`);
-            groupField[0].value = groupName;
-          }
-        };
-      },
-
-      /**
-       * Redraw the operator labels that are displayed next to each filter.
-       */
-      redrawOperatorLabels() {
-        for (let i = 0; i < this.draggableRows.length; i++) {
-          // Within the row, the operator labels are displayed inside the first
-          // table cell (next to the filter name).
-          const $draggableRow = $(this.draggableRows[i]);
-          const $firstCell = $draggableRow.find('td').eq(0);
-          if ($firstCell.length) {
-            // The value of the operator label ("And" or "Or") is taken from the
-            // first operator dropdown we encounter, going backwards from the
-            // current row. This dropdown is the one associated with the current
-            // row's filter group.
-            const operatorValue = $draggableRow
-              .prevAll('.views-group-title')
-              .find('option:selected')
-              .html();
-            const operatorLabel = `<span class="views-operator-label">${operatorValue}</span>`;
-            // If the next visible row after this one is a draggable filter row,
-            // display the operator label next to the current row. (Checking for
-            // visibility is necessary here since the "Remove" links hide the
-            // removed row but don't actually remove it from the document).
-            const $nextRow = $draggableRow.nextAll(':visible').eq(0);
-            const $existingOperatorLabel = $firstCell.find(
-              '.views-operator-label',
-            );
-            if ($nextRow.hasClass('draggable')) {
-              // If an operator label was already there, replace it with the new
-              // one.
-              if ($existingOperatorLabel.length) {
-                $existingOperatorLabel.replaceWith(operatorLabel);
-              }
-              // Otherwise, append the operator label to the end of the table
-              // cell.
-              else {
-                $firstCell.append(operatorLabel);
-              }
-            }
-            // If the next row doesn't contain a filter, then this is the last row
-            // in the group. We don't want to display the operator there (since
-            // operators should only display between two related filters, e.g.
-            // "filter1 AND filter2 AND filter3"). So we remove any existing label
-            // that this row has.
-            else {
-              $existingOperatorLabel.remove();
-            }
-          }
-        }
-      },
-
-      /**
-       * Update the rowspan attribute of each cell containing an operator
-       * dropdown.
-       */
-      updateRowspans() {
-        let $row;
-        let $currentEmptyRow;
-        let draggableCount;
-        let $operatorCell;
-        const rows = $(this.table).find('tr');
-        const length = rows.length;
-        for (let i = 0; i < length; i++) {
-          $row = $(rows[i]);
-          if ($row.hasClass('views-group-title')) {
-            // This row is a title row.
-            // Keep a reference to the cell containing the dropdown operator.
-            $operatorCell = $row.find('td.group-operator');
-            // Assume this filter group is empty, until we find otherwise.
-            draggableCount = 0;
-            $currentEmptyRow = $row.next('tr');
-            $currentEmptyRow
-              .removeClass('group-populated')
-              .addClass('group-empty');
-            // The cell with the dropdown operator should span the title row and
-            // the "this group is empty" row.
-            $operatorCell.attr('rowspan', 2);
-          } else if ($row.hasClass('draggable') && $row.is(':visible')) {
-            // We've found a visible filter row, so we now know the group isn't
-            // empty.
-            draggableCount++;
-            $currentEmptyRow
-              .removeClass('group-empty')
-              .addClass('group-populated');
-            // The operator cell should span all draggable rows, plus the title.
-            $operatorCell.attr('rowspan', draggableCount + 1);
-          }
-        }
-      },
-    },
-  );
-
-  /**
-   * Add a select all checkbox, which checks each checkbox at once.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches select all functionality to the views filter form.
-   */
-  Drupal.behaviors.viewsFilterConfigSelectAll = {
-    attach(context) {
-      const selectAll = once(
-        'filterConfigSelectAll',
-        '.js-form-item-options-value-all',
-        context,
-      );
-
-      if (selectAll.length) {
-        const $selectAll = $(selectAll);
-        const $selectAllCheckbox = $selectAll.find('input[type=checkbox]');
-        const $checkboxes = $selectAll
-          .closest('.form-checkboxes')
-          .find(
-            '.js-form-type-checkbox:not(.js-form-item-options-value-all) input[type="checkbox"]',
-          );
-        // Show the select all checkbox.
-        $selectAll.show();
-        $selectAllCheckbox.on('click', function () {
-          // Update all checkbox beside the select all checkbox.
-          $checkboxes.prop('checked', $(this).is(':checked'));
-        });
-
-        // Uncheck the select all checkbox if any of the others are unchecked.
-        $checkboxes.on('click', function () {
-          if ($(this).is('checked') === false) {
-            $selectAllCheckbox.prop('checked', false);
-          }
-        });
-      }
-    },
-  };
-
-  /**
-   * Remove icon class from elements that are themed as buttons or dropbuttons.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Removes the icon class from certain views elements.
-   */
-  Drupal.behaviors.viewsRemoveIconClass = {
-    attach(context) {
-      $(once('dropbutton-icon', '.dropbutton', context))
-        .find('.icon')
-        .removeClass('icon');
-    },
-  };
-
-  /**
-   * Change "Expose filter" buttons into checkboxes.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Changes buttons into checkboxes via {@link Drupal.viewsUi.Checkboxifier}.
-   */
-  Drupal.behaviors.viewsUiCheckboxify = {
-    attach(context, settings) {
-      const buttons = once(
-        'views-ui-checkboxify',
-        '[data-drupal-selector="edit-options-expose-button-button"], [data-drupal-selector="edit-options-group-button-button"]',
-      ).forEach((button) => new Drupal.viewsUi.Checkboxifier(button));
-    },
-  };
-
-  /**
-   * Change the default widget to select the default group according to the
-   * selected widget for the exposed group.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Changes the default widget based on user input.
-   */
-  Drupal.behaviors.viewsUiChangeDefaultWidget = {
-    attach(context) {
-      const $context = $(context);
-
-      function changeDefaultWidget(event) {
-        if ($(event.target).prop('checked')) {
-          $context.find('input.default-radios').parent().hide();
-          $context.find('td.any-default-radios-row').parent().hide();
-          $context.find('input.default-checkboxes').parent().show();
-        } else {
-          $context.find('input.default-checkboxes').parent().hide();
-          $context.find('td.any-default-radios-row').parent().show();
-          $context.find('input.default-radios').parent().show();
-        }
-      }
-
-      // Update on widget change.
-      $context
-        .find('input[name="options[group_info][multiple]"]')
-        .on('change', changeDefaultWidget)
-        // Update the first time the form is rendered.
-        .trigger('change');
-    },
-  };
-
-  /**
-   * Attaches expose filter button to a checkbox that triggers its click event.
-   *
-   * @constructor
-   *
-   * @param {Element} button
-   *   The DOM object representing the button to be checkboxified.
-   */
-  Drupal.viewsUi.Checkboxifier = function (button) {
-    this.$button = $(button);
-    this.$parent = this.$button.parent('div.views-expose, div.views-grouped');
-    this.$input = this.$parent.find('input:checkbox, input:radio');
-    // Hide the button and its description.
-    this.$button.hide();
-    this.$parent.find('.exposed-description, .grouped-description').hide();
-
-    this.$input.on('click', $.proxy(this, 'clickHandler'));
-  };
-
-  /**
-   * When the checkbox is checked or unchecked, simulate a button press.
-   *
-   * @param {jQuery.Event} e
-   *   The event triggered.
-   */
-  Drupal.viewsUi.Checkboxifier.prototype.clickHandler = function (e) {
-    this.$button.trigger('click').trigger('submit');
-  };
-
-  /**
-   * Change the Apply button text based upon the override select state.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to change the Apply button according to the current
-   *   state.
-   */
-  Drupal.behaviors.viewsUiOverrideSelect = {
-    attach(context) {
-      once(
-        'views-ui-override-button-text',
-        '[data-drupal-selector="edit-override-dropdown"]',
-        context,
-      ).forEach((dropdown) => {
-        // Closures! :(
-        const $context = $(context);
-        const submit = context.querySelector('[id^=edit-submit]');
-        const oldValue = submit ? submit.value : '';
-
-        $(once('views-ui-override-button-text', submit)).on(
-          'mouseup',
-          function () {
-            this.value = oldValue;
-            return true;
-          },
-        );
-
-        $(dropdown)
-          .on('change', function () {
-            if (!submit) {
-              return;
-            }
-            if (this.value === 'default') {
-              submit.value = Drupal.t('Apply (all displays)');
-            } else if (this.value === 'default_revert') {
-              submit.value = Drupal.t('Revert to default');
-            } else {
-              submit.value = Drupal.t('Apply (this display)');
-            }
-            const $dialog = $context.closest('.ui-dialog-content');
-            $dialog.trigger('dialogButtonsChange');
-          })
-          .trigger('change');
-      });
-    },
-  };
-
-  /**
-   * Functionality for the remove link in the views UI.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior for the remove view and remove display links.
-   */
-  Drupal.behaviors.viewsUiHandlerRemoveLink = {
-    attach(context) {
-      const $context = $(context);
-      // Handle handler deletion by looking for the hidden checkbox and hiding
-      // the row.
-      $(once('views', 'a.views-remove-link', context)).on(
-        'click',
-        function (event) {
-          const id = $(this).attr('id').replace('views-remove-link-', '');
-          $context.find(`#views-row-${id}`).hide();
-          $context.find(`#views-removed-${id}`).prop('checked', true);
-          event.preventDefault();
-        },
-      );
-
-      // Handle display deletion by looking for the hidden checkbox and hiding
-      // the row.
-      $(once('display', 'a.display-remove-link', context)).on(
-        'click',
-        function (event) {
-          const id = $(this).attr('id').replace('display-remove-link-', '');
-          $context.find(`#display-row-${id}`).hide();
-          $context.find(`#display-removed-${id}`).prop('checked', true);
-          event.preventDefault();
-        },
-      );
-    },
-  };
-
-  /**
-   * Rearranges the filters.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attach handlers to make it possible to rearrange the filters in the form
-   *   in question.
-   *   @see Drupal.viewsUi.RearrangeFilterHandler
-   */
-  Drupal.behaviors.viewsUiRearrangeFilter = {
-    attach(context) {
-      // Only act on the rearrange filter form.
-      if (
-        typeof Drupal.tableDrag === 'undefined' ||
-        typeof Drupal.tableDrag['views-rearrange-filters'] === 'undefined'
-      ) {
-        return;
-      }
-      const table = once(
-        'views-rearrange-filters',
-        '#views-rearrange-filters',
-        context,
-      );
-      const operator = once(
-        'views-rearrange-filters',
-        '.js-form-item-filter-groups-operator',
-        context,
-      );
-      if (table.length) {
-        new Drupal.viewsUi.RearrangeFilterHandler($(table), $(operator));
-      }
-    },
-  };
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/views_ui/js/views-admin.js b/core/modules/views_ui/js/views-admin.js
index 82e5afa37f14..3cc2795d455a 100644
--- a/core/modules/views_ui/js/views-admin.js
+++ b/core/modules/views_ui/js/views-admin.js
@@ -1,150 +1,326 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Some basic behaviors and utility functions for Views UI.
+ */
 
 (function ($, Drupal, drupalSettings) {
+  /**
+   * @namespace
+   */
   Drupal.viewsUi = {};
+
+  /**
+   * Improve the user experience of the views edit interface.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches toggling of SQL rewrite warning on the corresponding checkbox.
+   */
   Drupal.behaviors.viewsUiEditView = {
     attach() {
-      $('[data-drupal-selector="edit-query-options-disable-sql-rewrite"]').on('click', () => {
-        $('.sql-rewrite-warning').toggleClass('js-hide');
-      });
-    }
-
+      // Only show the SQL rewrite warning when the user has chosen the
+      // corresponding checkbox.
+      $('[data-drupal-selector="edit-query-options-disable-sql-rewrite"]').on(
+        'click',
+        () => {
+          $('.sql-rewrite-warning').toggleClass('js-hide');
+        },
+      );
+    },
   };
+
+  /**
+   * In the add view wizard, use the view name to prepopulate form fields such
+   * as page title and menu link.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior for prepopulating page title and menu links, based on
+   *   view name.
+   */
   Drupal.behaviors.viewsUiAddView = {
     attach(context) {
       const $context = $(context);
+      // Set up regular expressions to allow only numbers, letters, and dashes.
       const exclude = new RegExp('[^a-z0-9\\-]+', 'g');
       const replace = '-';
       let suffix;
-      const $fields = $context.find('[id^="edit-page-title"], [id^="edit-block-title"], [id^="edit-page-link-properties-title"]');
 
+      // The page title, block title, and menu link fields can all be
+      // prepopulated with the view name - no regular expression needed.
+      const $fields = $context.find(
+        '[id^="edit-page-title"], [id^="edit-block-title"], [id^="edit-page-link-properties-title"]',
+      );
       if ($fields.length) {
         if (!this.fieldsFiller) {
           this.fieldsFiller = new Drupal.viewsUi.FormFieldFiller($fields);
         } else {
+          // After an AJAX response, this.fieldsFiller will still have event
+          // handlers bound to the old version of the form fields (which don't
+          // exist anymore). The event handlers need to be unbound and then
+          // rebound to the new markup. Note that jQuery.live is difficult to
+          // make work in this case because the IDs of the form fields change
+          // on every AJAX response.
           this.fieldsFiller.rebind($fields);
         }
       }
 
+      // Prepopulate the path field with a URLified version of the view name.
       const $pathField = $context.find('[id^="edit-page-path"]');
-
       if ($pathField.length) {
         if (!this.pathFiller) {
-          this.pathFiller = new Drupal.viewsUi.FormFieldFiller($pathField, exclude, replace);
+          this.pathFiller = new Drupal.viewsUi.FormFieldFiller(
+            $pathField,
+            exclude,
+            replace,
+          );
         } else {
           this.pathFiller.rebind($pathField);
         }
       }
 
-      const $feedField = $context.find('[id^="edit-page-feed-properties-path"]');
-
+      // Populate the RSS feed field with a URLified version of the view name,
+      // and an .xml suffix (to make it unique).
+      const $feedField = $context.find(
+        '[id^="edit-page-feed-properties-path"]',
+      );
       if ($feedField.length) {
         if (!this.feedFiller) {
           suffix = '.xml';
-          this.feedFiller = new Drupal.viewsUi.FormFieldFiller($feedField, exclude, replace, suffix);
+          this.feedFiller = new Drupal.viewsUi.FormFieldFiller(
+            $feedField,
+            exclude,
+            replace,
+            suffix,
+          );
         } else {
           this.feedFiller.rebind($feedField);
         }
       }
-    }
-
+    },
   };
 
-  Drupal.viewsUi.FormFieldFiller = function ($target, exclude, replace, suffix) {
+  /**
+   * Constructor for the {@link Drupal.viewsUi.FormFieldFiller} object.
+   *
+   * Prepopulates a form field based on the view name.
+   *
+   * @constructor
+   *
+   * @param {jQuery} $target
+   *   A jQuery object representing the form field or fields to prepopulate.
+   * @param {bool} [exclude=false]
+   *   A regular expression representing characters to exclude from
+   *   the target field.
+   * @param {string} [replace='']
+   *   A string to use as the replacement value for disallowed characters.
+   * @param {string} [suffix='']
+   *   A suffix to append at the end of the target field content.
+   */
+  Drupal.viewsUi.FormFieldFiller = function (
+    $target,
+    exclude,
+    replace,
+    suffix,
+  ) {
+    /**
+     *
+     * @type {jQuery}
+     */
     this.source = $('#edit-label');
+
+    /**
+     *
+     * @type {jQuery}
+     */
     this.target = $target;
+
+    /**
+     *
+     * @type {bool}
+     */
     this.exclude = exclude || false;
+
+    /**
+     *
+     * @type {string}
+     */
     this.replace = replace || '';
+
+    /**
+     *
+     * @type {string}
+     */
     this.suffix = suffix || '';
+
+    // Create bound versions of this instance's object methods to use as event
+    // handlers. This will let us easily unbind those specific handlers later
+    // on. NOTE: jQuery.proxy will not work for this because it assumes we want
+    // only one bound version of an object method, whereas we need one version
+    // per object instance.
     const self = this;
 
+    /**
+     * Populate the target form field with the altered source field value.
+     *
+     * @return {*}
+     *   The result of the _populate call, which should be undefined.
+     */
     this.populate = function () {
       return self._populate.call(self);
     };
 
+    /**
+     * Stop prepopulating the form fields.
+     *
+     * @return {*}
+     *   The result of the _unbind call, which should be undefined.
+     */
     this.unbind = function () {
       return self._unbind.call(self);
     };
 
     this.bind();
+    // Object constructor; no return value.
   };
 
-  $.extend(Drupal.viewsUi.FormFieldFiller.prototype, {
-    bind() {
-      this.unbind();
-      this.source.on('keyup.viewsUi change.viewsUi', this.populate);
-      this.target.on('focus.viewsUi', this.unbind);
-    },
-
-    getTransliterated() {
-      let from = this.source.length ? this.source[0].value : '';
-
-      if (this.exclude) {
-        from = from.toLowerCase().replace(this.exclude, this.replace);
-      }
-
-      return from;
-    },
-
-    _populate() {
-      const transliterated = this.getTransliterated();
-      const suffix = this.suffix;
-      this.target.each(function (i) {
-        const maxlength = $(this).attr('maxlength') - suffix.length;
-        this.value = transliterated.substr(0, maxlength) + suffix;
-      });
-    },
-
-    _unbind() {
-      this.source.off('keyup.viewsUi change.viewsUi', this.populate);
-      this.target.off('focus.viewsUi', this.unbind);
+  $.extend(
+    Drupal.viewsUi.FormFieldFiller.prototype,
+    /** @lends Drupal.viewsUi.FormFieldFiller# */ {
+      /**
+       * Bind the form-filling behavior.
+       */
+      bind() {
+        this.unbind();
+        // Populate the form field when the source changes.
+        this.source.on('keyup.viewsUi change.viewsUi', this.populate);
+        // Quit populating the field as soon as it gets focus.
+        this.target.on('focus.viewsUi', this.unbind);
+      },
+
+      /**
+       * Get the source form field value as altered by the passed-in parameters.
+       *
+       * @return {string}
+       *   The source form field value.
+       */
+      getTransliterated() {
+        let from = this.source.length ? this.source[0].value : '';
+        if (this.exclude) {
+          from = from.toLowerCase().replace(this.exclude, this.replace);
+        }
+        return from;
+      },
+
+      /**
+       * Populate the target form field with the altered source field value.
+       */
+      _populate() {
+        const transliterated = this.getTransliterated();
+        const suffix = this.suffix;
+        this.target.each(function (i) {
+          // Ensure that the maxlength is not exceeded by prepopulating the field.
+          const maxlength = $(this).attr('maxlength') - suffix.length;
+          this.value = transliterated.substr(0, maxlength) + suffix;
+        });
+      },
+
+      /**
+       * Stop prepopulating the form fields.
+       */
+      _unbind() {
+        this.source.off('keyup.viewsUi change.viewsUi', this.populate);
+        this.target.off('focus.viewsUi', this.unbind);
+      },
+
+      /**
+       * Bind event handlers to new form fields, after they're replaced via Ajax.
+       *
+       * @param {jQuery} $fields
+       *   Fields to rebind functionality to.
+       */
+      rebind($fields) {
+        this.target = $fields;
+        this.bind();
+      },
     },
-
-    rebind($fields) {
-      this.target = $fields;
-      this.bind();
-    }
-
-  });
+  );
+
+  /**
+   * Adds functionality for the add item form.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the functionality in {@link Drupal.viewsUi.AddItemForm} to the
+   *   forms in question.
+   */
   Drupal.behaviors.addItemForm = {
     attach(context) {
       const $context = $(context);
       let $form = $context;
-
+      // The add handler form may have an id of views-ui-add-handler-form--n.
       if (!$context.is('form[id^="views-ui-add-handler-form"]')) {
         $form = $context.find('form[id^="views-ui-add-handler-form"]');
       }
-
       if (once('views-ui-add-handler-form', $form).length) {
+        // If we have an unprocessed views-ui-add-handler-form, let's
+        // instantiate.
         new Drupal.viewsUi.AddItemForm($form);
       }
-    }
-
+    },
   };
 
+  /**
+   * Constructs a new AddItemForm.
+   *
+   * @constructor
+   *
+   * @param {jQuery} $form
+   *   The form element used.
+   */
   Drupal.viewsUi.AddItemForm = function ($form) {
+    /**
+     *
+     * @type {jQuery}
+     */
     this.$form = $form;
-    this.$form.find('.views-filterable-options :checkbox').on('click', $.proxy(this.handleCheck, this));
+    this.$form
+      .find('.views-filterable-options :checkbox')
+      .on('click', $.proxy(this.handleCheck, this));
+
+    /**
+     * Find the wrapper of the displayed text.
+     */
     this.$selected_div = this.$form.find('.views-selected-options').parent();
     this.$selected_div.hide();
+
+    /**
+     *
+     * @type {Array}
+     */
     this.checkedItems = [];
   };
 
+  /**
+   * Handles a checkbox check.
+   *
+   * @param {jQuery.Event} event
+   *   The event triggered.
+   */
   Drupal.viewsUi.AddItemForm.prototype.handleCheck = function (event) {
     const $target = $(event.target);
     const label = $target.closest('td').next().html().trim();
-
+    // Add/remove the checked item to the list.
     if ($target.is(':checked')) {
       this.$selected_div.show().css('display', 'block');
       this.checkedItems.push(label);
     } else {
       const position = $.inArray(label, this.checkedItems);
-
+      // Delete the item from the list and make sure that the list doesn't have
+      // undefined items left.
       for (let i = 0; i < this.checkedItems.length; i++) {
         if (i === position) {
           this.checkedItems.splice(i, 1);
@@ -152,384 +328,838 @@
           break;
         }
       }
-
+      // Hide it again if none item is selected.
       if (this.checkedItems.length === 0) {
         this.$selected_div.hide();
       }
     }
-
     this.refreshCheckedItems();
   };
 
+  /**
+   * Refresh the display of the checked items.
+   */
   Drupal.viewsUi.AddItemForm.prototype.refreshCheckedItems = function () {
-    this.$selected_div.find('.views-selected-options').html(this.checkedItems.join(', ')).trigger('dialogContentResize');
+    // Perhaps we should precache the text div, too.
+    this.$selected_div
+      .find('.views-selected-options')
+      .html(this.checkedItems.join(', '))
+      .trigger('dialogContentResize');
   };
 
+  /**
+   * The input field items that add displays must be rendered as `<input>`
+   * elements. The following behavior detaches the `<input>` elements from the
+   * DOM, wraps them in an unordered list, then appends them to the list of
+   * tabs.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Fixes the input elements needed.
+   */
   Drupal.behaviors.viewsUiRenderAddViewButton = {
     attach(context) {
-      const menu = once('views-ui-render-add-view-button', '#views-display-menu-tabs', context);
-
+      // Build the add display menu and pull the display input buttons into it.
+      const menu = once(
+        'views-ui-render-add-view-button',
+        '#views-display-menu-tabs',
+        context,
+      );
       if (!menu.length) {
         return;
       }
-
       const $menu = $(menu);
-      const $addDisplayDropdown = $(`<li class="add"><a href="#"><span class="icon add"></span>${Drupal.t('Add')}</a><ul class="action-list" style="display:none;"></ul></li>`);
+
+      const $addDisplayDropdown = $(
+        `<li class="add"><a href="#"><span class="icon add"></span>${Drupal.t(
+          'Add',
+        )}</a><ul class="action-list" style="display:none;"></ul></li>`,
+      );
       const $displayButtons = $menu.nextAll('input.add-display').detach();
-      $displayButtons.appendTo($addDisplayDropdown.find('.action-list')).wrap('<li>').parent().eq(0).addClass('first').end().eq(-1).addClass('last');
+      $displayButtons
+        .appendTo($addDisplayDropdown.find('.action-list'))
+        .wrap('<li>')
+        .parent()
+        .eq(0)
+        .addClass('first')
+        .end()
+        .eq(-1)
+        .addClass('last');
       $displayButtons.each(function () {
         const $this = $(this);
         this.value = $this.attr('data-drupal-dropdown-label');
       });
       $addDisplayDropdown.appendTo($menu);
+
+      // Add the click handler for the add display button.
       $menu.find('li.add > a').on('click', function (event) {
         event.preventDefault();
         const $trigger = $(this);
         Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
       });
+      // Add a mouseleave handler to close the dropdown when the user mouses
+      // away from the item. We use mouseleave instead of mouseout because
+      // the user is going to trigger mouseout when moving away from the trigger
+      // link to the sub menu items.
+      // We use the live binder because the open class on this item will be
+      // toggled on and off and we want the handler to take effect in the cases
+      // that the class is present, but not when it isn't.
       $('li.add', $menu).on('mouseleave', function (event) {
         const $this = $(this);
         const $trigger = $this.children('a[href="#"]');
-
         if ($this.children('.action-list').is(':visible')) {
           Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
         }
       });
-    }
-
+    },
   };
 
+  /**
+   * Toggle menu visibility.
+   *
+   * @param {jQuery} $trigger
+   *   The element where the toggle was triggered.
+   *
+   *
+   * @note [@jessebeach] I feel like the following should be a more generic
+   *   function and not written specifically for this UI, but I'm not sure
+   *   where to put it.
+   */
   Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu = function ($trigger) {
     $trigger.parent().toggleClass('open');
     $trigger.next().slideToggle('fast');
   };
 
+  /**
+   * Add search options to the views ui.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches {@link Drupal.viewsUi.OptionsSearch} to the views ui filter
+   *   options.
+   */
   Drupal.behaviors.viewsUiSearchOptions = {
     attach(context) {
       const $context = $(context);
       let $form = $context;
-
+      // The add handler form may have an id of views-ui-add-handler-form--n.
       if (!$context.is('form[id^="views-ui-add-handler-form"]')) {
         $form = $context.find('form[id^="views-ui-add-handler-form"]');
       }
-
+      // Make sure we don't add more than one event handler to the same form.
       if (once('views-ui-filter-options', $form).length) {
         new Drupal.viewsUi.OptionsSearch($form);
       }
-    }
-
+    },
   };
 
+  /**
+   * Constructor for the viewsUi.OptionsSearch object.
+   *
+   * The OptionsSearch object filters the available options on a form according
+   * to the user's search term. Typing in "taxonomy" will show only those
+   * options containing "taxonomy" in their label.
+   *
+   * @constructor
+   *
+   * @param {jQuery} $form
+   *   The form element.
+   */
   Drupal.viewsUi.OptionsSearch = function ($form) {
+    /**
+     *
+     * @type {jQuery}
+     */
     this.$form = $form;
-    this.$form.on('click', 'td.title', event => {
+
+    // Click on the title checks the box.
+    this.$form.on('click', 'td.title', (event) => {
       const $target = $(event.currentTarget);
       $target.closest('tr').find('input').trigger('click');
     });
-    const searchBoxSelector = '[data-drupal-selector="edit-override-controls-options-search"]';
-    const controlGroupSelector = '[data-drupal-selector="edit-override-controls-group"]';
-    this.$form.on('formUpdated', `${searchBoxSelector},${controlGroupSelector}`, $.proxy(this.handleFilter, this));
+
+    const searchBoxSelector =
+      '[data-drupal-selector="edit-override-controls-options-search"]';
+    const controlGroupSelector =
+      '[data-drupal-selector="edit-override-controls-group"]';
+    this.$form.on(
+      'formUpdated',
+      `${searchBoxSelector},${controlGroupSelector}`,
+      $.proxy(this.handleFilter, this),
+    );
+
     this.$searchBox = this.$form.find(searchBoxSelector);
     this.$controlGroup = this.$form.find(controlGroupSelector);
+
+    /**
+     * Get a list of option labels and their corresponding divs and maintain it
+     * in memory, so we have as little overhead as possible at keyup time.
+     */
     this.options = this.getOptions(this.$form.find('.filterable-option'));
-    this.$searchBox.on('keypress', event => {
+
+    // Trap the ENTER key in the search box so that it doesn't submit the form.
+    this.$searchBox.on('keypress', (event) => {
       if (event.which === 13) {
         event.preventDefault();
       }
     });
   };
 
-  $.extend(Drupal.viewsUi.OptionsSearch.prototype, {
-    getOptions($allOptions) {
-      let $title;
-      let $description;
-      let $option;
-      const options = [];
-      const length = $allOptions.length;
-
-      for (let i = 0; i < length; i++) {
-        $option = $($allOptions[i]);
-        $title = $option.find('.title');
-        $description = $option.find('.description');
-        options[i] = {
-          searchText: `${$title[0].textContent.toLowerCase()} ${$description[0].textContent.toLowerCase()}
+  $.extend(
+    Drupal.viewsUi.OptionsSearch.prototype,
+    /** @lends Drupal.viewsUi.OptionsSearch# */ {
+      /**
+       * Assemble a list of all the filterable options on the form.
+       *
+       * @param {jQuery} $allOptions
+       *   A jQuery object representing the rows of filterable options to be
+       *   shown and hidden depending on the user's search terms.
+       *
+       * @return {Array}
+       *   An array of all the filterable options.
+       */
+      getOptions($allOptions) {
+        let $title;
+        let $description;
+        let $option;
+        const options = [];
+        const length = $allOptions.length;
+        for (let i = 0; i < length; i++) {
+          $option = $($allOptions[i]);
+          $title = $option.find('.title');
+          $description = $option.find('.description');
+          options[i] = {
+            // Search on the lowercase version of the title text + description.
+            searchText: `${$title[0].textContent.toLowerCase()} ${$description[0].textContent.toLowerCase()}
               .toLowerCase()}`,
-          $div: $option
-        };
-      }
-
-      return options;
-    },
-
-    handleFilter(event) {
-      const search = this.$searchBox[0].value.toLowerCase();
-      const words = search.split(' ');
-      const group = this.$controlGroup[0].value;
-      this.options.forEach(option => {
-        function hasWord(word) {
-          return option.searchText.indexOf(word) !== -1;
-        }
-
-        let found = true;
-
-        if (search) {
-          found = words.every(hasWord);
+            // Maintain a reference to the jQuery object for each row, so we don't
+            // have to create a new object inside the performance-sensitive keyup
+            // handler.
+            $div: $option,
+          };
         }
+        return options;
+      },
+
+      /**
+       * Filter handler for the search box and type select that hides or shows the relevant
+       * options.
+       *
+       * @param {jQuery.Event} event
+       *   The formUpdated event.
+       */
+      handleFilter(event) {
+        // Determine the user's search query. The search text has been converted
+        // to lowercase.
+        const search = this.$searchBox[0].value.toLowerCase();
+        const words = search.split(' ');
+        // Get selected Group
+        const group = this.$controlGroup[0].value;
+
+        // Search through the search texts in the form for matching text.
+        this.options.forEach((option) => {
+          function hasWord(word) {
+            return option.searchText.indexOf(word) !== -1;
+          }
 
-        if (found && group !== 'all') {
-          found = option.$div.hasClass(group);
-        }
+          let found = true;
+          // Each word in the search string has to match the item in order for the
+          // item to be shown.
+          if (search) {
+            found = words.every(hasWord);
+          }
+          if (found && group !== 'all') {
+            found = option.$div.hasClass(group);
+          }
 
-        option.$div.toggle(found);
-      });
-      $(event.target).trigger('dialogContentResize');
-    }
+          option.$div.toggle(found);
+        });
 
-  });
+        // Adapt dialog to content size.
+        $(event.target).trigger('dialogContentResize');
+      },
+    },
+  );
+
+  /**
+   * Preview functionality in the views edit form.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the preview functionality to the view edit form.
+   */
   Drupal.behaviors.viewsUiPreview = {
     attach(context) {
-      const $contextualFiltersBucket = $(context).find('.views-display-column .views-ui-display-tab-bucket.argument');
-
+      // Only act on the edit view form.
+      const $contextualFiltersBucket = $(context).find(
+        '.views-display-column .views-ui-display-tab-bucket.argument',
+      );
       if ($contextualFiltersBucket.length === 0) {
         return;
       }
 
-      const $contextualFilters = $contextualFiltersBucket.find('.views-display-setting a');
-
+      // If the display has no contextual filters, hide the form where you
+      // enter the contextual filters for the live preview. If it has contextual
+      // filters, show the form.
+      const $contextualFilters = $contextualFiltersBucket.find(
+        '.views-display-setting a',
+      );
       if ($contextualFilters.length) {
         $('#preview-args').parent().show();
       } else {
         $('#preview-args').parent().hide();
       }
 
-      if ($(once('edit-displays-live-preview', '#edit-displays-live-preview')).is(':checked')) {
-        $(once('edit-displays-live-preview', '#preview-submit')).trigger('click');
+      // Executes an initial preview.
+      if (
+        $(once('edit-displays-live-preview', '#edit-displays-live-preview')).is(
+          ':checked',
+        )
+      ) {
+        $(once('edit-displays-live-preview', '#preview-submit')).trigger(
+          'click',
+        );
       }
-    }
-
+    },
   };
 
+  /**
+   * Improve the UI of the rearrange filters dialog box.
+   *
+   * @constructor
+   *
+   * @param {jQuery} $table
+   *   The table in the filter form.
+   * @param {jQuery} $operator
+   *   The filter groups operator element.
+   */
   Drupal.viewsUi.RearrangeFilterHandler = function ($table, $operator) {
+    /**
+     * Keep a reference to the `<table>` being altered and to the div containing
+     * the filter groups operator dropdown (if it exists).
+     */
     this.table = $table;
+
+    /**
+     *
+     * @type {jQuery}
+     */
     this.operator = $operator;
+
+    /**
+     *
+     * @type {bool}
+     */
     this.hasGroupOperator = this.operator.length > 0;
+
+    /**
+     * Keep a reference to all draggable rows within the table.
+     *
+     * @type {jQuery}
+     */
     this.draggableRows = $table.find('.draggable');
+
+    /**
+     * Keep a reference to the buttons for adding and removing filter groups.
+     *
+     * @type {jQuery}
+     */
     this.addGroupButton = $('#views-add-group');
+
+    /**
+     * @type {jQuery}
+     */
     this.removeGroupButtons = $table.find('.views-remove-group');
+
+    // Add links that duplicate the functionality of the (hidden) add and remove
+    // buttons.
     this.insertAddRemoveFilterGroupLinks();
 
+    // When there is a filter groups operator dropdown on the page, create
+    // duplicates of the dropdown between each pair of filter groups.
     if (this.hasGroupOperator) {
+      /**
+       * @type {jQuery}
+       */
       this.dropdowns = this.duplicateGroupsOperator();
       this.syncGroupsOperators();
     }
 
+    // Add methods to the tableDrag instance to account for operator cells
+    // (which span multiple rows), the operator labels next to each filter
+    // (e.g., "And" or "Or"), the filter groups, and other special aspects of
+    // this tableDrag instance.
     this.modifyTableDrag();
+
+    // Initialize the operator labels (e.g., "And" or "Or") that are displayed
+    // next to the filters in each group, and bind a handler so that they change
+    // based on the values of the operator dropdown within that group.
     this.redrawOperatorLabels();
-    $(once('views-rearrange-filter-handler', $table.find('.views-group-title select'))).on('change.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels'));
-    $(once('views-rearrange-filter-handler', $table.find('a.views-groups-remove-link'))).on('click.views-rearrange-filter-handler', $.proxy(this, 'updateRowspans')).on('click.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels'));
+    $(
+      once(
+        'views-rearrange-filter-handler',
+        $table.find('.views-group-title select'),
+      ),
+    ).on(
+      'change.views-rearrange-filter-handler',
+      $.proxy(this, 'redrawOperatorLabels'),
+    );
+
+    // Bind handlers so that when a "Remove" link is clicked, we:
+    // - Update the rowspans of cells containing an operator dropdown (since
+    //   they need to change to reflect the number of rows in each group).
+    // - Redraw the operator labels next to the filters in the group (since the
+    //   filter that is currently displayed last in each group is not supposed
+    //   to have a label display next to it).
+    $(
+      once(
+        'views-rearrange-filter-handler',
+        $table.find('a.views-groups-remove-link'),
+      ),
+    )
+      .on(
+        'click.views-rearrange-filter-handler',
+        $.proxy(this, 'updateRowspans'),
+      )
+      .on(
+        'click.views-rearrange-filter-handler',
+        $.proxy(this, 'redrawOperatorLabels'),
+      );
   };
 
-  $.extend(Drupal.viewsUi.RearrangeFilterHandler.prototype, {
-    insertAddRemoveFilterGroupLinks() {
-      $(once('views-rearrange-filter-handler', $(`<ul class="action-links"><li><a id="views-add-group-link" href="#">${this.addGroupButton[0].value}</a></li></ul>`).prependTo(this.table.parent()))).find('#views-add-group-link').on('click.views-rearrange-filter-handler', $.proxy(this, 'clickAddGroupButton'));
-      const length = this.removeGroupButtons.length;
-      let i;
-
-      for (i = 0; i < length; i++) {
-        const $removeGroupButton = $(this.removeGroupButtons[i]);
-        const buttonId = $removeGroupButton.attr('id');
-        $(once('views-rearrange-filter-handler', $(`<a href="#" class="views-remove-group-link">${Drupal.t('Remove group')}</a>`).insertBefore($removeGroupButton))).on('click.views-rearrange-filter-handler', {
-          buttonId
-        }, $.proxy(this, 'clickRemoveGroupButton'));
-      }
-    },
-
-    clickAddGroupButton(event) {
-      this.addGroupButton.trigger('mousedown');
-      event.preventDefault();
-    },
-
-    clickRemoveGroupButton(event) {
-      this.table.find(`#${event.data.buttonId}`).trigger('mousedown');
-      event.preventDefault();
-    },
-
-    duplicateGroupsOperator() {
-      let newRow;
-      let titleRow;
-      const titleRows = once('duplicateGroupsOperator', 'tr.views-group-title');
-
-      if (!titleRows.length) {
-        return this.operator;
-      }
+  $.extend(
+    Drupal.viewsUi.RearrangeFilterHandler.prototype,
+    /** @lends Drupal.viewsUi.RearrangeFilterHandler# */ {
+      /**
+       * Insert links that allow filter groups to be added and removed.
+       */
+      insertAddRemoveFilterGroupLinks() {
+        // Insert a link for adding a new group at the top of the page, and make
+        // it match the action link styling used in a typical page.html.twig.
+        // Since Drupal does not provide a theme function for this markup this is
+        // the best we can do.
+        $(
+          once(
+            'views-rearrange-filter-handler',
+            // When the link is clicked, dynamically click the hidden form
+            // button for adding a new filter group.
+            $(
+              `<ul class="action-links"><li><a id="views-add-group-link" href="#">${this.addGroupButton[0].value}</a></li></ul>`,
+            ).prependTo(this.table.parent()),
+          ),
+        )
+          .find('#views-add-group-link')
+          .on(
+            'click.views-rearrange-filter-handler',
+            $.proxy(this, 'clickAddGroupButton'),
+          );
+
+        // Find each (visually hidden) button for removing a filter group and
+        // insert a link next to it.
+        const length = this.removeGroupButtons.length;
+        let i;
+        for (i = 0; i < length; i++) {
+          const $removeGroupButton = $(this.removeGroupButtons[i]);
+          const buttonId = $removeGroupButton.attr('id');
+          $(
+            once(
+              'views-rearrange-filter-handler',
+              // When the link is clicked, dynamically click the corresponding form
+              // button.
+              $(
+                `<a href="#" class="views-remove-group-link">${Drupal.t(
+                  'Remove group',
+                )}</a>`,
+              ).insertBefore($removeGroupButton),
+            ),
+          ).on(
+            'click.views-rearrange-filter-handler',
+            { buttonId },
+            $.proxy(this, 'clickRemoveGroupButton'),
+          );
+        }
+      },
+
+      /**
+       * Dynamically click the button that adds a new filter group.
+       *
+       * @param {jQuery.Event} event
+       *   The event triggered.
+       */
+      clickAddGroupButton(event) {
+        this.addGroupButton.trigger('mousedown');
+        event.preventDefault();
+      },
+
+      /**
+       * Dynamically click a button for removing a filter group.
+       *
+       * @param {jQuery.Event} event
+       *   Event being triggered, with event.data.buttonId set to the ID of the
+       *   form button that should be clicked.
+       */
+      clickRemoveGroupButton(event) {
+        this.table.find(`#${event.data.buttonId}`).trigger('mousedown');
+        event.preventDefault();
+      },
+
+      /**
+       * Move the groups operator so that it's between the first two groups, and
+       * duplicate it between any subsequent groups.
+       *
+       * @return {jQuery}
+       *   An operator element.
+       */
+      duplicateGroupsOperator() {
+        let newRow;
+        let titleRow;
+
+        const titleRows = once(
+          'duplicateGroupsOperator',
+          'tr.views-group-title',
+        );
+
+        if (!titleRows.length) {
+          return this.operator;
+        }
 
-      this.operator.find('label').add('div.description').addClass('visually-hidden');
-      this.operator.find('select').addClass('form-select');
-      const dropdowns = this.operator;
-      titleRow = $('tr#views-group-title-2');
-      newRow = $('<tr class="filter-group-operator-row"><td colspan="5"></td></tr>');
-      newRow.find('td').append(this.operator);
-      newRow.insertBefore(titleRow);
-      const length = titleRows.length;
-
-      for (let i = 2; i < length; i++) {
-        titleRow = $(titleRows[i]);
-        const fakeOperator = this.operator.clone();
-        fakeOperator.attr('id', '');
-        newRow = $('<tr class="filter-group-operator-row"><td colspan="5"></td></tr>');
-        newRow.find('td').append(fakeOperator);
+        // Get rid of the explanatory text around the operator; its placement is
+        // explanatory enough.
+        this.operator
+          .find('label')
+          .add('div.description')
+          .addClass('visually-hidden');
+        this.operator.find('select').addClass('form-select');
+
+        // Keep a list of the operator dropdowns, so we can sync their behavior
+        // later.
+        const dropdowns = this.operator;
+
+        // Move the operator to a new row just above the second group.
+        titleRow = $('tr#views-group-title-2');
+        newRow = $(
+          '<tr class="filter-group-operator-row"><td colspan="5"></td></tr>',
+        );
+        newRow.find('td').append(this.operator);
         newRow.insertBefore(titleRow);
-        dropdowns.add(fakeOperator);
-      }
-
-      return dropdowns;
-    },
-
-    syncGroupsOperators() {
-      if (this.dropdowns.length < 2) {
-        return;
-      }
-
-      this.dropdowns.on('change', $.proxy(this, 'operatorChangeHandler'));
-    },
-
-    operatorChangeHandler(event) {
-      const $target = $(event.target);
-      const operators = this.dropdowns.find('select').not($target);
-      operators.each(function (index, item) {
-        item.value = $target[0].value;
-      });
-    },
-
-    modifyTableDrag() {
-      const tableDrag = Drupal.tableDrag['views-rearrange-filters'];
-      const filterHandler = this;
-
-      tableDrag.row.prototype.onSwap = function () {
-        if (filterHandler.hasGroupOperator) {
-          const thisRow = $(this.group);
-          const previousRow = thisRow.prev('tr');
+        const length = titleRows.length;
+        // Starting with the third group, copy the operator to a new row above the
+        // group title.
+        for (let i = 2; i < length; i++) {
+          titleRow = $(titleRows[i]);
+          // Make a copy of the operator dropdown and put it in a new table row.
+          const fakeOperator = this.operator.clone();
+          fakeOperator.attr('id', '');
+          newRow = $(
+            '<tr class="filter-group-operator-row"><td colspan="5"></td></tr>',
+          );
+          newRow.find('td').append(fakeOperator);
+          newRow.insertBefore(titleRow);
+          dropdowns.add(fakeOperator);
+        }
 
-          if (previousRow.length && !previousRow.hasClass('group-message') && !previousRow.hasClass('draggable')) {
-            const next = thisRow.next();
+        return dropdowns;
+      },
+
+      /**
+       * Make the duplicated groups operators change in sync with each other.
+       */
+      syncGroupsOperators() {
+        if (this.dropdowns.length < 2) {
+          // We only have one dropdown (or none at all), so there's nothing to
+          // sync.
+          return;
+        }
 
-            if (next.is('tr')) {
-              this.swap('after', next);
+        this.dropdowns.on('change', $.proxy(this, 'operatorChangeHandler'));
+      },
+
+      /**
+       * Click handler for the operators that appear between filter groups.
+       *
+       * Forces all operator dropdowns to have the same value.
+       *
+       * @param {jQuery.Event} event
+       *   The event triggered.
+       */
+      operatorChangeHandler(event) {
+        const $target = $(event.target);
+        const operators = this.dropdowns.find('select').not($target);
+
+        // Change the other operators to match this new value.
+        operators.each(function (index, item) {
+          item.value = $target[0].value;
+        });
+      },
+
+      /**
+       * @method
+       */
+      modifyTableDrag() {
+        const tableDrag = Drupal.tableDrag['views-rearrange-filters'];
+        const filterHandler = this;
+
+        /**
+         * Override the row.onSwap method from tabledrag.js.
+         *
+         * When a row is dragged to another place in the table, several things
+         * need to occur.
+         * - The row needs to be moved so that it's within one of the filter
+         * groups.
+         * - The operator cells that span multiple rows need their rowspan
+         * attributes updated to reflect the number of rows in each group.
+         * - The operator labels that are displayed next to each filter need to
+         * be redrawn, to account for the row's new location.
+         */
+        tableDrag.row.prototype.onSwap = function () {
+          if (filterHandler.hasGroupOperator) {
+            // Make sure the row that just got moved (this.group) is inside one
+            // of the filter groups (i.e. below an empty marker row or a
+            // draggable). If it isn't, move it down one.
+            const thisRow = $(this.group);
+            const previousRow = thisRow.prev('tr');
+            if (
+              previousRow.length &&
+              !previousRow.hasClass('group-message') &&
+              !previousRow.hasClass('draggable')
+            ) {
+              // Move the dragged row down one.
+              const next = thisRow.next();
+              if (next.is('tr')) {
+                this.swap('after', next);
+              }
             }
+            filterHandler.updateRowspans();
           }
+          // Redraw the operator labels that are displayed next to each filter, to
+          // account for the row's new location.
+          filterHandler.redrawOperatorLabels();
+        };
 
-          filterHandler.updateRowspans();
-        }
-
-        filterHandler.redrawOperatorLabels();
-      };
-
-      tableDrag.onDrop = function () {
-        const changeMarker = $(this.oldRowElement).find('.tabledrag-changed');
-
-        if (changeMarker.length) {
-          const operatorLabel = changeMarker.prevAll('.views-operator-label');
-
-          if (operatorLabel.length) {
-            operatorLabel.insertAfter(changeMarker);
+        /**
+         * Override the onDrop method from tabledrag.js.
+         */
+        tableDrag.onDrop = function () {
+          // If the tabledrag change marker (i.e., the "*") has been inserted
+          // inside a row after the operator label (i.e., "And" or "Or")
+          // rearrange the items so the operator label continues to appear last.
+          const changeMarker = $(this.oldRowElement).find('.tabledrag-changed');
+          if (changeMarker.length) {
+            // Search for occurrences of the operator label before the change
+            // marker, and reverse them.
+            const operatorLabel = changeMarker.prevAll('.views-operator-label');
+            if (operatorLabel.length) {
+              operatorLabel.insertAfter(changeMarker);
+            }
           }
-        }
-
-        const groupRow = $(this.rowObject.element).prevAll('tr.group-message').get(0);
-        const groupName = groupRow.className.replace(/([^ ]+[ ]+)*group-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
-        const groupField = $('select.views-group-select', this.rowObject.element);
 
-        if (!groupField.is(`.views-group-select-${groupName}`)) {
-          const oldGroupName = groupField.attr('class').replace(/([^ ]+[ ]+)*views-group-select-([^ ]+)([ ]+[^ ]+)*/, '$2');
-          groupField.removeClass(`views-group-select-${oldGroupName}`).addClass(`views-group-select-${groupName}`);
-          groupField[0].value = groupName;
-        }
-      };
-    },
-
-    redrawOperatorLabels() {
-      for (let i = 0; i < this.draggableRows.length; i++) {
-        const $draggableRow = $(this.draggableRows[i]);
-        const $firstCell = $draggableRow.find('td').eq(0);
-
-        if ($firstCell.length) {
-          const operatorValue = $draggableRow.prevAll('.views-group-title').find('option:selected').html();
-          const operatorLabel = `<span class="views-operator-label">${operatorValue}</span>`;
-          const $nextRow = $draggableRow.nextAll(':visible').eq(0);
-          const $existingOperatorLabel = $firstCell.find('.views-operator-label');
-
-          if ($nextRow.hasClass('draggable')) {
-            if ($existingOperatorLabel.length) {
-              $existingOperatorLabel.replaceWith(operatorLabel);
-            } else {
-              $firstCell.append(operatorLabel);
+          // Make sure the "group" dropdown is properly updated when rows are
+          // dragged into an empty filter group. This is borrowed heavily from
+          // the block.js implementation of tableDrag.onDrop().
+          const groupRow = $(this.rowObject.element)
+            .prevAll('tr.group-message')
+            .get(0);
+          const groupName = groupRow.className.replace(
+            /([^ ]+[ ]+)*group-([^ ]+)-message([ ]+[^ ]+)*/,
+            '$2',
+          );
+          const groupField = $(
+            'select.views-group-select',
+            this.rowObject.element,
+          );
+          if (!groupField.is(`.views-group-select-${groupName}`)) {
+            const oldGroupName = groupField
+              .attr('class')
+              .replace(
+                /([^ ]+[ ]+)*views-group-select-([^ ]+)([ ]+[^ ]+)*/,
+                '$2',
+              );
+            groupField
+              .removeClass(`views-group-select-${oldGroupName}`)
+              .addClass(`views-group-select-${groupName}`);
+            groupField[0].value = groupName;
+          }
+        };
+      },
+
+      /**
+       * Redraw the operator labels that are displayed next to each filter.
+       */
+      redrawOperatorLabels() {
+        for (let i = 0; i < this.draggableRows.length; i++) {
+          // Within the row, the operator labels are displayed inside the first
+          // table cell (next to the filter name).
+          const $draggableRow = $(this.draggableRows[i]);
+          const $firstCell = $draggableRow.find('td').eq(0);
+          if ($firstCell.length) {
+            // The value of the operator label ("And" or "Or") is taken from the
+            // first operator dropdown we encounter, going backwards from the
+            // current row. This dropdown is the one associated with the current
+            // row's filter group.
+            const operatorValue = $draggableRow
+              .prevAll('.views-group-title')
+              .find('option:selected')
+              .html();
+            const operatorLabel = `<span class="views-operator-label">${operatorValue}</span>`;
+            // If the next visible row after this one is a draggable filter row,
+            // display the operator label next to the current row. (Checking for
+            // visibility is necessary here since the "Remove" links hide the
+            // removed row but don't actually remove it from the document).
+            const $nextRow = $draggableRow.nextAll(':visible').eq(0);
+            const $existingOperatorLabel = $firstCell.find(
+              '.views-operator-label',
+            );
+            if ($nextRow.hasClass('draggable')) {
+              // If an operator label was already there, replace it with the new
+              // one.
+              if ($existingOperatorLabel.length) {
+                $existingOperatorLabel.replaceWith(operatorLabel);
+              }
+              // Otherwise, append the operator label to the end of the table
+              // cell.
+              else {
+                $firstCell.append(operatorLabel);
+              }
+            }
+            // If the next row doesn't contain a filter, then this is the last row
+            // in the group. We don't want to display the operator there (since
+            // operators should only display between two related filters, e.g.
+            // "filter1 AND filter2 AND filter3"). So we remove any existing label
+            // that this row has.
+            else {
+              $existingOperatorLabel.remove();
             }
-          } else {
-            $existingOperatorLabel.remove();
           }
         }
-      }
-    },
-
-    updateRowspans() {
-      let $row;
-      let $currentEmptyRow;
-      let draggableCount;
-      let $operatorCell;
-      const rows = $(this.table).find('tr');
-      const length = rows.length;
-
-      for (let i = 0; i < length; i++) {
-        $row = $(rows[i]);
-
-        if ($row.hasClass('views-group-title')) {
-          $operatorCell = $row.find('td.group-operator');
-          draggableCount = 0;
-          $currentEmptyRow = $row.next('tr');
-          $currentEmptyRow.removeClass('group-populated').addClass('group-empty');
-          $operatorCell.attr('rowspan', 2);
-        } else if ($row.hasClass('draggable') && $row.is(':visible')) {
-          draggableCount++;
-          $currentEmptyRow.removeClass('group-empty').addClass('group-populated');
-          $operatorCell.attr('rowspan', draggableCount + 1);
+      },
+
+      /**
+       * Update the rowspan attribute of each cell containing an operator
+       * dropdown.
+       */
+      updateRowspans() {
+        let $row;
+        let $currentEmptyRow;
+        let draggableCount;
+        let $operatorCell;
+        const rows = $(this.table).find('tr');
+        const length = rows.length;
+        for (let i = 0; i < length; i++) {
+          $row = $(rows[i]);
+          if ($row.hasClass('views-group-title')) {
+            // This row is a title row.
+            // Keep a reference to the cell containing the dropdown operator.
+            $operatorCell = $row.find('td.group-operator');
+            // Assume this filter group is empty, until we find otherwise.
+            draggableCount = 0;
+            $currentEmptyRow = $row.next('tr');
+            $currentEmptyRow
+              .removeClass('group-populated')
+              .addClass('group-empty');
+            // The cell with the dropdown operator should span the title row and
+            // the "this group is empty" row.
+            $operatorCell.attr('rowspan', 2);
+          } else if ($row.hasClass('draggable') && $row.is(':visible')) {
+            // We've found a visible filter row, so we now know the group isn't
+            // empty.
+            draggableCount++;
+            $currentEmptyRow
+              .removeClass('group-empty')
+              .addClass('group-populated');
+            // The operator cell should span all draggable rows, plus the title.
+            $operatorCell.attr('rowspan', draggableCount + 1);
+          }
         }
-      }
-    }
-
-  });
+      },
+    },
+  );
+
+  /**
+   * Add a select all checkbox, which checks each checkbox at once.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches select all functionality to the views filter form.
+   */
   Drupal.behaviors.viewsFilterConfigSelectAll = {
     attach(context) {
-      const selectAll = once('filterConfigSelectAll', '.js-form-item-options-value-all', context);
+      const selectAll = once(
+        'filterConfigSelectAll',
+        '.js-form-item-options-value-all',
+        context,
+      );
 
       if (selectAll.length) {
         const $selectAll = $(selectAll);
         const $selectAllCheckbox = $selectAll.find('input[type=checkbox]');
-        const $checkboxes = $selectAll.closest('.form-checkboxes').find('.js-form-type-checkbox:not(.js-form-item-options-value-all) input[type="checkbox"]');
+        const $checkboxes = $selectAll
+          .closest('.form-checkboxes')
+          .find(
+            '.js-form-type-checkbox:not(.js-form-item-options-value-all) input[type="checkbox"]',
+          );
+        // Show the select all checkbox.
         $selectAll.show();
         $selectAllCheckbox.on('click', function () {
+          // Update all checkbox beside the select all checkbox.
           $checkboxes.prop('checked', $(this).is(':checked'));
         });
+
+        // Uncheck the select all checkbox if any of the others are unchecked.
         $checkboxes.on('click', function () {
           if ($(this).is('checked') === false) {
             $selectAllCheckbox.prop('checked', false);
           }
         });
       }
-    }
-
+    },
   };
+
+  /**
+   * Remove icon class from elements that are themed as buttons or dropbuttons.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Removes the icon class from certain views elements.
+   */
   Drupal.behaviors.viewsRemoveIconClass = {
     attach(context) {
-      $(once('dropbutton-icon', '.dropbutton', context)).find('.icon').removeClass('icon');
-    }
-
+      $(once('dropbutton-icon', '.dropbutton', context))
+        .find('.icon')
+        .removeClass('icon');
+    },
   };
+
+  /**
+   * Change "Expose filter" buttons into checkboxes.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Changes buttons into checkboxes via {@link Drupal.viewsUi.Checkboxifier}.
+   */
   Drupal.behaviors.viewsUiCheckboxify = {
     attach(context, settings) {
-      const buttons = once('views-ui-checkboxify', '[data-drupal-selector="edit-options-expose-button-button"], [data-drupal-selector="edit-options-group-button-button"]').forEach(button => new Drupal.viewsUi.Checkboxifier(button));
-    }
-
+      const buttons = once(
+        'views-ui-checkboxify',
+        '[data-drupal-selector="edit-options-expose-button-button"], [data-drupal-selector="edit-options-group-button-button"]',
+      ).forEach((button) => new Drupal.viewsUi.Checkboxifier(button));
+    },
   };
+
+  /**
+   * Change the default widget to select the default group according to the
+   * selected widget for the exposed group.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Changes the default widget based on user input.
+   */
   Drupal.behaviors.viewsUiChangeDefaultWidget = {
     attach(context) {
       const $context = $(context);
@@ -546,85 +1176,162 @@
         }
       }
 
-      $context.find('input[name="options[group_info][multiple]"]').on('change', changeDefaultWidget).trigger('change');
-    }
-
+      // Update on widget change.
+      $context
+        .find('input[name="options[group_info][multiple]"]')
+        .on('change', changeDefaultWidget)
+        // Update the first time the form is rendered.
+        .trigger('change');
+    },
   };
 
+  /**
+   * Attaches expose filter button to a checkbox that triggers its click event.
+   *
+   * @constructor
+   *
+   * @param {Element} button
+   *   The DOM object representing the button to be checkboxified.
+   */
   Drupal.viewsUi.Checkboxifier = function (button) {
     this.$button = $(button);
     this.$parent = this.$button.parent('div.views-expose, div.views-grouped');
     this.$input = this.$parent.find('input:checkbox, input:radio');
+    // Hide the button and its description.
     this.$button.hide();
     this.$parent.find('.exposed-description, .grouped-description').hide();
+
     this.$input.on('click', $.proxy(this, 'clickHandler'));
   };
 
+  /**
+   * When the checkbox is checked or unchecked, simulate a button press.
+   *
+   * @param {jQuery.Event} e
+   *   The event triggered.
+   */
   Drupal.viewsUi.Checkboxifier.prototype.clickHandler = function (e) {
     this.$button.trigger('click').trigger('submit');
   };
 
+  /**
+   * Change the Apply button text based upon the override select state.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to change the Apply button according to the current
+   *   state.
+   */
   Drupal.behaviors.viewsUiOverrideSelect = {
     attach(context) {
-      once('views-ui-override-button-text', '[data-drupal-selector="edit-override-dropdown"]', context).forEach(dropdown => {
+      once(
+        'views-ui-override-button-text',
+        '[data-drupal-selector="edit-override-dropdown"]',
+        context,
+      ).forEach((dropdown) => {
+        // Closures! :(
         const $context = $(context);
         const submit = context.querySelector('[id^=edit-submit]');
         const oldValue = submit ? submit.value : '';
-        $(once('views-ui-override-button-text', submit)).on('mouseup', function () {
-          this.value = oldValue;
-          return true;
-        });
-        $(dropdown).on('change', function () {
-          if (!submit) {
-            return;
-          }
-
-          if (this.value === 'default') {
-            submit.value = Drupal.t('Apply (all displays)');
-          } else if (this.value === 'default_revert') {
-            submit.value = Drupal.t('Revert to default');
-          } else {
-            submit.value = Drupal.t('Apply (this display)');
-          }
 
-          const $dialog = $context.closest('.ui-dialog-content');
-          $dialog.trigger('dialogButtonsChange');
-        }).trigger('change');
+        $(once('views-ui-override-button-text', submit)).on(
+          'mouseup',
+          function () {
+            this.value = oldValue;
+            return true;
+          },
+        );
+
+        $(dropdown)
+          .on('change', function () {
+            if (!submit) {
+              return;
+            }
+            if (this.value === 'default') {
+              submit.value = Drupal.t('Apply (all displays)');
+            } else if (this.value === 'default_revert') {
+              submit.value = Drupal.t('Revert to default');
+            } else {
+              submit.value = Drupal.t('Apply (this display)');
+            }
+            const $dialog = $context.closest('.ui-dialog-content');
+            $dialog.trigger('dialogButtonsChange');
+          })
+          .trigger('change');
       });
-    }
-
+    },
   };
+
+  /**
+   * Functionality for the remove link in the views UI.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior for the remove view and remove display links.
+   */
   Drupal.behaviors.viewsUiHandlerRemoveLink = {
     attach(context) {
       const $context = $(context);
-      $(once('views', 'a.views-remove-link', context)).on('click', function (event) {
-        const id = $(this).attr('id').replace('views-remove-link-', '');
-        $context.find(`#views-row-${id}`).hide();
-        $context.find(`#views-removed-${id}`).prop('checked', true);
-        event.preventDefault();
-      });
-      $(once('display', 'a.display-remove-link', context)).on('click', function (event) {
-        const id = $(this).attr('id').replace('display-remove-link-', '');
-        $context.find(`#display-row-${id}`).hide();
-        $context.find(`#display-removed-${id}`).prop('checked', true);
-        event.preventDefault();
-      });
-    }
-
+      // Handle handler deletion by looking for the hidden checkbox and hiding
+      // the row.
+      $(once('views', 'a.views-remove-link', context)).on(
+        'click',
+        function (event) {
+          const id = $(this).attr('id').replace('views-remove-link-', '');
+          $context.find(`#views-row-${id}`).hide();
+          $context.find(`#views-removed-${id}`).prop('checked', true);
+          event.preventDefault();
+        },
+      );
+
+      // Handle display deletion by looking for the hidden checkbox and hiding
+      // the row.
+      $(once('display', 'a.display-remove-link', context)).on(
+        'click',
+        function (event) {
+          const id = $(this).attr('id').replace('display-remove-link-', '');
+          $context.find(`#display-row-${id}`).hide();
+          $context.find(`#display-removed-${id}`).prop('checked', true);
+          event.preventDefault();
+        },
+      );
+    },
   };
+
+  /**
+   * Rearranges the filters.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach handlers to make it possible to rearrange the filters in the form
+   *   in question.
+   *   @see Drupal.viewsUi.RearrangeFilterHandler
+   */
   Drupal.behaviors.viewsUiRearrangeFilter = {
     attach(context) {
-      if (typeof Drupal.tableDrag === 'undefined' || typeof Drupal.tableDrag['views-rearrange-filters'] === 'undefined') {
+      // Only act on the rearrange filter form.
+      if (
+        typeof Drupal.tableDrag === 'undefined' ||
+        typeof Drupal.tableDrag['views-rearrange-filters'] === 'undefined'
+      ) {
         return;
       }
-
-      const table = once('views-rearrange-filters', '#views-rearrange-filters', context);
-      const operator = once('views-rearrange-filters', '.js-form-item-filter-groups-operator', context);
-
+      const table = once(
+        'views-rearrange-filters',
+        '#views-rearrange-filters',
+        context,
+      );
+      const operator = once(
+        'views-rearrange-filters',
+        '.js-form-item-filter-groups-operator',
+        context,
+      );
       if (table.length) {
         new Drupal.viewsUi.RearrangeFilterHandler($(table), $(operator));
       }
-    }
-
+    },
   };
-})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/views_ui/js/views_ui.listing.es6.js b/core/modules/views_ui/js/views_ui.listing.es6.js
deleted file mode 100644
index 24bafde92a2f..000000000000
--- a/core/modules/views_ui/js/views_ui.listing.es6.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * @file
- * Views listing behaviors.
- */
-
-(function ($, Drupal) {
-  /**
-   * Filters the view listing tables by a text input search string.
-   *
-   * Text search input: input.views-filter-text
-   * Target table:      input.views-filter-text[data-table]
-   * Source text:       [data-drupal-selector="views-table-filter-text-source"]
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the filter functionality to the views admin text search field.
-   */
-  Drupal.behaviors.viewTableFilterByText = {
-    attach(context, settings) {
-      const [input] = once('views-filter-text', 'input.views-filter-text');
-      if (!input) {
-        return;
-      }
-      const $table = $(input.getAttribute('data-table'));
-      let $rows;
-
-      function filterViewList(e) {
-        const query = e.target.value.toLowerCase();
-
-        function showViewRow(index, row) {
-          const sources = row.querySelectorAll(
-            '[data-drupal-selector="views-table-filter-text-source"]',
-          );
-          let sourcesConcat = '';
-          sources.forEach((item) => {
-            sourcesConcat += item.textContent;
-          });
-          const textMatch = sourcesConcat.toLowerCase().indexOf(query) !== -1;
-          $(row).closest('tr').toggle(textMatch);
-        }
-
-        // Filter if the length of the query is at least 2 characters.
-        if (query.length >= 2) {
-          $rows.each(showViewRow);
-        } else {
-          $rows.show();
-        }
-      }
-
-      if ($table.length) {
-        $rows = $table.find('tbody tr');
-        $(input).on('keyup', filterViewList);
-      }
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/modules/views_ui/js/views_ui.listing.js b/core/modules/views_ui/js/views_ui.listing.js
index 43be02e3e732..24bafde92a2f 100644
--- a/core/modules/views_ui/js/views_ui.listing.js
+++ b/core/modules/views_ui/js/views_ui.listing.js
@@ -1,19 +1,27 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Views listing behaviors.
+ */
 
 (function ($, Drupal) {
+  /**
+   * Filters the view listing tables by a text input search string.
+   *
+   * Text search input: input.views-filter-text
+   * Target table:      input.views-filter-text[data-table]
+   * Source text:       [data-drupal-selector="views-table-filter-text-source"]
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the filter functionality to the views admin text search field.
+   */
   Drupal.behaviors.viewTableFilterByText = {
     attach(context, settings) {
       const [input] = once('views-filter-text', 'input.views-filter-text');
-
       if (!input) {
         return;
       }
-
       const $table = $(input.getAttribute('data-table'));
       let $rows;
 
@@ -21,15 +29,18 @@
         const query = e.target.value.toLowerCase();
 
         function showViewRow(index, row) {
-          const sources = row.querySelectorAll('[data-drupal-selector="views-table-filter-text-source"]');
+          const sources = row.querySelectorAll(
+            '[data-drupal-selector="views-table-filter-text-source"]',
+          );
           let sourcesConcat = '';
-          sources.forEach(item => {
+          sources.forEach((item) => {
             sourcesConcat += item.textContent;
           });
           const textMatch = sourcesConcat.toLowerCase().indexOf(query) !== -1;
           $(row).closest('tr').toggle(textMatch);
         }
 
+        // Filter if the length of the query is at least 2 characters.
         if (query.length >= 2) {
           $rows.each(showViewRow);
         } else {
@@ -41,7 +52,6 @@
         $rows = $table.find('tbody tr');
         $(input).on('keyup', filterViewList);
       }
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/package.json b/core/package.json
index 9ebf6b22a99f..4007133ad522 100644
--- a/core/package.json
+++ b/core/package.json
@@ -8,22 +8,18 @@
     "node": ">= 16.0"
   },
   "scripts": {
-    "build": "yarn build:css & yarn build:js & yarn build:ckeditor5 & yarn vendor-update",
-    "watch": "yarn watch:css & yarn watch:js & yarn watch:ckeditor5",
+    "build": "yarn build:css & yarn build:ckeditor5 & yarn vendor-update",
+    "watch": "yarn watch:css & yarn watch:ckeditor5",
     "build:css": "node ./scripts/css/postcss-build.js",
     "watch:css": "node ./scripts/css/postcss-watch.js",
-    "build:js": "cross-env BABEL_ENV=legacy node ./scripts/js/babel-es6-build.js",
-    "build:js-dev": "cross-env NODE_ENV=development BABEL_ENV=legacy node ./scripts/js/babel-es6-build.js",
-    "watch:js": "cross-env BABEL_ENV=legacy node ./scripts/js/babel-es6-watch.js",
-    "watch:js-dev": "cross-env NODE_ENV=development BABEL_ENV=legacy node ./scripts/js/babel-es6-watch.js",
     "lint:core-js": "node ./node_modules/eslint/bin/eslint.js .",
     "lint:core-js-passing": "node ./node_modules/eslint/bin/eslint.js --quiet --config=.eslintrc.passing.json .",
     "lint:core-js-stats": "node ./node_modules/eslint/bin/eslint.js --format=./scripts/js/eslint-stats-by-type.js .",
     "lint:css": "stylelint \"**/*.css\"",
     "lint:css-checkstyle": "stylelint \"**/*.css\" --custom-formatter ./node_modules/stylelint-checkstyle-formatter/index.js",
     "lint:yaml": "node ./node_modules/eslint/bin/eslint.js --ext .yml .",
-    "test:nightwatch": "cross-env BABEL_ENV=development node -r dotenv-safe/config -r @babel/register ./node_modules/.bin/nightwatch --config ./tests/Drupal/Nightwatch/nightwatch.conf.js",
-    "prettier": "prettier --write \"./**/*.es6.js\" \"./tests/Drupal/Nightwatch/**/*.js\" \"./modules/ckeditor5/js/ckeditor5_plugins/**/*.js\"",
+    "test:nightwatch": "node -r dotenv-safe/config ./node_modules/.bin/nightwatch --config ./tests/Drupal/Nightwatch/nightwatch.conf.js",
+    "prettier": "prettier --write \"./**/*.js\"",
     "spellcheck": "cspell",
     "spellcheck:make-drupal-dict": "rm -f misc/cspell/dictionary.txt && touch misc/cspell/dictionary.txt && yarn -s spellcheck:core --unique --wordsOnly | tr '[:upper:]' '[:lower:]' | tr -d \\\\\\\\ | LC_ALL=C sort -u -o misc/cspell/dictionary.txt",
     "spellcheck:core": "cspell \"**/*\" \".*\" \"../composer/**/*\" \"../composer.json\"",
@@ -36,9 +32,6 @@
     "watch:ckeditor5-dev": "yarn watch:ckeditor5 --mode=development"
   },
   "devDependencies": {
-    "@babel/core": "^7.0.0",
-    "@babel/preset-env": "^7.0.0",
-    "@babel/register": "^7.7.7",
     "@ckeditor/ckeditor5-alignment": "~35.1.0",
     "@ckeditor/ckeditor5-basic-styles": "~35.1.0",
     "@ckeditor/ckeditor5-block-quote": "~35.1.0",
@@ -61,12 +54,10 @@
     "@ckeditor/ckeditor5-style": "~35.1.0",
     "@ckeditor/ckeditor5-table": "~35.1.0",
     "@drupal/once": "1.0.x",
-    "babel-plugin-add-header-comment": "^1.0.3",
     "backbone": "1.4.x",
     "chokidar": "^3.3.1",
     "chromedriver": "^98.0.1",
     "ckeditor5": "~35.1.0",
-    "cross-env": "^7.0.2",
     "cspell": "^6.0.0",
     "dotenv-safe": "^8.2.0",
     "eslint": "^8.9.0",
@@ -109,34 +100,6 @@
     "webpack": "^5.51.1",
     "webpack-cli": "^4.4.0"
   },
-  "//": "'development is the default environment, and legacy is for transpiling the old jQuery codebase",
-  "babel": {
-    "env": {
-      "development": {
-        "presets": [
-          [
-            "@babel/preset-env",
-            {
-              "modules": "commonjs",
-              "targets": {
-                "node": "current"
-              }
-            }
-          ]
-        ]
-      },
-      "legacy": {
-        "presets": [
-          [
-            "@babel/preset-env",
-            {
-              "modules": false
-            }
-          ]
-        ]
-      }
-    }
-  },
   "browserslist": [
     "last 2 Chrome major versions",
     "last 2 Firefox major versions",
diff --git a/core/profiles/demo_umami/themes/umami/js/classy/media_embed_ckeditor.theme.es6.js b/core/profiles/demo_umami/themes/umami/js/classy/media_embed_ckeditor.theme.es6.js
deleted file mode 100644
index a33d18ffcd3d..000000000000
--- a/core/profiles/demo_umami/themes/umami/js/classy/media_embed_ckeditor.theme.es6.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * @file
- * Classy theme overrides for the Media Embed CKEditor plugin.
- */
-
-((Drupal) => {
-  /**
-   * Themes the error displayed when the media embed preview fails.
-   *
-   * @param {string} error
-   *   The error message to display
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   *
-   * @see media-embed-error.html.twig
-   */
-  Drupal.theme.mediaEmbedPreviewError = () =>
-    `<div class="media-embed-error media-embed-error--preview-error">${Drupal.t(
-      'An error occurred while trying to preview the media. Please save your work and reload this page.',
-    )}</div>`;
-})(Drupal);
diff --git a/core/profiles/demo_umami/themes/umami/js/classy/media_embed_ckeditor.theme.js b/core/profiles/demo_umami/themes/umami/js/classy/media_embed_ckeditor.theme.js
index 19cc4ff77763..a33d18ffcd3d 100644
--- a/core/profiles/demo_umami/themes/umami/js/classy/media_embed_ckeditor.theme.js
+++ b/core/profiles/demo_umami/themes/umami/js/classy/media_embed_ckeditor.theme.js
@@ -1,10 +1,22 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Classy theme overrides for the Media Embed CKEditor plugin.
+ */
 
-(Drupal => {
-  Drupal.theme.mediaEmbedPreviewError = () => `<div class="media-embed-error media-embed-error--preview-error">${Drupal.t('An error occurred while trying to preview the media. Please save your work and reload this page.')}</div>`;
-})(Drupal);
\ No newline at end of file
+((Drupal) => {
+  /**
+   * Themes the error displayed when the media embed preview fails.
+   *
+   * @param {string} error
+   *   The error message to display
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   *
+   * @see media-embed-error.html.twig
+   */
+  Drupal.theme.mediaEmbedPreviewError = () =>
+    `<div class="media-embed-error media-embed-error--preview-error">${Drupal.t(
+      'An error occurred while trying to preview the media. Please save your work and reload this page.',
+    )}</div>`;
+})(Drupal);
diff --git a/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js b/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js
deleted file mode 100644
index e467f4a7eba7..000000000000
--- a/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * @file
- * This file is used to add any javascript that is needed for the main menu.
- */
-
-(function () {
-  const toggler = document.querySelector(
-    '[data-drupal-selector="menu-main-toggle"]',
-  );
-  const menu = document.querySelector('[data-drupal-selector="menu-main"]');
-
-  function toggleMenu() {
-    toggler.classList.toggle('menu-main-toggle--active');
-    menu.classList.toggle('menu-main--active');
-    return false;
-  }
-
-  toggler.addEventListener('click', toggleMenu);
-})();
diff --git a/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.js b/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.js
index faeec79da9b0..e467f4a7eba7 100644
--- a/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.js
+++ b/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.js
@@ -1,12 +1,12 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * This file is used to add any javascript that is needed for the main menu.
+ */
 
 (function () {
-  const toggler = document.querySelector('[data-drupal-selector="menu-main-toggle"]');
+  const toggler = document.querySelector(
+    '[data-drupal-selector="menu-main-toggle"]',
+  );
   const menu = document.querySelector('[data-drupal-selector="menu-main"]');
 
   function toggleMenu() {
@@ -16,4 +16,4 @@
   }
 
   toggler.addEventListener('click', toggleMenu);
-})();
\ No newline at end of file
+})();
diff --git a/core/scripts/css/postcss-build.js b/core/scripts/css/postcss-build.js
index e7420187b480..ce1eca458797 100644
--- a/core/scripts/css/postcss-build.js
+++ b/core/scripts/css/postcss-build.js
@@ -5,9 +5,9 @@
  *
  * Run build:css with --file to only parse a specific file. Using the --check
  * flag build:css can be run to check if files are compiled correctly.
- * @example <caption>Only process misc/drupal.es6.js and misc/drupal.init.es6.js</caption
+ * @example <caption>Only process misc/drupal.pcss.css and misc/drupal.init.pcss.css</caption>
  * yarn run build:css -- --file misc/drupal.pcss.css --file misc/drupal.init.pcss.css
- * @example <caption>Check if all files have been compiled correctly</caption
+ * @example <caption>Check if all files have been compiled correctly</caption>
  * yarn run build:css -- --check
  *
  * @internal This file is part of the core CSS build process and is only
diff --git a/core/scripts/dev/commit-code-check.sh b/core/scripts/dev/commit-code-check.sh
index f62076677218..d91ed13dce60 100755
--- a/core/scripts/dev/commit-code-check.sh
+++ b/core/scripts/dev/commit-code-check.sh
@@ -13,7 +13,6 @@
 # - PHPCS checks PHP and YAML files.
 # - PHPStan checks PHP files.
 # - ESLint checks JavaScript and YAML files.
-# - Checks .es6.js and .js files are equivalent.
 # - Stylelint checks CSS files.
 # - Checks .pcss.css and .css files are equivalent.
 
@@ -384,67 +383,17 @@
   ############################################################################
   ### JAVASCRIPT FILES
   ############################################################################
-  if [[ -f "$TOP_LEVEL/$FILE" ]] && [[ $FILE =~ \.js$ ]] && [[ ! $FILE =~ ^core/tests/Drupal/Nightwatch ]] && [[ ! $FILE =~ /tests/src/Nightwatch/ ]] && [[ ! $FILE =~ ^core/modules/ckeditor5/js/ckeditor5_plugins ]]; then
-    # Work out the root name of the JavaScript so we can ensure that the ES6
-    # version has been compiled correctly.
-    if [[ $FILE =~ \.es6\.js$ ]]; then
-      BASENAME=${FILE%.es6.js}
-      COMPILE_CHECK=1
-    else
-      BASENAME=${FILE%.js}
-      # We only need to compile check if the .es6.js file is not also
-      # changing. This is because the compile check will occur for the
-      # .es6.js file. This might occur if the compile scripts have changed.
-      contains_element "$BASENAME.es6.js" "${FILES[@]}"
-      HASES6=$?
-      if [ "$HASES6" -ne "0" ]; then
-        COMPILE_CHECK=1
-      else
-        COMPILE_CHECK=0
-      fi
-    fi
-    if [[ "$COMPILE_CHECK" == "1" ]] && [[ -f "$TOP_LEVEL/$BASENAME.es6.js" ]]; then
-      cd "$TOP_LEVEL/core"
-      yarn run build:js --check --file "$TOP_LEVEL/$BASENAME.es6.js"
+  if [[ -f "$TOP_LEVEL/$FILE" ]] && [[ $FILE =~ \.js$ ]]; then
+    # Check the coding standards.
+    if [[ -f ".eslintrc.passing.json" ]]; then
+      node ./node_modules/eslint/bin/eslint.js --quiet --config=.eslintrc.passing.json "$TOP_LEVEL/$FILE"
       CORRECTJS=$?
       if [ "$CORRECTJS" -ne "0" ]; then
-        # No need to write any output the yarn run command will do this for
-        # us.
-        STATUS=1
-      fi
-      # Check the coding standards.
-      if [[ -f ".eslintrc.passing.json" ]]; then
-        node ./node_modules/eslint/bin/eslint.js --quiet --config=.eslintrc.passing.json "$TOP_LEVEL/$BASENAME.es6.js"
-        CORRECTJS=$?
-        if [ "$CORRECTJS" -ne "0" ]; then
-          # No need to write any output the node command will do this for us.
-          STATUS=1
-        fi
-      fi
-      cd $TOP_LEVEL
-    else
-      # If there is no .es6.js file then there should be unless the .js is
-      # not really Drupal's.
-      if ! [[ "$FILE" =~ ^core/assets/vendor ]] && ! [[ "$FILE" =~ ^core/modules/ckeditor5/js/build ]] && ! [[ "$FILE" =~ ^core/scripts/js ]] && ! [[ "$FILE" =~ ^core/scripts/css ]] && ! [[ "$FILE" =~ webpack.config.js$ ]] && ! [[ -f "$TOP_LEVEL/$BASENAME.es6.js" ]] && ! [[ "$FILE" =~ core/modules/ckeditor5/tests/modules/ckeditor5_test/js/build/layercake.js ]]; then
-        printf "${red}FAILURE${reset} $FILE does not have a corresponding $BASENAME.es6.js\n"
+        # No need to write any output the node command will do this for us.
         STATUS=1
       fi
     fi
-  else
-    # Check coding standards of Nightwatch files.
-    if [[ -f "$TOP_LEVEL/$FILE" ]] && [[ $FILE =~ \.js$ ]]; then
-      cd "$TOP_LEVEL/core"
-      # Check the coding standards.
-      if [[ -f ".eslintrc.passing.json" ]]; then
-        node ./node_modules/eslint/bin/eslint.js --quiet --config=.eslintrc.passing.json "$TOP_LEVEL/$FILE"
-        CORRECTJS=$?
-        if [ "$CORRECTJS" -ne "0" ]; then
-          # No need to write any output the node command will do this for us.
-          STATUS=1
-        fi
-      fi
-      cd $TOP_LEVEL
-    fi
+    cd $TOP_LEVEL
   fi
 
   ############################################################################
diff --git a/core/scripts/js/babel-es6-build.js b/core/scripts/js/babel-es6-build.js
deleted file mode 100644
index 647bd870aefc..000000000000
--- a/core/scripts/js/babel-es6-build.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @file
- *
- * Provides the build:js command to compile *.es6.js files to ES5.
- *
- * Run build:js with --file to only parse a specific file. Using the --check
- * flag build:js can be run to check if files are compiled correctly.
- * @example <caption>Only process misc/drupal.es6.js and misc/drupal.init.es6.js</caption
- * yarn run build:js -- --file misc/drupal.es6.js --file misc/drupal.init.es6.js
- * @example <caption>Check if all files have been compiled correctly</caption
- * yarn run build:js -- --check
- *
- * @internal This file is part of the core javascript build process and is only
- * meant to be used in that context.
- */
-
-'use strict';
-
-const glob = require('glob');
-const argv = require('minimist')(process.argv.slice(2));
-const changeOrAdded = require('./changeOrAdded');
-const check = require('./check');
-const log = require('./log');
-
-console.warn('⚠️  yarn `build:js` command is deprecated in drupal:9.4.0 and will be removed from drupal:10.0.0. This command is no longer needed in Drupal 10.0.0 once https://www.drupal.org/project/drupal/issues/3278415 is committed.️');
-
-// Match only on .es6.js files.
-const fileMatch = './**/*.es6.js';
-// Ignore everything in node_modules
-const globOptions = {
-  ignore: './node_modules/**'
-};
-const processFiles = (error, filePaths) => {
-  if (error) {
-    process.exitCode = 1;
-  }
-  // Process all the found files.
-  let callback = changeOrAdded;
-  if (argv.check) {
-    callback = check;
-  }
-  filePaths.forEach(callback);
-};
-
-if (argv.file) {
-  processFiles(null, [].concat(argv.file));
-}
-else {
-  glob(fileMatch, globOptions, processFiles);
-}
-process.exitCode = 0;
diff --git a/core/scripts/js/babel-es6-watch.js b/core/scripts/js/babel-es6-watch.js
deleted file mode 100644
index 2fbcfe3196d1..000000000000
--- a/core/scripts/js/babel-es6-watch.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * @file
- *
- * Watch changes to *.es6.js files and compile them to ES5 during development.
- *
- * @internal This file is part of the core javascript build process and is only
- * meant to be used in that context.
- */
-
-'use strict';
-
-const fs = require('fs');
-const path = require('path');
-const chokidar = require('chokidar');
-
-const changeOrAdded = require('./changeOrAdded');
-const log = require('./log');
-
-console.warn('⚠️  yarn `watch:js` command is deprecated in drupal:9.4.0 and will be removed from drupal:10.0.0. This command is no longer needed in Drupal 10.0.0 once https://www.drupal.org/project/drupal/issues/3278415 is committed.️');
-
-// Match only on .es6.js files.
-const fileMatch = './**/*.es6.js';
-// Ignore everything in node_modules
-const watcher = chokidar.watch(fileMatch, {
-  ignoreInitial: true,
-  ignored: './node_modules/**'
-});
-
-const unlinkHandler = (err) => {
-  if (err) {
-    log(err);
-  }
-};
-
-// Watch for filesystem changes.
-watcher
-  .on('add', changeOrAdded)
-  .on('change', changeOrAdded)
-  .on('unlink', (filePath) => {
-    const fileName = filePath.slice(0, -7);
-    fs.stat(`${fileName}.js`, () => {
-      fs.unlink(`${fileName}.js`, unlinkHandler);
-    });
-  })
-  .on('ready', () => log(`Watching '${fileMatch}' for changes.`));
diff --git a/core/scripts/js/changeOrAdded.js b/core/scripts/js/changeOrAdded.js
deleted file mode 100644
index 18fd7106ec07..000000000000
--- a/core/scripts/js/changeOrAdded.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const fs = require('fs');
-const log = require('./log');
-const compile = require('./compile');
-
-module.exports = (filePath) => {
-  log(`'${filePath}' is being processed.`);
-  // Transform the file.
-  compile(filePath, function write(code) {
-    const fileName = filePath.slice(0, -7);
-    // Write the result to the filesystem.
-    fs.writeFile(`${fileName}.js`, code, () => {
-      log(`'${filePath}' is finished.`);
-    });
-  });
-}
diff --git a/core/scripts/js/check.js b/core/scripts/js/check.js
deleted file mode 100644
index 83196773e503..000000000000
--- a/core/scripts/js/check.js
+++ /dev/null
@@ -1,22 +0,0 @@
-const fs = require('fs');
-const log = require('./log');
-const compile = require('./compile');
-
-module.exports = (filePath) => {
-  log(`'${filePath}' is being checked.`);
-  // Transform the file.
-  compile(filePath, function check(code) {
-    const fileName = filePath.slice(0, -7);
-    fs.readFile(`${fileName}.js`, function read(err, data) {
-      if (err) {
-        log(err);
-        process.exitCode = 1;
-        return;
-      }
-      if (code !== data.toString()) {
-        log(`'${filePath}' is not updated.`);
-        process.exitCode = 1;
-      }
-    });
-  });
-}
diff --git a/core/scripts/js/compile.js b/core/scripts/js/compile.js
deleted file mode 100644
index 326c191b0c92..000000000000
--- a/core/scripts/js/compile.js
+++ /dev/null
@@ -1,30 +0,0 @@
-const log = require('./log');
-const babel = require('@babel/core');
-
-module.exports = (filePath, callback) => {
-  // Transform the file.
-  // Check process.env.NODE_ENV to see if we should create sourcemaps.
-  babel.transformFile(
-    filePath,
-    {
-      sourceMaps: process.env.NODE_ENV === 'development' ? 'inline' : false,
-      comments: false,
-      plugins: [
-        ['add-header-comment', {
-          'header': [
-            `DO NOT EDIT THIS FILE.\nSee the following change record for more information,\nhttps://www.drupal.org/node/2815083\n@preserve`
-          ]
-        }]
-      ]
-    },
-    (err, result) => {
-      if (err) {
-        log(err);
-        process.exitCode = 1;
-      }
-      else {
-        callback(result.code);
-      }
-    }
-  );
-};
diff --git a/core/tests/Drupal/KernelTests/Core/Theme/ConfirmClassyCopiesTest.php b/core/tests/Drupal/KernelTests/Core/Theme/ConfirmClassyCopiesTest.php
index 0fce544a1d05..05f04da05905 100644
--- a/core/tests/Drupal/KernelTests/Core/Theme/ConfirmClassyCopiesTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Theme/ConfirmClassyCopiesTest.php
@@ -151,7 +151,6 @@ public function providerTestClassyCopies() {
             'ui-dialog.css',
           ],
           'js' => [
-            'media_embed_ckeditor.theme.es6.js',
             'media_embed_ckeditor.theme.js',
           ],
           'images' => [
@@ -279,7 +278,6 @@ public function providerTestClassyCopies() {
             'ui-dialog.css',
           ],
           'js' => [
-            'media_embed_ckeditor.theme.es6.js',
             'media_embed_ckeditor.theme.js',
           ],
           'images' => [
@@ -418,8 +416,7 @@ protected function getClassyHash($type, $file) {
         'user.css' => '0ec6acc22567a7c9c228f04b5a97c711',
       ],
       'js' => [
-        'media_embed_ckeditor.theme.es6.js' => 'd9fa9e008aff8d4fb0401083bab0a1ad',
-        'media_embed_ckeditor.theme.js' => 'b2e705b4503be407a35692b272c7ed6a',
+        'media_embed_ckeditor.theme.js' => 'd9fa9e008aff8d4fb0401083bab0a1ad',
       ],
       'images' => [
         'application-octet-stream.png' => 'fef73511632890590b5ae0a13c99e4bf',
diff --git a/core/tests/Drupal/Nightwatch/Commands/drupalInstall.js b/core/tests/Drupal/Nightwatch/Commands/drupalInstall.js
index 73732164a8b7..d42047d0830f 100644
--- a/core/tests/Drupal/Nightwatch/Commands/drupalInstall.js
+++ b/core/tests/Drupal/Nightwatch/Commands/drupalInstall.js
@@ -1,6 +1,6 @@
-import { execSync } from 'child_process';
-import { URL } from 'url';
-import { commandAsWebserver } from '../globals';
+const { execSync } = require('child_process');
+const { URL } = require('url');
+const { commandAsWebserver } = require('../globals');
 
 /**
  * Installs a Drupal test site.
diff --git a/core/tests/Drupal/Nightwatch/Commands/drupalLoginAsAdmin.js b/core/tests/Drupal/Nightwatch/Commands/drupalLoginAsAdmin.js
index 833c31354217..390cf11d82c7 100644
--- a/core/tests/Drupal/Nightwatch/Commands/drupalLoginAsAdmin.js
+++ b/core/tests/Drupal/Nightwatch/Commands/drupalLoginAsAdmin.js
@@ -1,6 +1,6 @@
-import { execSync } from 'child_process';
-import { URL } from 'url';
-import { commandAsWebserver } from '../globals';
+const { execSync } = require('child_process');
+const { URL } = require('url');
+const { commandAsWebserver } = require('../globals');
 
 /**
  * Logs in as the admin user.
diff --git a/core/tests/Drupal/Nightwatch/Commands/drupalLogout.js b/core/tests/Drupal/Nightwatch/Commands/drupalLogout.js
index 866ba489f867..02f8b2598647 100644
--- a/core/tests/Drupal/Nightwatch/Commands/drupalLogout.js
+++ b/core/tests/Drupal/Nightwatch/Commands/drupalLogout.js
@@ -1,5 +1,5 @@
-import { execSync } from 'child_process';
-import { URL } from 'url';
+const { execSync } = require('child_process');
+const { URL } = require('url');
 
 /**
  * Logs out from a Drupal site.
diff --git a/core/tests/Drupal/Nightwatch/Commands/drupalUninstall.js b/core/tests/Drupal/Nightwatch/Commands/drupalUninstall.js
index 7170d62d5caa..d904f494ebf1 100644
--- a/core/tests/Drupal/Nightwatch/Commands/drupalUninstall.js
+++ b/core/tests/Drupal/Nightwatch/Commands/drupalUninstall.js
@@ -1,5 +1,5 @@
-import { execSync } from 'child_process';
-import { commandAsWebserver } from '../globals';
+const { execSync } = require('child_process');
+const { commandAsWebserver } = require('../globals');
 
 /**
  * Uninstalls a test Drupal site.
diff --git a/core/tests/Drupal/Nightwatch/Tests/jQueryUIPositionShimTest.js b/core/tests/Drupal/Nightwatch/Tests/jQueryUIPositionShimTest.js
index bfea5b6372e9..c013a52016d9 100644
--- a/core/tests/Drupal/Nightwatch/Tests/jQueryUIPositionShimTest.js
+++ b/core/tests/Drupal/Nightwatch/Tests/jQueryUIPositionShimTest.js
@@ -823,7 +823,7 @@ module.exports = {
            * @return {{horizontal: (*|string), verticalOffset: number, vertical: (*|string), horizontalOffset: number}}
            *   The horizontal and vertical alignment and offset values for the element.
            *
-           * @see core/misc/position.es6.js
+           * @see core/misc/position.js
            */
           const parseOffset = (offset, element) => {
             const regexHorizontal = /left|center|right/;
diff --git a/core/tests/Drupal/Nightwatch/globals.js b/core/tests/Drupal/Nightwatch/globals.js
index 9abe233e104e..55bda0be1bda 100644
--- a/core/tests/Drupal/Nightwatch/globals.js
+++ b/core/tests/Drupal/Nightwatch/globals.js
@@ -1,20 +1,17 @@
-import { spawn } from 'child_process';
-import path from 'path';
-import fs from 'fs';
-import mkdirp from 'mkdirp';
-import chromedriver from 'chromedriver';
-import nightwatchSettings from './nightwatch.conf';
+const { spawn } = require('child_process');
+const path = require('path');
+const fs = require('fs');
+const mkdirp = require('mkdirp');
+const chromedriver = require('chromedriver');
+const nightwatchSettings = require('./nightwatch.conf');
 
-export const commandAsWebserver = (command) => {
+const commandAsWebserver = (command) => {
   if (process.env.DRUPAL_TEST_WEBSERVER_USER) {
     return `sudo -u ${process.env.DRUPAL_TEST_WEBSERVER_USER} ${command}`;
   }
   return command;
 };
 
-export const drupalDbPrefix = null;
-export const drupalSitePath = null;
-
 module.exports = {
   before: (done) => {
     if (JSON.parse(process.env.DRUPAL_TEST_CHROMEDRIVER_AUTOSTART)) {
diff --git a/core/tests/Drupal/Nightwatch/nightwatch.conf.js b/core/tests/Drupal/Nightwatch/nightwatch.conf.js
index 46c672e3bc1e..4a121e635338 100644
--- a/core/tests/Drupal/Nightwatch/nightwatch.conf.js
+++ b/core/tests/Drupal/Nightwatch/nightwatch.conf.js
@@ -1,5 +1,5 @@
-import path from 'path';
-import glob from 'glob';
+const path = require('path');
+const glob = require('glob');
 
 // Find directories which have Nightwatch tests in them.
 const regex = /(.*\/?tests\/?.*\/Nightwatch)\/.*/g;
diff --git a/core/themes/claro/js/ajax.es6.js b/core/themes/claro/js/ajax.es6.js
deleted file mode 100644
index 587e262fe303..000000000000
--- a/core/themes/claro/js/ajax.es6.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * @file
- * Ajax theme overrides for Claro.
- */
-
-((Drupal) => {
-  /**
-   * Theme override of the ajax progress indicator for full screen.
-   *
-   * @return {string}
-   *   The HTML markup for the throbber.
-   */
-  Drupal.theme.ajaxProgressIndicatorFullscreen = () =>
-    '<div class="ajax-progress ajax-progress--fullscreen"><div class="ajax-progress__throbber ajax-progress__throbber--fullscreen">&nbsp;</div></div>';
-
-  /**
-   * Theme override of the ajax progress indicator.
-   *
-   * @param {string} message
-   *   The message shown on the UI.
-   * @return {string}
-   *   The HTML markup for the throbber.
-   */
-  Drupal.theme.ajaxProgressThrobber = (message) => {
-    // Build markup without adding extra white space since it affects rendering.
-    const messageMarkup =
-      typeof message === 'string'
-        ? Drupal.theme('ajaxProgressMessage', message)
-        : '';
-    const throbber = '<div class="ajax-progress__throbber">&nbsp;</div>';
-
-    return `<div class="ajax-progress ajax-progress--throbber">${throbber}${messageMarkup}</div>`;
-  };
-
-  /**
-   * Theme override of the ajax progress message.
-   *
-   * @param {string} message
-   *   The message shown on the UI.
-   * @return {string}
-   *   The HTML markup for the throbber.
-   */
-  Drupal.theme.ajaxProgressMessage = (message) =>
-    `<div class="ajax-progress__message">${message}</div>`;
-})(Drupal);
diff --git a/core/themes/claro/js/ajax.js b/core/themes/claro/js/ajax.js
index c84b742914c7..587e262fe303 100644
--- a/core/themes/claro/js/ajax.js
+++ b/core/themes/claro/js/ajax.js
@@ -1,18 +1,45 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Ajax theme overrides for Claro.
+ */
 
-(Drupal => {
-  Drupal.theme.ajaxProgressIndicatorFullscreen = () => '<div class="ajax-progress ajax-progress--fullscreen"><div class="ajax-progress__throbber ajax-progress__throbber--fullscreen">&nbsp;</div></div>';
+((Drupal) => {
+  /**
+   * Theme override of the ajax progress indicator for full screen.
+   *
+   * @return {string}
+   *   The HTML markup for the throbber.
+   */
+  Drupal.theme.ajaxProgressIndicatorFullscreen = () =>
+    '<div class="ajax-progress ajax-progress--fullscreen"><div class="ajax-progress__throbber ajax-progress__throbber--fullscreen">&nbsp;</div></div>';
 
-  Drupal.theme.ajaxProgressThrobber = message => {
-    const messageMarkup = typeof message === 'string' ? Drupal.theme('ajaxProgressMessage', message) : '';
+  /**
+   * Theme override of the ajax progress indicator.
+   *
+   * @param {string} message
+   *   The message shown on the UI.
+   * @return {string}
+   *   The HTML markup for the throbber.
+   */
+  Drupal.theme.ajaxProgressThrobber = (message) => {
+    // Build markup without adding extra white space since it affects rendering.
+    const messageMarkup =
+      typeof message === 'string'
+        ? Drupal.theme('ajaxProgressMessage', message)
+        : '';
     const throbber = '<div class="ajax-progress__throbber">&nbsp;</div>';
+
     return `<div class="ajax-progress ajax-progress--throbber">${throbber}${messageMarkup}</div>`;
   };
 
-  Drupal.theme.ajaxProgressMessage = message => `<div class="ajax-progress__message">${message}</div>`;
-})(Drupal);
\ No newline at end of file
+  /**
+   * Theme override of the ajax progress message.
+   *
+   * @param {string} message
+   *   The message shown on the UI.
+   * @return {string}
+   *   The HTML markup for the throbber.
+   */
+  Drupal.theme.ajaxProgressMessage = (message) =>
+    `<div class="ajax-progress__message">${message}</div>`;
+})(Drupal);
diff --git a/core/themes/claro/js/autocomplete.es6.js b/core/themes/claro/js/autocomplete.es6.js
deleted file mode 100644
index a7abf4da18e3..000000000000
--- a/core/themes/claro/js/autocomplete.es6.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @file
- * Claro's enhancement for autocomplete form element.
- */
-
-(($, Drupal, once) => {
-  Drupal.behaviors.claroAutoCompete = {
-    attach(context) {
-      once('claroAutoComplete', 'input.form-autocomplete', context).forEach(
-        (value) => {
-          const $input = $(value);
-          const timeout = 400;
-          let classRemoveTimeout;
-          const classRemove = ($autoCompleteElem) => {
-            $autoCompleteElem.removeClass('is-autocompleting');
-            $autoCompleteElem
-              .siblings('[data-drupal-selector="autocomplete-message"]')
-              .addClass('hidden');
-          };
-
-          $input.on(
-            'input autocompletesearch autocompleteresponses',
-            (event) => {
-              if (event && event.type && event.type === 'autocompletesearch') {
-                $(event.target).addClass('is-autocompleting');
-                $(event.target)
-                  .siblings('[data-drupal-selector="autocomplete-message"]')
-                  .removeClass('hidden');
-              }
-              clearTimeout(classRemoveTimeout);
-              classRemoveTimeout = setTimeout(
-                classRemove,
-                timeout,
-                $(event.target),
-              );
-            },
-          );
-        },
-      );
-    },
-  };
-})(jQuery, Drupal, once);
diff --git a/core/themes/claro/js/autocomplete.js b/core/themes/claro/js/autocomplete.js
index 003c5de05ecf..a7abf4da18e3 100644
--- a/core/themes/claro/js/autocomplete.js
+++ b/core/themes/claro/js/autocomplete.js
@@ -1,34 +1,42 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Claro's enhancement for autocomplete form element.
+ */
 
 (($, Drupal, once) => {
   Drupal.behaviors.claroAutoCompete = {
     attach(context) {
-      once('claroAutoComplete', 'input.form-autocomplete', context).forEach(value => {
-        const $input = $(value);
-        const timeout = 400;
-        let classRemoveTimeout;
-
-        const classRemove = $autoCompleteElem => {
-          $autoCompleteElem.removeClass('is-autocompleting');
-          $autoCompleteElem.siblings('[data-drupal-selector="autocomplete-message"]').addClass('hidden');
-        };
-
-        $input.on('input autocompletesearch autocompleteresponses', event => {
-          if (event && event.type && event.type === 'autocompletesearch') {
-            $(event.target).addClass('is-autocompleting');
-            $(event.target).siblings('[data-drupal-selector="autocomplete-message"]').removeClass('hidden');
-          }
-
-          clearTimeout(classRemoveTimeout);
-          classRemoveTimeout = setTimeout(classRemove, timeout, $(event.target));
-        });
-      });
-    }
+      once('claroAutoComplete', 'input.form-autocomplete', context).forEach(
+        (value) => {
+          const $input = $(value);
+          const timeout = 400;
+          let classRemoveTimeout;
+          const classRemove = ($autoCompleteElem) => {
+            $autoCompleteElem.removeClass('is-autocompleting');
+            $autoCompleteElem
+              .siblings('[data-drupal-selector="autocomplete-message"]')
+              .addClass('hidden');
+          };
 
+          $input.on(
+            'input autocompletesearch autocompleteresponses',
+            (event) => {
+              if (event && event.type && event.type === 'autocompletesearch') {
+                $(event.target).addClass('is-autocompleting');
+                $(event.target)
+                  .siblings('[data-drupal-selector="autocomplete-message"]')
+                  .removeClass('hidden');
+              }
+              clearTimeout(classRemoveTimeout);
+              classRemoveTimeout = setTimeout(
+                classRemove,
+                timeout,
+                $(event.target),
+              );
+            },
+          );
+        },
+      );
+    },
   };
-})(jQuery, Drupal, once);
\ No newline at end of file
+})(jQuery, Drupal, once);
diff --git a/core/themes/claro/js/checkbox.es6.js b/core/themes/claro/js/checkbox.es6.js
deleted file mode 100644
index 26243e7f74bd..000000000000
--- a/core/themes/claro/js/checkbox.es6.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * @file
- * Theme override for checkbox.
- */
-
-((Drupal) => {
-  /**
-   * Constructs a checkbox input element.
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   */
-  Drupal.theme.checkbox = () =>
-    '<input type="checkbox" class="form-checkbox form-boolean form-boolean--type-checkbox"/>';
-})(Drupal);
diff --git a/core/themes/claro/js/checkbox.js b/core/themes/claro/js/checkbox.js
index e2032acf910c..26243e7f74bd 100644
--- a/core/themes/claro/js/checkbox.js
+++ b/core/themes/claro/js/checkbox.js
@@ -1,10 +1,15 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Theme override for checkbox.
+ */
 
-(Drupal => {
-  Drupal.theme.checkbox = () => '<input type="checkbox" class="form-checkbox form-boolean form-boolean--type-checkbox"/>';
-})(Drupal);
\ No newline at end of file
+((Drupal) => {
+  /**
+   * Constructs a checkbox input element.
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   */
+  Drupal.theme.checkbox = () =>
+    '<input type="checkbox" class="form-checkbox form-boolean form-boolean--type-checkbox"/>';
+})(Drupal);
diff --git a/core/themes/claro/js/classy/media_embed_ckeditor.theme.es6.js b/core/themes/claro/js/classy/media_embed_ckeditor.theme.es6.js
deleted file mode 100644
index a33d18ffcd3d..000000000000
--- a/core/themes/claro/js/classy/media_embed_ckeditor.theme.es6.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * @file
- * Classy theme overrides for the Media Embed CKEditor plugin.
- */
-
-((Drupal) => {
-  /**
-   * Themes the error displayed when the media embed preview fails.
-   *
-   * @param {string} error
-   *   The error message to display
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   *
-   * @see media-embed-error.html.twig
-   */
-  Drupal.theme.mediaEmbedPreviewError = () =>
-    `<div class="media-embed-error media-embed-error--preview-error">${Drupal.t(
-      'An error occurred while trying to preview the media. Please save your work and reload this page.',
-    )}</div>`;
-})(Drupal);
diff --git a/core/themes/claro/js/classy/media_embed_ckeditor.theme.js b/core/themes/claro/js/classy/media_embed_ckeditor.theme.js
index 19cc4ff77763..a33d18ffcd3d 100644
--- a/core/themes/claro/js/classy/media_embed_ckeditor.theme.js
+++ b/core/themes/claro/js/classy/media_embed_ckeditor.theme.js
@@ -1,10 +1,22 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Classy theme overrides for the Media Embed CKEditor plugin.
+ */
 
-(Drupal => {
-  Drupal.theme.mediaEmbedPreviewError = () => `<div class="media-embed-error media-embed-error--preview-error">${Drupal.t('An error occurred while trying to preview the media. Please save your work and reload this page.')}</div>`;
-})(Drupal);
\ No newline at end of file
+((Drupal) => {
+  /**
+   * Themes the error displayed when the media embed preview fails.
+   *
+   * @param {string} error
+   *   The error message to display
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   *
+   * @see media-embed-error.html.twig
+   */
+  Drupal.theme.mediaEmbedPreviewError = () =>
+    `<div class="media-embed-error media-embed-error--preview-error">${Drupal.t(
+      'An error occurred while trying to preview the media. Please save your work and reload this page.',
+    )}</div>`;
+})(Drupal);
diff --git a/core/themes/claro/js/details.es6.js b/core/themes/claro/js/details.es6.js
deleted file mode 100644
index 05853d6915bf..000000000000
--- a/core/themes/claro/js/details.es6.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * @file
- * Claro's polyfill enhancements for HTML5 details.
- */
-
-(($, Modernizr, Drupal) => {
-  /**
-   * Workaround for Firefox.
-   *
-   * Firefox applies the focus state only for keyboard navigation.
-   * We have to manually trigger focus to make the behavior consistent across
-   * browsers.
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.claroDetails = {
-    attach(context) {
-      // The second argument of once() needs to be an instance of Element, but
-      // document is an instance of Document, replace it with the html Element.
-      $(once('claroDetails', context === document ? 'html' : context)).on(
-        'click',
-        (event) => {
-          if (event.target.nodeName === 'SUMMARY') {
-            $(event.target).trigger('focus');
-          }
-        },
-      );
-    },
-  };
-
-  /**
-   * Workaround for non-supporting browsers.
-   *
-   * This shim extends HTML5 Shiv used by core.
-   *
-   * HTML5 Shiv toggles focused details for hitting enter. We copy that for
-   * space key as well to make the behavior consistent across browsers.
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.claroDetailsToggleShim = {
-    attach(context) {
-      if (Modernizr.details || !Drupal.CollapsibleDetails.instances.length) {
-        return;
-      }
-
-      $(once('claroDetailsToggleShim', 'details .details-title', context)).on(
-        'keypress',
-        (event) => {
-          const keyCode = event.keyCode || event.charCode;
-          if (keyCode === 32) {
-            $(event.target).closest('summary').trigger('click');
-            event.preventDefault();
-          }
-        },
-      );
-    },
-  };
-
-  /**
-   * Theme override providing a wrapper for summarized details content.
-   *
-   * @return {string}
-   *   The markup for the element that will contain the summarized content.
-   */
-  Drupal.theme.detailsSummarizedContentWrapper = () =>
-    `<span class="claro-details__summary-summary"></span>`;
-
-  /**
-   * Theme override of summarized details content text.
-   *
-   * @param {string|null} [text]
-   *   (optional) The summarized content displayed in the summary.
-   * @return {string}
-   *   The formatted summarized content text.
-   */
-  Drupal.theme.detailsSummarizedContentText = (text) => text || '';
-})(jQuery, Modernizr, Drupal);
diff --git a/core/themes/claro/js/details.js b/core/themes/claro/js/details.js
index 903bde189a4f..05853d6915bf 100644
--- a/core/themes/claro/js/details.js
+++ b/core/themes/claro/js/details.js
@@ -1,40 +1,78 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Claro's polyfill enhancements for HTML5 details.
+ */
 
 (($, Modernizr, Drupal) => {
+  /**
+   * Workaround for Firefox.
+   *
+   * Firefox applies the focus state only for keyboard navigation.
+   * We have to manually trigger focus to make the behavior consistent across
+   * browsers.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.claroDetails = {
     attach(context) {
-      $(once('claroDetails', context === document ? 'html' : context)).on('click', event => {
-        if (event.target.nodeName === 'SUMMARY') {
-          $(event.target).trigger('focus');
-        }
-      });
-    }
-
+      // The second argument of once() needs to be an instance of Element, but
+      // document is an instance of Document, replace it with the html Element.
+      $(once('claroDetails', context === document ? 'html' : context)).on(
+        'click',
+        (event) => {
+          if (event.target.nodeName === 'SUMMARY') {
+            $(event.target).trigger('focus');
+          }
+        },
+      );
+    },
   };
+
+  /**
+   * Workaround for non-supporting browsers.
+   *
+   * This shim extends HTML5 Shiv used by core.
+   *
+   * HTML5 Shiv toggles focused details for hitting enter. We copy that for
+   * space key as well to make the behavior consistent across browsers.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.claroDetailsToggleShim = {
     attach(context) {
       if (Modernizr.details || !Drupal.CollapsibleDetails.instances.length) {
         return;
       }
 
-      $(once('claroDetailsToggleShim', 'details .details-title', context)).on('keypress', event => {
-        const keyCode = event.keyCode || event.charCode;
-
-        if (keyCode === 32) {
-          $(event.target).closest('summary').trigger('click');
-          event.preventDefault();
-        }
-      });
-    }
-
+      $(once('claroDetailsToggleShim', 'details .details-title', context)).on(
+        'keypress',
+        (event) => {
+          const keyCode = event.keyCode || event.charCode;
+          if (keyCode === 32) {
+            $(event.target).closest('summary').trigger('click');
+            event.preventDefault();
+          }
+        },
+      );
+    },
   };
 
-  Drupal.theme.detailsSummarizedContentWrapper = () => `<span class="claro-details__summary-summary"></span>`;
+  /**
+   * Theme override providing a wrapper for summarized details content.
+   *
+   * @return {string}
+   *   The markup for the element that will contain the summarized content.
+   */
+  Drupal.theme.detailsSummarizedContentWrapper = () =>
+    `<span class="claro-details__summary-summary"></span>`;
 
-  Drupal.theme.detailsSummarizedContentText = text => text || '';
-})(jQuery, Modernizr, Drupal);
\ No newline at end of file
+  /**
+   * Theme override of summarized details content text.
+   *
+   * @param {string|null} [text]
+   *   (optional) The summarized content displayed in the summary.
+   * @return {string}
+   *   The formatted summarized content text.
+   */
+  Drupal.theme.detailsSummarizedContentText = (text) => text || '';
+})(jQuery, Modernizr, Drupal);
diff --git a/core/themes/claro/js/dropbutton.es6.js b/core/themes/claro/js/dropbutton.es6.js
deleted file mode 100644
index 7fb87d60c25c..000000000000
--- a/core/themes/claro/js/dropbutton.es6.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * @file
- * Theme overrides for Claro.
- */
-
-((Drupal) => {
-  /**
-   * Overrides the dropbutton toggle markup.
-   *
-   * We have to keep the 'dropbutton-toggle' CSS class because the dropbutton JS
-   * operates with that one.
-   *
-   * @param {object} options
-   *   Options object.
-   * @param {string} [options.title]
-   *   The button text.
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   */
-  Drupal.theme.dropbuttonToggle = (options) =>
-    `<li class="dropbutton-toggle"><button type="button" class="dropbutton__toggle"><span class="visually-hidden">${options.title}</span></button></li>`;
-})(Drupal);
diff --git a/core/themes/claro/js/dropbutton.js b/core/themes/claro/js/dropbutton.js
index 108566a3eb0e..7fb87d60c25c 100644
--- a/core/themes/claro/js/dropbutton.js
+++ b/core/themes/claro/js/dropbutton.js
@@ -1,10 +1,23 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Theme overrides for Claro.
+ */
 
-(Drupal => {
-  Drupal.theme.dropbuttonToggle = options => `<li class="dropbutton-toggle"><button type="button" class="dropbutton__toggle"><span class="visually-hidden">${options.title}</span></button></li>`;
-})(Drupal);
\ No newline at end of file
+((Drupal) => {
+  /**
+   * Overrides the dropbutton toggle markup.
+   *
+   * We have to keep the 'dropbutton-toggle' CSS class because the dropbutton JS
+   * operates with that one.
+   *
+   * @param {object} options
+   *   Options object.
+   * @param {string} [options.title]
+   *   The button text.
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   */
+  Drupal.theme.dropbuttonToggle = (options) =>
+    `<li class="dropbutton-toggle"><button type="button" class="dropbutton__toggle"><span class="visually-hidden">${options.title}</span></button></li>`;
+})(Drupal);
diff --git a/core/themes/claro/js/media-library.ui.es6.js b/core/themes/claro/js/media-library.ui.es6.js
deleted file mode 100644
index 8eee2ad1fe18..000000000000
--- a/core/themes/claro/js/media-library.ui.es6.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * @file
- * Media Library overrides for Claro
- */
-(($, Drupal, window) => {
-  /**
-   * Update the media library selection when loaded or media items are selected.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches behavior to select media items.
-   */
-  Drupal.behaviors.MediaLibraryItemSelectionClaro = {
-    attach() {
-      // Move the selection count to the beginning of the button pane after it
-      // has been added to the Media Library dialog.
-      // @todo replace with theme function override in
-      //   https://drupal.org/node/3134526
-      if (!once('media-library-selection-info-claro-event', 'html').length) {
-        return;
-      }
-      $(window).on(
-        'dialog:aftercreate',
-        (event, dialog, $element, settings) => {
-          // Since the dialog HTML is not part of the context, we can't use
-          // context here.
-          const moveCounter = ($selectedCount, $buttonPane) => {
-            const $moveSelectedCount = $selectedCount.detach();
-            $buttonPane.prepend($moveSelectedCount);
-          };
-
-          const $buttonPane = $element
-            .closest('.media-library-widget-modal')
-            .find('.ui-dialog-buttonpane');
-          if (!$buttonPane.length) {
-            return;
-          }
-          const $selectedCount = $buttonPane.find(
-            '.js-media-library-selected-count',
-          );
-
-          // If the `selected` counter is already present, it can be moved from
-          // the end of the button pane to the beginning.
-          if ($selectedCount.length) {
-            moveCounter($selectedCount, $buttonPane);
-          } else {
-            // If the `selected` counter is not yet present, create a mutation
-            // observer that checks for items added to the button pane. As soon
-            // as the counter is added, move it from the end of the button pane
-            // to the beginning.
-            const selectedCountObserver = new MutationObserver(() => {
-              const $selectedCountFind = $buttonPane.find(
-                '.js-media-library-selected-count',
-              );
-              if ($selectedCountFind.length) {
-                moveCounter($selectedCountFind, $buttonPane);
-                selectedCountObserver.disconnect();
-              }
-            });
-            selectedCountObserver.observe($buttonPane[0], {
-              attributes: false,
-              childList: true,
-              characterData: false,
-              subtree: true,
-            });
-          }
-        },
-      );
-    },
-  };
-})(jQuery, Drupal, window);
diff --git a/core/themes/claro/js/media-library.ui.js b/core/themes/claro/js/media-library.ui.js
index 72c32cdb254d..8eee2ad1fe18 100644
--- a/core/themes/claro/js/media-library.ui.js
+++ b/core/themes/claro/js/media-library.ui.js
@@ -1,51 +1,72 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * @file
+ * Media Library overrides for Claro
+ */
 (($, Drupal, window) => {
+  /**
+   * Update the media library selection when loaded or media items are selected.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches behavior to select media items.
+   */
   Drupal.behaviors.MediaLibraryItemSelectionClaro = {
     attach() {
+      // Move the selection count to the beginning of the button pane after it
+      // has been added to the Media Library dialog.
+      // @todo replace with theme function override in
+      //   https://drupal.org/node/3134526
       if (!once('media-library-selection-info-claro-event', 'html').length) {
         return;
       }
+      $(window).on(
+        'dialog:aftercreate',
+        (event, dialog, $element, settings) => {
+          // Since the dialog HTML is not part of the context, we can't use
+          // context here.
+          const moveCounter = ($selectedCount, $buttonPane) => {
+            const $moveSelectedCount = $selectedCount.detach();
+            $buttonPane.prepend($moveSelectedCount);
+          };
 
-      $(window).on('dialog:aftercreate', (event, dialog, $element, settings) => {
-        const moveCounter = ($selectedCount, $buttonPane) => {
-          const $moveSelectedCount = $selectedCount.detach();
-          $buttonPane.prepend($moveSelectedCount);
-        };
-
-        const $buttonPane = $element.closest('.media-library-widget-modal').find('.ui-dialog-buttonpane');
-
-        if (!$buttonPane.length) {
-          return;
-        }
-
-        const $selectedCount = $buttonPane.find('.js-media-library-selected-count');
-
-        if ($selectedCount.length) {
-          moveCounter($selectedCount, $buttonPane);
-        } else {
-          const selectedCountObserver = new MutationObserver(() => {
-            const $selectedCountFind = $buttonPane.find('.js-media-library-selected-count');
-
-            if ($selectedCountFind.length) {
-              moveCounter($selectedCountFind, $buttonPane);
-              selectedCountObserver.disconnect();
-            }
-          });
-          selectedCountObserver.observe($buttonPane[0], {
-            attributes: false,
-            childList: true,
-            characterData: false,
-            subtree: true
-          });
-        }
-      });
-    }
+          const $buttonPane = $element
+            .closest('.media-library-widget-modal')
+            .find('.ui-dialog-buttonpane');
+          if (!$buttonPane.length) {
+            return;
+          }
+          const $selectedCount = $buttonPane.find(
+            '.js-media-library-selected-count',
+          );
 
+          // If the `selected` counter is already present, it can be moved from
+          // the end of the button pane to the beginning.
+          if ($selectedCount.length) {
+            moveCounter($selectedCount, $buttonPane);
+          } else {
+            // If the `selected` counter is not yet present, create a mutation
+            // observer that checks for items added to the button pane. As soon
+            // as the counter is added, move it from the end of the button pane
+            // to the beginning.
+            const selectedCountObserver = new MutationObserver(() => {
+              const $selectedCountFind = $buttonPane.find(
+                '.js-media-library-selected-count',
+              );
+              if ($selectedCountFind.length) {
+                moveCounter($selectedCountFind, $buttonPane);
+                selectedCountObserver.disconnect();
+              }
+            });
+            selectedCountObserver.observe($buttonPane[0], {
+              attributes: false,
+              childList: true,
+              characterData: false,
+              subtree: true,
+            });
+          }
+        },
+      );
+    },
   };
-})(jQuery, Drupal, window);
\ No newline at end of file
+})(jQuery, Drupal, window);
diff --git a/core/themes/claro/js/messages.es6.js b/core/themes/claro/js/messages.es6.js
deleted file mode 100644
index 196568742af7..000000000000
--- a/core/themes/claro/js/messages.es6.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @file
- * Message template overrides.
- */
-
-((Drupal) => {
-  /**
-   * Overrides message theme function.
-   *
-   * @param {object} message
-   *   The message object.
-   * @param {string} message.text
-   *   The message text.
-   * @param {object} options
-   *   The message context.
-   * @param {string} options.type
-   *   The message type.
-   * @param {string} options.id
-   *   ID of the message, for reference.
-   *
-   * @return {HTMLElement}
-   *   A DOM Node.
-   */
-  Drupal.theme.message = ({ text }, { type, id }) => {
-    const messagesTypes = Drupal.Message.getMessageTypeLabels();
-    const messageWrapper = document.createElement('div');
-
-    messageWrapper.setAttribute('class', `messages messages--${type}`);
-    messageWrapper.setAttribute(
-      'role',
-      type === 'error' || type === 'warning' ? 'alert' : 'status',
-    );
-    messageWrapper.setAttribute('aria-labelledby', `${id}-title`);
-    messageWrapper.setAttribute('data-drupal-message-id', id);
-    messageWrapper.setAttribute('data-drupal-message-type', type);
-
-    messageWrapper.innerHTML = `
-    <div class="messages__header">
-      <h2 id="${id}-title" class="messages__title">
-        ${messagesTypes[type]}
-      </h2>
-    </div>
-    <div class="messages__content">
-      ${text}
-    </div>
-  `;
-
-    return messageWrapper;
-  };
-})(Drupal);
diff --git a/core/themes/claro/js/messages.js b/core/themes/claro/js/messages.js
index d1dbcaaad9cc..196568742af7 100644
--- a/core/themes/claro/js/messages.js
+++ b/core/themes/claro/js/messages.js
@@ -1,26 +1,39 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Message template overrides.
+ */
 
-(Drupal => {
-  Drupal.theme.message = (_ref, _ref2) => {
-    let {
-      text
-    } = _ref;
-    let {
-      type,
-      id
-    } = _ref2;
+((Drupal) => {
+  /**
+   * Overrides message theme function.
+   *
+   * @param {object} message
+   *   The message object.
+   * @param {string} message.text
+   *   The message text.
+   * @param {object} options
+   *   The message context.
+   * @param {string} options.type
+   *   The message type.
+   * @param {string} options.id
+   *   ID of the message, for reference.
+   *
+   * @return {HTMLElement}
+   *   A DOM Node.
+   */
+  Drupal.theme.message = ({ text }, { type, id }) => {
     const messagesTypes = Drupal.Message.getMessageTypeLabels();
     const messageWrapper = document.createElement('div');
+
     messageWrapper.setAttribute('class', `messages messages--${type}`);
-    messageWrapper.setAttribute('role', type === 'error' || type === 'warning' ? 'alert' : 'status');
+    messageWrapper.setAttribute(
+      'role',
+      type === 'error' || type === 'warning' ? 'alert' : 'status',
+    );
     messageWrapper.setAttribute('aria-labelledby', `${id}-title`);
     messageWrapper.setAttribute('data-drupal-message-id', id);
     messageWrapper.setAttribute('data-drupal-message-type', type);
+
     messageWrapper.innerHTML = `
     <div class="messages__header">
       <h2 id="${id}-title" class="messages__title">
@@ -31,6 +44,7 @@
       ${text}
     </div>
   `;
+
     return messageWrapper;
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/themes/claro/js/mobile.install.es6.js b/core/themes/claro/js/mobile.install.es6.js
deleted file mode 100644
index a55e120b4523..000000000000
--- a/core/themes/claro/js/mobile.install.es6.js
+++ /dev/null
@@ -1,29 +0,0 @@
-(() => {
-  function findActiveStep(steps) {
-    for (let i = 0; i < steps.length; i++) {
-      if (steps[i].className === 'is-active') {
-        return i + 1;
-      }
-    }
-    // The final "Finished" step is never "active".
-    if (steps[steps.length - 1].className === 'done') {
-      return steps.length;
-    }
-    return 0;
-  }
-
-  function installStepsSetup() {
-    const steps = document.querySelectorAll('.task-list li');
-    if (steps.length) {
-      const header = document.querySelector('header[role="banner"]');
-      const stepIndicator = document.createElement('div');
-      stepIndicator.className = 'step-indicator';
-      stepIndicator.innerHTML = `${findActiveStep(steps)}/${steps.length}`;
-      header.appendChild(stepIndicator);
-    }
-  }
-
-  if (document.addEventListener) {
-    document.addEventListener('DOMContentLoaded', installStepsSetup);
-  }
-})();
diff --git a/core/themes/claro/js/mobile.install.js b/core/themes/claro/js/mobile.install.js
index 2dc3ae79741a..a55e120b4523 100644
--- a/core/themes/claro/js/mobile.install.js
+++ b/core/themes/claro/js/mobile.install.js
@@ -1,10 +1,3 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
 (() => {
   function findActiveStep(steps) {
     for (let i = 0; i < steps.length; i++) {
@@ -12,17 +5,15 @@
         return i + 1;
       }
     }
-
+    // The final "Finished" step is never "active".
     if (steps[steps.length - 1].className === 'done') {
       return steps.length;
     }
-
     return 0;
   }
 
   function installStepsSetup() {
     const steps = document.querySelectorAll('.task-list li');
-
     if (steps.length) {
       const header = document.querySelector('header[role="banner"]');
       const stepIndicator = document.createElement('div');
@@ -35,4 +26,4 @@
   if (document.addEventListener) {
     document.addEventListener('DOMContentLoaded', installStepsSetup);
   }
-})();
\ No newline at end of file
+})();
diff --git a/core/themes/claro/js/nav-tabs.es6.js b/core/themes/claro/js/nav-tabs.es6.js
deleted file mode 100644
index 1601e788b68e..000000000000
--- a/core/themes/claro/js/nav-tabs.es6.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * @file
- * Responsive navigation tabs.
- *
- * This also supports collapsible navigable is the 'is-collapsible' class is
- * added to the main element, and a target element is included.
- */
-(($, Drupal) => {
-  function init(tab) {
-    const $tab = $(tab);
-    const $target = $tab.find('[data-drupal-nav-tabs-target]');
-    const $active = $target.find('.js-active-tab');
-
-    const openMenu = () => {
-      $target.toggleClass('is-open');
-    };
-
-    const toggleOrder = (reset) => {
-      const current = $active.index();
-      const original = $active.data('original-order');
-
-      // Do not change order if already first or if already reset.
-      if (original === 0 || reset === (current === original)) {
-        return;
-      }
-
-      const siblings = {
-        first: '[data-original-order="0"]',
-        previous: `[data-original-order="${original - 1}"]`,
-      };
-
-      const $first = $target.find(siblings.first);
-      const $previous = $target.find(siblings.previous);
-
-      if (reset && current !== original) {
-        $active.insertAfter($previous);
-      } else if (!reset && current === original) {
-        $active.insertBefore($first);
-      }
-    };
-
-    const toggleCollapsed = () => {
-      if (window.matchMedia('(min-width: 48em)').matches) {
-        if ($tab.hasClass('is-horizontal') && !$tab.attr('data-width')) {
-          let width = 0;
-
-          $target.find('.js-tabs-link').each((index, value) => {
-            width += $(value).outerWidth();
-          });
-          $tab.attr('data-width', width);
-        }
-
-        // Collapse the tabs if the combined width of the tabs is greater than
-        // the width of the parent container.
-        const isHorizontal = $tab.attr('data-width') <= $tab.outerWidth();
-        $tab.toggleClass('is-horizontal', isHorizontal);
-        toggleOrder(isHorizontal);
-      } else {
-        toggleOrder(false);
-      }
-    };
-
-    $tab.addClass('position-container is-horizontal-enabled');
-
-    $target.find('.js-tab').each((index, element) => {
-      const $item = $(element);
-      $item.attr('data-original-order', $item.index());
-    });
-
-    $tab.on('click.tabs', '[data-drupal-nav-tabs-trigger]', openMenu);
-    $(window)
-      // @todo use a media query event listener https://www.drupal.org/project/drupal/issues/3225621
-      .on('resize.tabs', Drupal.debounce(toggleCollapsed, 150))
-      .trigger('resize.tabs');
-  }
-  /**
-   * Initialize the tabs JS.
-   */
-  Drupal.behaviors.navTabs = {
-    attach(context) {
-      once(
-        'nav-tabs',
-        '[data-drupal-nav-tabs].is-collapsible',
-        context,
-      ).forEach(init);
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/themes/claro/js/nav-tabs.js b/core/themes/claro/js/nav-tabs.js
index b714cc206f70..1601e788b68e 100644
--- a/core/themes/claro/js/nav-tabs.js
+++ b/core/themes/claro/js/nav-tabs.js
@@ -1,10 +1,10 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * @file
+ * Responsive navigation tabs.
+ *
+ * This also supports collapsible navigable is the 'is-collapsible' class is
+ * added to the main element, and a target element is included.
+ */
 (($, Drupal) => {
   function init(tab) {
     const $tab = $(tab);
@@ -15,18 +15,20 @@
       $target.toggleClass('is-open');
     };
 
-    const toggleOrder = reset => {
+    const toggleOrder = (reset) => {
       const current = $active.index();
       const original = $active.data('original-order');
 
+      // Do not change order if already first or if already reset.
       if (original === 0 || reset === (current === original)) {
         return;
       }
 
       const siblings = {
         first: '[data-original-order="0"]',
-        previous: `[data-original-order="${original - 1}"]`
+        previous: `[data-original-order="${original - 1}"]`,
       };
+
       const $first = $target.find(siblings.first);
       const $previous = $target.find(siblings.previous);
 
@@ -41,12 +43,15 @@
       if (window.matchMedia('(min-width: 48em)').matches) {
         if ($tab.hasClass('is-horizontal') && !$tab.attr('data-width')) {
           let width = 0;
+
           $target.find('.js-tabs-link').each((index, value) => {
             width += $(value).outerWidth();
           });
           $tab.attr('data-width', width);
         }
 
+        // Collapse the tabs if the combined width of the tabs is greater than
+        // the width of the parent container.
         const isHorizontal = $tab.attr('data-width') <= $tab.outerWidth();
         $tab.toggleClass('is-horizontal', isHorizontal);
         toggleOrder(isHorizontal);
@@ -56,18 +61,28 @@
     };
 
     $tab.addClass('position-container is-horizontal-enabled');
+
     $target.find('.js-tab').each((index, element) => {
       const $item = $(element);
       $item.attr('data-original-order', $item.index());
     });
+
     $tab.on('click.tabs', '[data-drupal-nav-tabs-trigger]', openMenu);
-    $(window).on('resize.tabs', Drupal.debounce(toggleCollapsed, 150)).trigger('resize.tabs');
+    $(window)
+      // @todo use a media query event listener https://www.drupal.org/project/drupal/issues/3225621
+      .on('resize.tabs', Drupal.debounce(toggleCollapsed, 150))
+      .trigger('resize.tabs');
   }
-
+  /**
+   * Initialize the tabs JS.
+   */
   Drupal.behaviors.navTabs = {
     attach(context) {
-      once('nav-tabs', '[data-drupal-nav-tabs].is-collapsible', context).forEach(init);
-    }
-
+      once(
+        'nav-tabs',
+        '[data-drupal-nav-tabs].is-collapsible',
+        context,
+      ).forEach(init);
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/themes/claro/js/responsive-details.es6.js b/core/themes/claro/js/responsive-details.es6.js
deleted file mode 100644
index 6daf4f235a6b..000000000000
--- a/core/themes/claro/js/responsive-details.es6.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @file
- * Provides responsive behaviors to HTML details elements.
- */
-
-(($, Drupal) => {
-  /**
-   * Initializes the responsive behaviors for details elements.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the responsive behavior to status report specific details elements.
-   */
-  Drupal.behaviors.responsiveDetails = {
-    attach(context) {
-      const details = once('responsive-details', 'details', context);
-
-      if (!details.length) {
-        return;
-      }
-
-      const $details = $(details);
-      const $summaries = $details.find('> summary');
-
-      function detailsToggle(matches) {
-        if (matches) {
-          $details.attr('open', true);
-          $summaries.attr('aria-expanded', true);
-          $summaries.on('click.details-open', false);
-        } else {
-          // If user explicitly opened one, leave it alone.
-          const $notPressed = $details
-            .find('> summary[aria-pressed!=true]')
-            .attr('aria-expanded', false);
-          $notPressed.parent('details').attr('open', false);
-          // After resize, allow user to close previously opened details.
-          $summaries.off('.details-open');
-        }
-      }
-
-      function handleDetailsMQ(event) {
-        detailsToggle(event.matches);
-      }
-
-      const mql = window.matchMedia('(min-width:48em)');
-      mql.addListener(handleDetailsMQ);
-      detailsToggle(mql.matches);
-    },
-  };
-})(jQuery, Drupal);
diff --git a/core/themes/claro/js/responsive-details.js b/core/themes/claro/js/responsive-details.js
index 4b4e6ba7fbe2..6daf4f235a6b 100644
--- a/core/themes/claro/js/responsive-details.js
+++ b/core/themes/claro/js/responsive-details.js
@@ -1,11 +1,17 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Provides responsive behaviors to HTML details elements.
+ */
 
 (($, Drupal) => {
+  /**
+   * Initializes the responsive behaviors for details elements.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the responsive behavior to status report specific details elements.
+   */
   Drupal.behaviors.responsiveDetails = {
     attach(context) {
       const details = once('responsive-details', 'details', context);
@@ -23,8 +29,12 @@
           $summaries.attr('aria-expanded', true);
           $summaries.on('click.details-open', false);
         } else {
-          const $notPressed = $details.find('> summary[aria-pressed!=true]').attr('aria-expanded', false);
+          // If user explicitly opened one, leave it alone.
+          const $notPressed = $details
+            .find('> summary[aria-pressed!=true]')
+            .attr('aria-expanded', false);
           $notPressed.parent('details').attr('open', false);
+          // After resize, allow user to close previously opened details.
           $summaries.off('.details-open');
         }
       }
@@ -36,7 +46,6 @@
       const mql = window.matchMedia('(min-width:48em)');
       mql.addListener(handleDetailsMQ);
       detailsToggle(mql.matches);
-    }
-
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/themes/claro/js/tabledrag.es6.js b/core/themes/claro/js/tabledrag.es6.js
deleted file mode 100644
index b6a9d331116b..000000000000
--- a/core/themes/claro/js/tabledrag.es6.js
+++ /dev/null
@@ -1,247 +0,0 @@
-/**
- * @file
- * tabledrag.js overrides and functionality extensions.
- */
-
-(($, Drupal) => {
-  /**
-   * Extends core's Tabledrag functionality.
-   *
-   * @type {Drupal~behavior}
-   */
-  Drupal.behaviors.claroTableDrag = {
-    attach(context, settings) {
-      /**
-       * Refactors the table row markup to improve item label text wrapping.
-       *
-       * This addresses an issue specific to item labels that are long enough
-       * to be wrapped to a new line. Without this fix, a new line may start
-       * at the beginning of the table row, instead of the expected behavior of
-       * starting at the x axis of the first line.
-       *
-       * Addressing this issue requires changing the structure of a tabledrag
-       * cell's first row.
-       * @example
-       *   <!-- Default tabledrag structure, which has the wrapping problem. -->
-       *   <tr class="draggable">
-       *     <td>
-       *       <!--
-       *         Indentations are next to each other because they are styled as
-       *         `float: left;`
-       *       -->
-       *       <div class="indentation"></div>
-       *       <div class="indentation"></div>
-       *       <a class="tabledrag-handle"></a>
-       *       <!-- If the text in this link wraps enough times that the element
-       *         is taller than the floated elements preceding it, some lines
-       *         will wrap to the beginning of the row instead of aligning with
-       *         the beginning of the link text.
-       *       -->
-       *       <a class="menu-item__link">A longer label that may require wrapping</a>
-       *     </td>
-       *     <!-- etc. -->
-       *   </tr>
-       * @example
-       * <!-- Claro tabledrag structure, this fixes the wrapping problem. -->
-       *   <tr class="draggable">
-       *     <td class="tabledrag-cell">
-       *       <div class="tabledrag-cell-content">
-       *          <!-- Indentations are next to each other because
-       *            .table-drag-cell-content is styled as `display: table-row;`
-       *            and .table-drag-cell-content > * is styled as
-       *            `display: table-cell;`
-       *          -->
-       *         <div class="indentation"></div>
-       *         <div class="indentation"></div>
-       *         <a class="tabledrag-handle"></a>
-       *         <div class="tabledrag-cell-content__item">
-       *           <!-- Placing the link inside a div styled as
-       *             `display: table-cell;` allows the text to wrap within
-       *             the boundaries of the "cell".
-       *           -->
-       *           <a class="menu-item__link">A longer label that may require wrapping</a>
-       *         </div>
-       *      </div>
-       *    </td>
-       *    <!-- additional <td> -->
-       *   </tr>
-       *
-       * @param {number} index
-       *   The index in the loop, as provided by `jQuery.each`.
-       * @param {HTMLElement} row
-       *   A draggable table row.
-       *
-       * @todo this may be removable as part of https://drupal.org/node/3083044
-       */
-      const createItemWrapBoundaries = (row) => {
-        const $row = $(row);
-        const $firstCell = $row
-          .find('td:first-of-type')
-          .eq(0)
-          .wrapInner(Drupal.theme('tableDragCellContentWrapper'))
-          .wrapInner(
-            $(Drupal.theme('tableDragCellItemsWrapper')).addClass(
-              'js-tabledrag-cell-content',
-            ),
-          );
-
-        const $targetElem = $firstCell.find('.js-tabledrag-cell-content');
-
-        // Move handle into the '.js-tabledrag-cell-content' target.
-        $targetElem
-          .eq(0)
-          .find(
-            '> .tabledrag-cell-content__item > .js-tabledrag-handle, > .tabledrag-cell-content__item > .js-indentation',
-          )
-          .prependTo($targetElem);
-      };
-
-      // Find each row in a draggable table and process it with
-      // createItemWrapBoundaries().
-      Object.keys(settings.tableDrag || {}).forEach((base) => {
-        once(
-          'claroTabledrag',
-          $(context)
-            .find(`#${base}`)
-            .find('> tr.draggable, > tbody > tr.draggable'),
-        ).forEach(createItemWrapBoundaries);
-      });
-    },
-  };
-  $.extend(Drupal.tableDrag.prototype.row.prototype, {
-    /**
-     * Add an asterisk or other marker to the changed row.
-     *
-     * @todo this may be removable as part of https://drupal.org/node/3084910
-     */
-    markChanged() {
-      const marker = $(Drupal.theme('tableDragChangedMarker')).addClass(
-        'js-tabledrag-changed-marker',
-      );
-      const cell = $(this.element).find('td:first-of-type');
-      if (cell.find('.js-tabledrag-changed-marker').length === 0) {
-        cell.find('.js-tabledrag-handle').after(marker);
-      }
-    },
-
-    /**
-     * Moves added indents into Claro's wrapper element.
-     *
-     * For indents to work properly, they must be inside the wrapper
-     * created by createItemWrapBoundaries(). When an indent is added via
-     * dragging, core's tabledrag functionality does not add it inside the
-     * wrapper. This function fires immediately after an indent is added, which
-     * moves the indent into that wrapper.
-     *
-     * @see Drupal.tableDrag.prototype.row.prototype.indent
-     *
-     * @todo this may be removable as part of https://drupal.org/node/3083044
-     */
-    onIndent() {
-      $(this.table)
-        .find('.tabledrag-cell > .js-indentation')
-        .each((index, indentToMove) => {
-          const $indentToMove = $(indentToMove);
-          const $cellContent = $indentToMove.siblings(
-            '.tabledrag-cell-content',
-          );
-          $indentToMove.prependTo($cellContent);
-        });
-    },
-  });
-
-  $.extend(
-    Drupal.theme,
-    /** @lends Drupal.theme */ {
-      /**
-       * Constructs the table drag changed marker.
-       *
-       * @return {string}
-       *   Markup for the indentation.
-       */
-      tableDragIndentation() {
-        return '<div class="js-indentation indentation"><svg xmlns="http://www.w3.org/2000/svg" class="tree" width="25" height="25" viewBox="0 0 25 25"><path class="tree__item tree__item-child-ltr tree__item-child-last-ltr tree__item-horizontal tree__item-horizontal-right" d="M12,12.5 H25" stroke="#888"/><path class="tree__item tree__item-child-rtl tree__item-child-last-rtl tree__item-horizontal tree__horizontal-left" d="M0,12.5 H13" stroke="#888"/><path class="tree__item tree__item-child-ltr tree__item-child-rtl tree__item-child-last-ltr tree__item-child-last-rtl tree__vertical tree__vertical-top" d="M12.5,12 v-99" stroke="#888"/><path class="tree__item tree__item-child-ltr tree__item-child-rtl tree__vertical tree__vertical-bottom" d="M12.5,12 v99" stroke="#888"/></svg></div>';
-      },
-
-      /**
-       * Constructs the table drag changed warning.
-       *
-       * @return {string}
-       *   Markup for the warning.
-       */
-      tableDragChangedWarning() {
-        return `<div class="tabledrag-changed-warning messages messages--warning" role="alert">${Drupal.theme(
-          'tableDragChangedMarker',
-        )} ${Drupal.t('You have unsaved changes.')}</div>`;
-      },
-
-      /**
-       * Constructs the table drag handle.
-       *
-       * @return {string}
-       *   A string representing a DOM fragment.
-       */
-      tableDragHandle: () =>
-        `<a href="#" title="${Drupal.t(
-          'Drag to re-order',
-        )}" class="tabledrag-handle js-tabledrag-handle"></a>`,
-
-      /**
-       * The button for toggling table row weight visibility.
-       *
-       * @return {string}
-       *   HTML markup for the weight toggle button and its container.
-       */
-      tableDragToggle: () =>
-        `<div class="tabledrag-toggle-weight-wrapper" data-drupal-selector="tabledrag-toggle-weight-wrapper">
-            <button type="button" class="link action-link tabledrag-toggle-weight" data-drupal-selector="tabledrag-toggle-weight"></button>
-            </div>`,
-
-      /**
-       * Constructs contents of the toggle weight button.
-       *
-       * @param {boolean} show
-       *   If the table weights are currently displayed.
-       *
-       * @return {string}
-       *  HTML markup for the weight toggle button content.
-       */
-      toggleButtonContent: (show) => {
-        const classes = [
-          'action-link',
-          'action-link--extrasmall',
-          'tabledrag-toggle-weight',
-        ];
-        let text = '';
-        if (show) {
-          classes.push('action-link--icon-hide');
-          text = Drupal.t('Hide row weights');
-        } else {
-          classes.push('action-link--icon-show');
-          text = Drupal.t('Show row weights');
-        }
-        return `<span class="${classes.join(' ')}">${text}</a>`;
-      },
-
-      /**
-       * Constructs the wrapper for the initial content of the drag cell.
-       *
-       * @return {string}
-       *   A string representing a DOM fragment.
-       */
-      tableDragCellContentWrapper() {
-        return '<div class="tabledrag-cell-content__item"></div>';
-      },
-
-      /**
-       * Constructs the wrapper for the whole table drag cell.
-       *
-       * @return {string}
-       *   A string representing a DOM fragment.
-       */
-      tableDragCellItemsWrapper() {
-        return '<div class="tabledrag-cell-content"></div>';
-      },
-    },
-  );
-})(jQuery, Drupal);
diff --git a/core/themes/claro/js/tabledrag.js b/core/themes/claro/js/tabledrag.js
index 2ff90e180ab2..b6a9d331116b 100644
--- a/core/themes/claro/js/tabledrag.js
+++ b/core/themes/claro/js/tabledrag.js
@@ -1,80 +1,247 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * tabledrag.js overrides and functionality extensions.
+ */
 
 (($, Drupal) => {
+  /**
+   * Extends core's Tabledrag functionality.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.claroTableDrag = {
     attach(context, settings) {
-      const createItemWrapBoundaries = row => {
+      /**
+       * Refactors the table row markup to improve item label text wrapping.
+       *
+       * This addresses an issue specific to item labels that are long enough
+       * to be wrapped to a new line. Without this fix, a new line may start
+       * at the beginning of the table row, instead of the expected behavior of
+       * starting at the x axis of the first line.
+       *
+       * Addressing this issue requires changing the structure of a tabledrag
+       * cell's first row.
+       * @example
+       *   <!-- Default tabledrag structure, which has the wrapping problem. -->
+       *   <tr class="draggable">
+       *     <td>
+       *       <!--
+       *         Indentations are next to each other because they are styled as
+       *         `float: left;`
+       *       -->
+       *       <div class="indentation"></div>
+       *       <div class="indentation"></div>
+       *       <a class="tabledrag-handle"></a>
+       *       <!-- If the text in this link wraps enough times that the element
+       *         is taller than the floated elements preceding it, some lines
+       *         will wrap to the beginning of the row instead of aligning with
+       *         the beginning of the link text.
+       *       -->
+       *       <a class="menu-item__link">A longer label that may require wrapping</a>
+       *     </td>
+       *     <!-- etc. -->
+       *   </tr>
+       * @example
+       * <!-- Claro tabledrag structure, this fixes the wrapping problem. -->
+       *   <tr class="draggable">
+       *     <td class="tabledrag-cell">
+       *       <div class="tabledrag-cell-content">
+       *          <!-- Indentations are next to each other because
+       *            .table-drag-cell-content is styled as `display: table-row;`
+       *            and .table-drag-cell-content > * is styled as
+       *            `display: table-cell;`
+       *          -->
+       *         <div class="indentation"></div>
+       *         <div class="indentation"></div>
+       *         <a class="tabledrag-handle"></a>
+       *         <div class="tabledrag-cell-content__item">
+       *           <!-- Placing the link inside a div styled as
+       *             `display: table-cell;` allows the text to wrap within
+       *             the boundaries of the "cell".
+       *           -->
+       *           <a class="menu-item__link">A longer label that may require wrapping</a>
+       *         </div>
+       *      </div>
+       *    </td>
+       *    <!-- additional <td> -->
+       *   </tr>
+       *
+       * @param {number} index
+       *   The index in the loop, as provided by `jQuery.each`.
+       * @param {HTMLElement} row
+       *   A draggable table row.
+       *
+       * @todo this may be removable as part of https://drupal.org/node/3083044
+       */
+      const createItemWrapBoundaries = (row) => {
         const $row = $(row);
-        const $firstCell = $row.find('td:first-of-type').eq(0).wrapInner(Drupal.theme('tableDragCellContentWrapper')).wrapInner($(Drupal.theme('tableDragCellItemsWrapper')).addClass('js-tabledrag-cell-content'));
+        const $firstCell = $row
+          .find('td:first-of-type')
+          .eq(0)
+          .wrapInner(Drupal.theme('tableDragCellContentWrapper'))
+          .wrapInner(
+            $(Drupal.theme('tableDragCellItemsWrapper')).addClass(
+              'js-tabledrag-cell-content',
+            ),
+          );
+
         const $targetElem = $firstCell.find('.js-tabledrag-cell-content');
-        $targetElem.eq(0).find('> .tabledrag-cell-content__item > .js-tabledrag-handle, > .tabledrag-cell-content__item > .js-indentation').prependTo($targetElem);
+
+        // Move handle into the '.js-tabledrag-cell-content' target.
+        $targetElem
+          .eq(0)
+          .find(
+            '> .tabledrag-cell-content__item > .js-tabledrag-handle, > .tabledrag-cell-content__item > .js-indentation',
+          )
+          .prependTo($targetElem);
       };
 
-      Object.keys(settings.tableDrag || {}).forEach(base => {
-        once('claroTabledrag', $(context).find(`#${base}`).find('> tr.draggable, > tbody > tr.draggable')).forEach(createItemWrapBoundaries);
+      // Find each row in a draggable table and process it with
+      // createItemWrapBoundaries().
+      Object.keys(settings.tableDrag || {}).forEach((base) => {
+        once(
+          'claroTabledrag',
+          $(context)
+            .find(`#${base}`)
+            .find('> tr.draggable, > tbody > tr.draggable'),
+        ).forEach(createItemWrapBoundaries);
       });
-    }
-
+    },
   };
   $.extend(Drupal.tableDrag.prototype.row.prototype, {
+    /**
+     * Add an asterisk or other marker to the changed row.
+     *
+     * @todo this may be removable as part of https://drupal.org/node/3084910
+     */
     markChanged() {
-      const marker = $(Drupal.theme('tableDragChangedMarker')).addClass('js-tabledrag-changed-marker');
+      const marker = $(Drupal.theme('tableDragChangedMarker')).addClass(
+        'js-tabledrag-changed-marker',
+      );
       const cell = $(this.element).find('td:first-of-type');
-
       if (cell.find('.js-tabledrag-changed-marker').length === 0) {
         cell.find('.js-tabledrag-handle').after(marker);
       }
     },
 
+    /**
+     * Moves added indents into Claro's wrapper element.
+     *
+     * For indents to work properly, they must be inside the wrapper
+     * created by createItemWrapBoundaries(). When an indent is added via
+     * dragging, core's tabledrag functionality does not add it inside the
+     * wrapper. This function fires immediately after an indent is added, which
+     * moves the indent into that wrapper.
+     *
+     * @see Drupal.tableDrag.prototype.row.prototype.indent
+     *
+     * @todo this may be removable as part of https://drupal.org/node/3083044
+     */
     onIndent() {
-      $(this.table).find('.tabledrag-cell > .js-indentation').each((index, indentToMove) => {
-        const $indentToMove = $(indentToMove);
-        const $cellContent = $indentToMove.siblings('.tabledrag-cell-content');
-        $indentToMove.prependTo($cellContent);
-      });
-    }
-
-  });
-  $.extend(Drupal.theme, {
-    tableDragIndentation() {
-      return '<div class="js-indentation indentation"><svg xmlns="http://www.w3.org/2000/svg" class="tree" width="25" height="25" viewBox="0 0 25 25"><path class="tree__item tree__item-child-ltr tree__item-child-last-ltr tree__item-horizontal tree__item-horizontal-right" d="M12,12.5 H25" stroke="#888"/><path class="tree__item tree__item-child-rtl tree__item-child-last-rtl tree__item-horizontal tree__horizontal-left" d="M0,12.5 H13" stroke="#888"/><path class="tree__item tree__item-child-ltr tree__item-child-rtl tree__item-child-last-ltr tree__item-child-last-rtl tree__vertical tree__vertical-top" d="M12.5,12 v-99" stroke="#888"/><path class="tree__item tree__item-child-ltr tree__item-child-rtl tree__vertical tree__vertical-bottom" d="M12.5,12 v99" stroke="#888"/></svg></div>';
+      $(this.table)
+        .find('.tabledrag-cell > .js-indentation')
+        .each((index, indentToMove) => {
+          const $indentToMove = $(indentToMove);
+          const $cellContent = $indentToMove.siblings(
+            '.tabledrag-cell-content',
+          );
+          $indentToMove.prependTo($cellContent);
+        });
     },
+  });
 
-    tableDragChangedWarning() {
-      return `<div class="tabledrag-changed-warning messages messages--warning" role="alert">${Drupal.theme('tableDragChangedMarker')} ${Drupal.t('You have unsaved changes.')}</div>`;
-    },
+  $.extend(
+    Drupal.theme,
+    /** @lends Drupal.theme */ {
+      /**
+       * Constructs the table drag changed marker.
+       *
+       * @return {string}
+       *   Markup for the indentation.
+       */
+      tableDragIndentation() {
+        return '<div class="js-indentation indentation"><svg xmlns="http://www.w3.org/2000/svg" class="tree" width="25" height="25" viewBox="0 0 25 25"><path class="tree__item tree__item-child-ltr tree__item-child-last-ltr tree__item-horizontal tree__item-horizontal-right" d="M12,12.5 H25" stroke="#888"/><path class="tree__item tree__item-child-rtl tree__item-child-last-rtl tree__item-horizontal tree__horizontal-left" d="M0,12.5 H13" stroke="#888"/><path class="tree__item tree__item-child-ltr tree__item-child-rtl tree__item-child-last-ltr tree__item-child-last-rtl tree__vertical tree__vertical-top" d="M12.5,12 v-99" stroke="#888"/><path class="tree__item tree__item-child-ltr tree__item-child-rtl tree__vertical tree__vertical-bottom" d="M12.5,12 v99" stroke="#888"/></svg></div>';
+      },
+
+      /**
+       * Constructs the table drag changed warning.
+       *
+       * @return {string}
+       *   Markup for the warning.
+       */
+      tableDragChangedWarning() {
+        return `<div class="tabledrag-changed-warning messages messages--warning" role="alert">${Drupal.theme(
+          'tableDragChangedMarker',
+        )} ${Drupal.t('You have unsaved changes.')}</div>`;
+      },
 
-    tableDragHandle: () => `<a href="#" title="${Drupal.t('Drag to re-order')}" class="tabledrag-handle js-tabledrag-handle"></a>`,
-    tableDragToggle: () => `<div class="tabledrag-toggle-weight-wrapper" data-drupal-selector="tabledrag-toggle-weight-wrapper">
+      /**
+       * Constructs the table drag handle.
+       *
+       * @return {string}
+       *   A string representing a DOM fragment.
+       */
+      tableDragHandle: () =>
+        `<a href="#" title="${Drupal.t(
+          'Drag to re-order',
+        )}" class="tabledrag-handle js-tabledrag-handle"></a>`,
+
+      /**
+       * The button for toggling table row weight visibility.
+       *
+       * @return {string}
+       *   HTML markup for the weight toggle button and its container.
+       */
+      tableDragToggle: () =>
+        `<div class="tabledrag-toggle-weight-wrapper" data-drupal-selector="tabledrag-toggle-weight-wrapper">
             <button type="button" class="link action-link tabledrag-toggle-weight" data-drupal-selector="tabledrag-toggle-weight"></button>
             </div>`,
-    toggleButtonContent: show => {
-      const classes = ['action-link', 'action-link--extrasmall', 'tabledrag-toggle-weight'];
-      let text = '';
 
-      if (show) {
-        classes.push('action-link--icon-hide');
-        text = Drupal.t('Hide row weights');
-      } else {
-        classes.push('action-link--icon-show');
-        text = Drupal.t('Show row weights');
-      }
+      /**
+       * Constructs contents of the toggle weight button.
+       *
+       * @param {boolean} show
+       *   If the table weights are currently displayed.
+       *
+       * @return {string}
+       *  HTML markup for the weight toggle button content.
+       */
+      toggleButtonContent: (show) => {
+        const classes = [
+          'action-link',
+          'action-link--extrasmall',
+          'tabledrag-toggle-weight',
+        ];
+        let text = '';
+        if (show) {
+          classes.push('action-link--icon-hide');
+          text = Drupal.t('Hide row weights');
+        } else {
+          classes.push('action-link--icon-show');
+          text = Drupal.t('Show row weights');
+        }
+        return `<span class="${classes.join(' ')}">${text}</a>`;
+      },
 
-      return `<span class="${classes.join(' ')}">${text}</a>`;
-    },
+      /**
+       * Constructs the wrapper for the initial content of the drag cell.
+       *
+       * @return {string}
+       *   A string representing a DOM fragment.
+       */
+      tableDragCellContentWrapper() {
+        return '<div class="tabledrag-cell-content__item"></div>';
+      },
 
-    tableDragCellContentWrapper() {
-      return '<div class="tabledrag-cell-content__item"></div>';
+      /**
+       * Constructs the wrapper for the whole table drag cell.
+       *
+       * @return {string}
+       *   A string representing a DOM fragment.
+       */
+      tableDragCellItemsWrapper() {
+        return '<div class="tabledrag-cell-content"></div>';
+      },
     },
-
-    tableDragCellItemsWrapper() {
-      return '<div class="tabledrag-cell-content"></div>';
-    }
-
-  });
-})(jQuery, Drupal);
\ No newline at end of file
+  );
+})(jQuery, Drupal);
diff --git a/core/themes/claro/js/user.theme.es6.js b/core/themes/claro/js/user.theme.es6.js
deleted file mode 100644
index 341d3084593d..000000000000
--- a/core/themes/claro/js/user.theme.es6.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * @file
- * Password confirm widget template overrides.
- */
-
-((Drupal) => {
-  Object.assign(Drupal.user.password.css, {
-    passwordWeak: 'is-weak',
-    widgetInitial: 'is-initial',
-    passwordEmpty: 'is-password-empty',
-    passwordFilled: 'is-password-filled',
-    confirmEmpty: 'is-confirm-empty',
-    confirmFilled: 'is-confirm-filled',
-  });
-
-  /**
-   * Constructs a password confirm message element.
-   *
-   * @param {object} passwordSettings
-   *   An object containing password related settings and translated text to
-   *   display.
-   * @param {string} passwordSettings.confirmTitle
-   *   The translated confirm description that labels the actual confirm text.
-   *
-   * @return {string}
-   *   Markup for the password confirm message.
-   */
-  Drupal.theme.passwordConfirmMessage = ({ confirmTitle }) => {
-    const confirmTextWrapper =
-      '<span class="password-match-message__text" data-drupal-selector="password-match-status-text"></span>';
-    return `<div aria-live="polite" aria-atomic="true" class="password-match-message" data-drupal-selector="password-confirm-message">${confirmTitle} ${confirmTextWrapper}</div>`;
-  };
-
-  /**
-   * Constructs a password strength message.
-   *
-   * @param {object} passwordSettings
-   *   An object containing password related settings and translated text to
-   *   display.
-   * @param {string} passwordSettings.strengthTitle
-   *   The title that precedes the strength text.
-   *
-   * @return {string}
-   *   Markup for the password strength indicator.
-   */
-  Drupal.theme.passwordStrength = ({ strengthTitle }) => {
-    const strengthBar =
-      '<div class="password-strength__bar" data-drupal-selector="password-strength-indicator"></div>';
-    const strengthText =
-      '<span class="password-strength__text" data-drupal-selector="password-strength-text"></span>';
-    return `
-      <div class="password-strength">
-        <div class="password-strength__track" data-drupal-selector="password-strength-meter">${strengthBar}</div>
-        <div aria-live="polite" aria-atomic="true" class="password-strength__title">${strengthTitle} ${strengthText}</div>
-      </div>
-    `;
-  };
-
-  /**
-   * Constructs password suggestions tips.
-   *
-   * @param {object} passwordSettings
-   *   An object containing password related settings and translated tex  t to
-   *   display.
-   * @param {string} passwordSettings.hasWeaknesses
-   *   The title that precedes tips.
-   * @param {Array.<string>} tips
-   *   Array containing the tips.
-   *
-   * @return {string}
-   *   Markup for the password suggestions.
-   */
-  Drupal.theme.passwordSuggestions = ({ hasWeaknesses }, tips) =>
-    `<div class="password-suggestions">${
-      tips.length
-        ? `${hasWeaknesses}<ul class="password-suggestions__tips"><li class="password-suggestions__tip">${tips.join(
-            '</li><li class="password-suggestions__tip">',
-          )}</li></ul>`
-        : ''
-    }</div>`;
-})(Drupal);
diff --git a/core/themes/claro/js/user.theme.js b/core/themes/claro/js/user.theme.js
index ed863d2655b3..341d3084593d 100644
--- a/core/themes/claro/js/user.theme.js
+++ b/core/themes/claro/js/user.theme.js
@@ -1,34 +1,53 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Password confirm widget template overrides.
+ */
 
-(Drupal => {
+((Drupal) => {
   Object.assign(Drupal.user.password.css, {
     passwordWeak: 'is-weak',
     widgetInitial: 'is-initial',
     passwordEmpty: 'is-password-empty',
     passwordFilled: 'is-password-filled',
     confirmEmpty: 'is-confirm-empty',
-    confirmFilled: 'is-confirm-filled'
+    confirmFilled: 'is-confirm-filled',
   });
 
-  Drupal.theme.passwordConfirmMessage = _ref => {
-    let {
-      confirmTitle
-    } = _ref;
-    const confirmTextWrapper = '<span class="password-match-message__text" data-drupal-selector="password-match-status-text"></span>';
+  /**
+   * Constructs a password confirm message element.
+   *
+   * @param {object} passwordSettings
+   *   An object containing password related settings and translated text to
+   *   display.
+   * @param {string} passwordSettings.confirmTitle
+   *   The translated confirm description that labels the actual confirm text.
+   *
+   * @return {string}
+   *   Markup for the password confirm message.
+   */
+  Drupal.theme.passwordConfirmMessage = ({ confirmTitle }) => {
+    const confirmTextWrapper =
+      '<span class="password-match-message__text" data-drupal-selector="password-match-status-text"></span>';
     return `<div aria-live="polite" aria-atomic="true" class="password-match-message" data-drupal-selector="password-confirm-message">${confirmTitle} ${confirmTextWrapper}</div>`;
   };
 
-  Drupal.theme.passwordStrength = _ref2 => {
-    let {
-      strengthTitle
-    } = _ref2;
-    const strengthBar = '<div class="password-strength__bar" data-drupal-selector="password-strength-indicator"></div>';
-    const strengthText = '<span class="password-strength__text" data-drupal-selector="password-strength-text"></span>';
+  /**
+   * Constructs a password strength message.
+   *
+   * @param {object} passwordSettings
+   *   An object containing password related settings and translated text to
+   *   display.
+   * @param {string} passwordSettings.strengthTitle
+   *   The title that precedes the strength text.
+   *
+   * @return {string}
+   *   Markup for the password strength indicator.
+   */
+  Drupal.theme.passwordStrength = ({ strengthTitle }) => {
+    const strengthBar =
+      '<div class="password-strength__bar" data-drupal-selector="password-strength-indicator"></div>';
+    const strengthText =
+      '<span class="password-strength__text" data-drupal-selector="password-strength-text"></span>';
     return `
       <div class="password-strength">
         <div class="password-strength__track" data-drupal-selector="password-strength-meter">${strengthBar}</div>
@@ -37,10 +56,26 @@
     `;
   };
 
-  Drupal.theme.passwordSuggestions = (_ref3, tips) => {
-    let {
-      hasWeaknesses
-    } = _ref3;
-    return `<div class="password-suggestions">${tips.length ? `${hasWeaknesses}<ul class="password-suggestions__tips"><li class="password-suggestions__tip">${tips.join('</li><li class="password-suggestions__tip">')}</li></ul>` : ''}</div>`;
-  };
-})(Drupal);
\ No newline at end of file
+  /**
+   * Constructs password suggestions tips.
+   *
+   * @param {object} passwordSettings
+   *   An object containing password related settings and translated tex  t to
+   *   display.
+   * @param {string} passwordSettings.hasWeaknesses
+   *   The title that precedes tips.
+   * @param {Array.<string>} tips
+   *   Array containing the tips.
+   *
+   * @return {string}
+   *   Markup for the password suggestions.
+   */
+  Drupal.theme.passwordSuggestions = ({ hasWeaknesses }, tips) =>
+    `<div class="password-suggestions">${
+      tips.length
+        ? `${hasWeaknesses}<ul class="password-suggestions__tips"><li class="password-suggestions__tip">${tips.join(
+            '</li><li class="password-suggestions__tip">',
+          )}</li></ul>`
+        : ''
+    }</div>`;
+})(Drupal);
diff --git a/core/themes/claro/js/vertical-tabs.es6.js b/core/themes/claro/js/vertical-tabs.es6.js
deleted file mode 100644
index bb37ab6bede9..000000000000
--- a/core/themes/claro/js/vertical-tabs.es6.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * @file
- * Overrides vertical tabs theming to enable Claro designs.
- */
-
-(($, Drupal) => {
-  /**
-   * Theme function for a vertical tab.
-   *
-   * @param {object} settings
-   *   An object with the following keys:
-   * @param {string} settings.title
-   *   The name of the tab.
-   *
-   * @return {object}
-   *   This function has to return an object with at least these keys:
-   *   - item: The root tab jQuery element
-   *   - link: The anchor tag that acts as the clickable area of the tab
-   *       (jQuery version)
-   *   - summary: The jQuery element that contains the tab summary
-   */
-  Drupal.theme.verticalTab = (settings) => {
-    const tab = {};
-    tab.title = $('<strong class="vertical-tabs__menu-item-title"></strong>');
-    tab.title[0].textContent = settings.title;
-    tab.item = $(
-      '<li class="vertical-tabs__menu-item" tabindex="-1"></li>',
-    ).append(
-      (tab.link = $('<a href="#" class="vertical-tabs__menu-link"></a>').append(
-        $('<span class="vertical-tabs__menu-link-content"></span>')
-          .append(tab.title)
-          .append(
-            (tab.summary = $(
-              '<span class="vertical-tabs__menu-link-summary"></span>',
-            )),
-          ),
-      )),
-    );
-    return tab;
-  };
-})(jQuery, Drupal);
diff --git a/core/themes/claro/js/vertical-tabs.js b/core/themes/claro/js/vertical-tabs.js
index 3d8ec943d5c7..bb37ab6bede9 100644
--- a/core/themes/claro/js/vertical-tabs.js
+++ b/core/themes/claro/js/vertical-tabs.js
@@ -1,16 +1,41 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Overrides vertical tabs theming to enable Claro designs.
+ */
 
 (($, Drupal) => {
-  Drupal.theme.verticalTab = settings => {
+  /**
+   * Theme function for a vertical tab.
+   *
+   * @param {object} settings
+   *   An object with the following keys:
+   * @param {string} settings.title
+   *   The name of the tab.
+   *
+   * @return {object}
+   *   This function has to return an object with at least these keys:
+   *   - item: The root tab jQuery element
+   *   - link: The anchor tag that acts as the clickable area of the tab
+   *       (jQuery version)
+   *   - summary: The jQuery element that contains the tab summary
+   */
+  Drupal.theme.verticalTab = (settings) => {
     const tab = {};
     tab.title = $('<strong class="vertical-tabs__menu-item-title"></strong>');
     tab.title[0].textContent = settings.title;
-    tab.item = $('<li class="vertical-tabs__menu-item" tabindex="-1"></li>').append(tab.link = $('<a href="#" class="vertical-tabs__menu-link"></a>').append($('<span class="vertical-tabs__menu-link-content"></span>').append(tab.title).append(tab.summary = $('<span class="vertical-tabs__menu-link-summary"></span>'))));
+    tab.item = $(
+      '<li class="vertical-tabs__menu-item" tabindex="-1"></li>',
+    ).append(
+      (tab.link = $('<a href="#" class="vertical-tabs__menu-link"></a>').append(
+        $('<span class="vertical-tabs__menu-link-content"></span>')
+          .append(tab.title)
+          .append(
+            (tab.summary = $(
+              '<span class="vertical-tabs__menu-link-summary"></span>',
+            )),
+          ),
+      )),
+    );
     return tab;
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/core/themes/classy/js/media_embed_ckeditor.theme.es6.js b/core/themes/classy/js/media_embed_ckeditor.theme.es6.js
deleted file mode 100644
index a33d18ffcd3d..000000000000
--- a/core/themes/classy/js/media_embed_ckeditor.theme.es6.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * @file
- * Classy theme overrides for the Media Embed CKEditor plugin.
- */
-
-((Drupal) => {
-  /**
-   * Themes the error displayed when the media embed preview fails.
-   *
-   * @param {string} error
-   *   The error message to display
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   *
-   * @see media-embed-error.html.twig
-   */
-  Drupal.theme.mediaEmbedPreviewError = () =>
-    `<div class="media-embed-error media-embed-error--preview-error">${Drupal.t(
-      'An error occurred while trying to preview the media. Please save your work and reload this page.',
-    )}</div>`;
-})(Drupal);
diff --git a/core/themes/classy/js/media_embed_ckeditor.theme.js b/core/themes/classy/js/media_embed_ckeditor.theme.js
index 19cc4ff77763..a33d18ffcd3d 100644
--- a/core/themes/classy/js/media_embed_ckeditor.theme.js
+++ b/core/themes/classy/js/media_embed_ckeditor.theme.js
@@ -1,10 +1,22 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Classy theme overrides for the Media Embed CKEditor plugin.
+ */
 
-(Drupal => {
-  Drupal.theme.mediaEmbedPreviewError = () => `<div class="media-embed-error media-embed-error--preview-error">${Drupal.t('An error occurred while trying to preview the media. Please save your work and reload this page.')}</div>`;
-})(Drupal);
\ No newline at end of file
+((Drupal) => {
+  /**
+   * Themes the error displayed when the media embed preview fails.
+   *
+   * @param {string} error
+   *   The error message to display
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   *
+   * @see media-embed-error.html.twig
+   */
+  Drupal.theme.mediaEmbedPreviewError = () =>
+    `<div class="media-embed-error media-embed-error--preview-error">${Drupal.t(
+      'An error occurred while trying to preview the media. Please save your work and reload this page.',
+    )}</div>`;
+})(Drupal);
diff --git a/core/themes/olivero/js/checkbox.es6.js b/core/themes/olivero/js/checkbox.es6.js
deleted file mode 100644
index 2114e28a42a6..000000000000
--- a/core/themes/olivero/js/checkbox.es6.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * @file
- * Customization of checkbox.
- */
-
-((Drupal) => {
-  /**
-   * Constructs a checkbox input element.
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   */
-  Drupal.theme.checkbox = () =>
-    '<input type="checkbox" class="form-checkbox form-boolean form-boolean--type-checkbox"/>';
-})(Drupal);
diff --git a/core/themes/olivero/js/checkbox.js b/core/themes/olivero/js/checkbox.js
index e2032acf910c..2114e28a42a6 100644
--- a/core/themes/olivero/js/checkbox.js
+++ b/core/themes/olivero/js/checkbox.js
@@ -1,10 +1,15 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Customization of checkbox.
+ */
 
-(Drupal => {
-  Drupal.theme.checkbox = () => '<input type="checkbox" class="form-checkbox form-boolean form-boolean--type-checkbox"/>';
-})(Drupal);
\ No newline at end of file
+((Drupal) => {
+  /**
+   * Constructs a checkbox input element.
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   */
+  Drupal.theme.checkbox = () =>
+    '<input type="checkbox" class="form-checkbox form-boolean form-boolean--type-checkbox"/>';
+})(Drupal);
diff --git a/core/themes/olivero/js/color-picker.es6.js b/core/themes/olivero/js/color-picker.es6.js
deleted file mode 100644
index e7e9a1a3fade..000000000000
--- a/core/themes/olivero/js/color-picker.es6.js
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- * @file
- * Provides UI/UX progressive enhancements on Olivero's theme settings by
- * creating an HTMLColorInput element and synchronizing its input with a text
- * input to provide an accessible and user-friendly interface. Additionally,
- * provides a select element with pre-defined color values for easy color
- * switching.
- */
-
-((Drupal, settings, once) => {
-  const colorSchemeOptions = settings.olivero.colorSchemes;
-
-  /**
-   * Announces the text value of the field's label.
-   *
-   * @param {HTMLElement} changedInput
-   *  The form element that was changed.
-   */
-  function announceFieldChange(changedInput) {
-    const fieldTitle =
-      changedInput.parentElement.querySelector('label').innerText;
-    const fieldValue = changedInput.value;
-    const announcement = Drupal.t('@fieldName has changed to @fieldValue', {
-      '@fieldName': fieldTitle,
-      '@fieldValue': fieldValue,
-    });
-    Drupal.announce(announcement);
-  }
-
-  /**
-   * `input` event callback to keep text & color inputs in sync.
-   *
-   * @param {HTMLElement} changedInput input element changed by user
-   * @param {HTMLElement} inputToSync input element to synchronize
-   */
-  function synchronizeInputs(changedInput, inputToSync) {
-    inputToSync.value = changedInput.value;
-
-    changedInput.setAttribute('data-olivero-custom-color', changedInput.value);
-    inputToSync.setAttribute('data-olivero-custom-color', changedInput.value);
-
-    const colorSchemeSelect = document.querySelector(
-      '[data-drupal-selector="edit-color-scheme"]',
-    );
-
-    if (colorSchemeSelect.value !== '') {
-      colorSchemeSelect.value = '';
-      announceFieldChange(colorSchemeSelect);
-    }
-  }
-
-  /**
-   * Set individual colors when a pre-defined color scheme is selected.
-   *
-   * @param {Event.target} target input element for which the value has changed.
-   */
-  function setColorScheme({ target }) {
-    if (!target.value) return;
-
-    const selectedColorScheme = colorSchemeOptions[target.value].colors;
-
-    if (selectedColorScheme) {
-      Object.entries(selectedColorScheme).forEach(([key, color]) => {
-        document
-          .querySelectorAll(`input[name="${key}"], input[name="${key}_visual"]`)
-          .forEach((input) => {
-            if (input.value !== color) {
-              input.value = color;
-              if (input.type === 'text') {
-                announceFieldChange(input);
-              }
-            }
-          });
-      });
-    } else {
-      document
-        .querySelectorAll(`input[data-olivero-custom-color]`)
-        .forEach((input) => {
-          input.value = input.getAttribute('data-olivero-custom-color');
-        });
-    }
-  }
-
-  /**
-   * Displays and initializes the color scheme selector.
-   *
-   * @param {HTMLSelectElement} selectElement div[data-drupal-selector="edit-color-scheme"]
-   */
-  function initColorSchemeSelect(selectElement) {
-    selectElement.closest('[style*="display:none;"]').style.display = '';
-    selectElement.addEventListener('change', setColorScheme);
-    Object.entries(colorSchemeOptions).forEach((option) => {
-      const [key, values] = option;
-
-      const { label, colors } = values;
-
-      let allColorsMatch = true;
-      Object.entries(colors).forEach(([colorName, colorHex]) => {
-        const field = document.querySelector(
-          `input[type="text"][name="${colorName}"]`,
-        );
-        if (field.value !== colorHex) {
-          allColorsMatch = false;
-        }
-      });
-
-      if (allColorsMatch) {
-        selectElement.value = key;
-      }
-    });
-  }
-
-  /**
-   * Initializes Olivero theme-settings color picker.
-   *   creates a color-type input and inserts it after the original text field.
-   *   modifies aria values to make label apply to both inputs.
-   *   adds event listeners to keep text & color inputs in sync.
-   *
-   * @param {HTMLElement} textInput The textfield input from the Drupal form API
-   */
-  function initColorPicker(textInput) {
-    // Create input element.
-    const colorInput = document.createElement('input');
-
-    // Set new input's attributes.
-    colorInput.type = 'color';
-    colorInput.classList.add(
-      'form-color',
-      'form-element',
-      'form-element--type-color',
-      'form-element--api-color',
-    );
-    colorInput.value = textInput.value;
-    colorInput.setAttribute('name', `${textInput.name}_visual`);
-    colorInput.setAttribute(
-      'data-olivero-custom-color',
-      textInput.getAttribute('data-olivero-custom-color'),
-    );
-
-    // Insert new input into DOM.
-    textInput.after(colorInput);
-
-    // Make field label apply to textInput and colorInput.
-    const fieldID = textInput.id;
-    const label = document.querySelector(`label[for="${fieldID}"]`);
-    label.removeAttribute('for');
-    label.setAttribute('id', `${fieldID}-label`);
-
-    textInput.setAttribute('aria-labelledby', `${fieldID}-label`);
-    colorInput.setAttribute('aria-labelledby', `${fieldID}-label`);
-
-    // Add `input` event listener to keep inputs synchronized.
-    textInput.addEventListener('input', () => {
-      synchronizeInputs(textInput, colorInput);
-    });
-
-    colorInput.addEventListener('input', () => {
-      synchronizeInputs(colorInput, textInput);
-    });
-  }
-
-  /**
-   * Olivero Color Picker behavior.
-   *
-   * @type {Drupal~behavior}
-   * @prop {Drupal~behaviorAttach} attach
-   *   Initializes color picker fields.
-   */
-  Drupal.behaviors.oliveroColorPicker = {
-    attach: () => {
-      const colorSchemeSelect = once(
-        'olivero-color-picker',
-        '[data-drupal-selector="edit-color-scheme"]',
-      );
-
-      colorSchemeSelect.forEach((selectElement) => {
-        initColorSchemeSelect(selectElement);
-      });
-
-      const colorTextInputs = once(
-        'olivero-color-picker',
-        '[data-drupal-selector="olivero-color-picker"] input[type="text"]',
-      );
-
-      colorTextInputs.forEach((textInput) => {
-        initColorPicker(textInput);
-      });
-    },
-  };
-})(Drupal, drupalSettings, once);
diff --git a/core/themes/olivero/js/color-picker.js b/core/themes/olivero/js/color-picker.js
index 1b3fd4157dd0..e7e9a1a3fade 100644
--- a/core/themes/olivero/js/color-picker.js
+++ b/core/themes/olivero/js/color-picker.js
@@ -1,28 +1,47 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Provides UI/UX progressive enhancements on Olivero's theme settings by
+ * creating an HTMLColorInput element and synchronizing its input with a text
+ * input to provide an accessible and user-friendly interface. Additionally,
+ * provides a select element with pre-defined color values for easy color
+ * switching.
+ */
 
 ((Drupal, settings, once) => {
   const colorSchemeOptions = settings.olivero.colorSchemes;
 
+  /**
+   * Announces the text value of the field's label.
+   *
+   * @param {HTMLElement} changedInput
+   *  The form element that was changed.
+   */
   function announceFieldChange(changedInput) {
-    const fieldTitle = changedInput.parentElement.querySelector('label').innerText;
+    const fieldTitle =
+      changedInput.parentElement.querySelector('label').innerText;
     const fieldValue = changedInput.value;
     const announcement = Drupal.t('@fieldName has changed to @fieldValue', {
       '@fieldName': fieldTitle,
-      '@fieldValue': fieldValue
+      '@fieldValue': fieldValue,
     });
     Drupal.announce(announcement);
   }
 
+  /**
+   * `input` event callback to keep text & color inputs in sync.
+   *
+   * @param {HTMLElement} changedInput input element changed by user
+   * @param {HTMLElement} inputToSync input element to synchronize
+   */
   function synchronizeInputs(changedInput, inputToSync) {
     inputToSync.value = changedInput.value;
+
     changedInput.setAttribute('data-olivero-custom-color', changedInput.value);
     inputToSync.setAttribute('data-olivero-custom-color', changedInput.value);
-    const colorSchemeSelect = document.querySelector('[data-drupal-selector="edit-color-scheme"]');
+
+    const colorSchemeSelect = document.querySelector(
+      '[data-drupal-selector="edit-color-scheme"]',
+    );
 
     if (colorSchemeSelect.value !== '') {
       colorSchemeSelect.value = '';
@@ -30,47 +49,56 @@
     }
   }
 
-  function setColorScheme(_ref) {
-    let {
-      target
-    } = _ref;
+  /**
+   * Set individual colors when a pre-defined color scheme is selected.
+   *
+   * @param {Event.target} target input element for which the value has changed.
+   */
+  function setColorScheme({ target }) {
     if (!target.value) return;
+
     const selectedColorScheme = colorSchemeOptions[target.value].colors;
 
     if (selectedColorScheme) {
-      Object.entries(selectedColorScheme).forEach(_ref2 => {
-        let [key, color] = _ref2;
-        document.querySelectorAll(`input[name="${key}"], input[name="${key}_visual"]`).forEach(input => {
-          if (input.value !== color) {
-            input.value = color;
-
-            if (input.type === 'text') {
-              announceFieldChange(input);
+      Object.entries(selectedColorScheme).forEach(([key, color]) => {
+        document
+          .querySelectorAll(`input[name="${key}"], input[name="${key}_visual"]`)
+          .forEach((input) => {
+            if (input.value !== color) {
+              input.value = color;
+              if (input.type === 'text') {
+                announceFieldChange(input);
+              }
             }
-          }
-        });
+          });
       });
     } else {
-      document.querySelectorAll(`input[data-olivero-custom-color]`).forEach(input => {
-        input.value = input.getAttribute('data-olivero-custom-color');
-      });
+      document
+        .querySelectorAll(`input[data-olivero-custom-color]`)
+        .forEach((input) => {
+          input.value = input.getAttribute('data-olivero-custom-color');
+        });
     }
   }
 
+  /**
+   * Displays and initializes the color scheme selector.
+   *
+   * @param {HTMLSelectElement} selectElement div[data-drupal-selector="edit-color-scheme"]
+   */
   function initColorSchemeSelect(selectElement) {
     selectElement.closest('[style*="display:none;"]').style.display = '';
     selectElement.addEventListener('change', setColorScheme);
-    Object.entries(colorSchemeOptions).forEach(option => {
+    Object.entries(colorSchemeOptions).forEach((option) => {
       const [key, values] = option;
-      const {
-        label,
-        colors
-      } = values;
-      let allColorsMatch = true;
-      Object.entries(colors).forEach(_ref3 => {
-        let [colorName, colorHex] = _ref3;
-        const field = document.querySelector(`input[type="text"][name="${colorName}"]`);
 
+      const { label, colors } = values;
+
+      let allColorsMatch = true;
+      Object.entries(colors).forEach(([colorName, colorHex]) => {
+        const field = document.querySelector(
+          `input[type="text"][name="${colorName}"]`,
+        );
         if (field.value !== colorHex) {
           allColorsMatch = false;
         }
@@ -82,38 +110,81 @@
     });
   }
 
+  /**
+   * Initializes Olivero theme-settings color picker.
+   *   creates a color-type input and inserts it after the original text field.
+   *   modifies aria values to make label apply to both inputs.
+   *   adds event listeners to keep text & color inputs in sync.
+   *
+   * @param {HTMLElement} textInput The textfield input from the Drupal form API
+   */
   function initColorPicker(textInput) {
+    // Create input element.
     const colorInput = document.createElement('input');
+
+    // Set new input's attributes.
     colorInput.type = 'color';
-    colorInput.classList.add('form-color', 'form-element', 'form-element--type-color', 'form-element--api-color');
+    colorInput.classList.add(
+      'form-color',
+      'form-element',
+      'form-element--type-color',
+      'form-element--api-color',
+    );
     colorInput.value = textInput.value;
     colorInput.setAttribute('name', `${textInput.name}_visual`);
-    colorInput.setAttribute('data-olivero-custom-color', textInput.getAttribute('data-olivero-custom-color'));
+    colorInput.setAttribute(
+      'data-olivero-custom-color',
+      textInput.getAttribute('data-olivero-custom-color'),
+    );
+
+    // Insert new input into DOM.
     textInput.after(colorInput);
+
+    // Make field label apply to textInput and colorInput.
     const fieldID = textInput.id;
     const label = document.querySelector(`label[for="${fieldID}"]`);
     label.removeAttribute('for');
     label.setAttribute('id', `${fieldID}-label`);
+
     textInput.setAttribute('aria-labelledby', `${fieldID}-label`);
     colorInput.setAttribute('aria-labelledby', `${fieldID}-label`);
+
+    // Add `input` event listener to keep inputs synchronized.
     textInput.addEventListener('input', () => {
       synchronizeInputs(textInput, colorInput);
     });
+
     colorInput.addEventListener('input', () => {
       synchronizeInputs(colorInput, textInput);
     });
   }
 
+  /**
+   * Olivero Color Picker behavior.
+   *
+   * @type {Drupal~behavior}
+   * @prop {Drupal~behaviorAttach} attach
+   *   Initializes color picker fields.
+   */
   Drupal.behaviors.oliveroColorPicker = {
     attach: () => {
-      const colorSchemeSelect = once('olivero-color-picker', '[data-drupal-selector="edit-color-scheme"]');
-      colorSchemeSelect.forEach(selectElement => {
+      const colorSchemeSelect = once(
+        'olivero-color-picker',
+        '[data-drupal-selector="edit-color-scheme"]',
+      );
+
+      colorSchemeSelect.forEach((selectElement) => {
         initColorSchemeSelect(selectElement);
       });
-      const colorTextInputs = once('olivero-color-picker', '[data-drupal-selector="olivero-color-picker"] input[type="text"]');
-      colorTextInputs.forEach(textInput => {
+
+      const colorTextInputs = once(
+        'olivero-color-picker',
+        '[data-drupal-selector="olivero-color-picker"] input[type="text"]',
+      );
+
+      colorTextInputs.forEach((textInput) => {
         initColorPicker(textInput);
       });
-    }
+    },
   };
-})(Drupal, drupalSettings, once);
\ No newline at end of file
+})(Drupal, drupalSettings, once);
diff --git a/core/themes/olivero/js/comments.es6.js b/core/themes/olivero/js/comments.es6.js
deleted file mode 100644
index 1e70ee9e8668..000000000000
--- a/core/themes/olivero/js/comments.es6.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * @file
- * Customization of comments.
- */
-
-((Drupal, once) => {
-  /**
-   * Initialize show/hide button for the comments.
-   *
-   * @param {Element} comments
-   *   The comment wrapper element.
-   */
-  function init(comments) {
-    comments
-      .querySelectorAll('[data-drupal-selector="comment"]')
-      .forEach((comment) => {
-        if (
-          comment.nextElementSibling != null &&
-          comment.nextElementSibling.matches('.indented')
-        ) {
-          comment.classList.add('has-children');
-        }
-      });
-
-    comments.querySelectorAll('.indented').forEach((commentGroup) => {
-      const showHideWrapper = document.createElement('div');
-      showHideWrapper.setAttribute('class', 'show-hide-wrapper');
-
-      const toggleCommentsBtn = document.createElement('button');
-      toggleCommentsBtn.setAttribute('type', 'button');
-      toggleCommentsBtn.setAttribute('aria-expanded', 'true');
-      toggleCommentsBtn.setAttribute('class', 'show-hide-btn');
-      toggleCommentsBtn.innerText = Drupal.t('Replies');
-
-      commentGroup.parentNode.insertBefore(showHideWrapper, commentGroup);
-      showHideWrapper.appendChild(toggleCommentsBtn);
-
-      toggleCommentsBtn.addEventListener('click', (e) => {
-        commentGroup.classList.toggle('hidden');
-        e.currentTarget.setAttribute(
-          'aria-expanded',
-          commentGroup.classList.contains('hidden') ? 'false' : 'true',
-        );
-      });
-    });
-  }
-
-  /**
-   * Attaches the comment behavior to comments.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the show/hide behavior for indented comments.
-   */
-  Drupal.behaviors.comments = {
-    attach(context) {
-      once('comments', '[data-drupal-selector="comments"]', context).forEach(
-        init,
-      );
-    },
-  };
-})(Drupal, once);
diff --git a/core/themes/olivero/js/comments.js b/core/themes/olivero/js/comments.js
index 2e5ca5bab658..1e70ee9e8668 100644
--- a/core/themes/olivero/js/comments.js
+++ b/core/themes/olivero/js/comments.js
@@ -1,38 +1,63 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Customization of comments.
+ */
 
 ((Drupal, once) => {
+  /**
+   * Initialize show/hide button for the comments.
+   *
+   * @param {Element} comments
+   *   The comment wrapper element.
+   */
   function init(comments) {
-    comments.querySelectorAll('[data-drupal-selector="comment"]').forEach(comment => {
-      if (comment.nextElementSibling != null && comment.nextElementSibling.matches('.indented')) {
-        comment.classList.add('has-children');
-      }
-    });
-    comments.querySelectorAll('.indented').forEach(commentGroup => {
+    comments
+      .querySelectorAll('[data-drupal-selector="comment"]')
+      .forEach((comment) => {
+        if (
+          comment.nextElementSibling != null &&
+          comment.nextElementSibling.matches('.indented')
+        ) {
+          comment.classList.add('has-children');
+        }
+      });
+
+    comments.querySelectorAll('.indented').forEach((commentGroup) => {
       const showHideWrapper = document.createElement('div');
       showHideWrapper.setAttribute('class', 'show-hide-wrapper');
+
       const toggleCommentsBtn = document.createElement('button');
       toggleCommentsBtn.setAttribute('type', 'button');
       toggleCommentsBtn.setAttribute('aria-expanded', 'true');
       toggleCommentsBtn.setAttribute('class', 'show-hide-btn');
       toggleCommentsBtn.innerText = Drupal.t('Replies');
+
       commentGroup.parentNode.insertBefore(showHideWrapper, commentGroup);
       showHideWrapper.appendChild(toggleCommentsBtn);
-      toggleCommentsBtn.addEventListener('click', e => {
+
+      toggleCommentsBtn.addEventListener('click', (e) => {
         commentGroup.classList.toggle('hidden');
-        e.currentTarget.setAttribute('aria-expanded', commentGroup.classList.contains('hidden') ? 'false' : 'true');
+        e.currentTarget.setAttribute(
+          'aria-expanded',
+          commentGroup.classList.contains('hidden') ? 'false' : 'true',
+        );
       });
     });
   }
 
+  /**
+   * Attaches the comment behavior to comments.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the show/hide behavior for indented comments.
+   */
   Drupal.behaviors.comments = {
     attach(context) {
-      once('comments', '[data-drupal-selector="comments"]', context).forEach(init);
-    }
-
+      once('comments', '[data-drupal-selector="comments"]', context).forEach(
+        init,
+      );
+    },
   };
-})(Drupal, once);
\ No newline at end of file
+})(Drupal, once);
diff --git a/core/themes/olivero/js/message.theme.es6.js b/core/themes/olivero/js/message.theme.es6.js
deleted file mode 100644
index 5d439c2a0fcc..000000000000
--- a/core/themes/olivero/js/message.theme.es6.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * @file
- * Overriding core's message functions to add icon and a remove button to each message.
- */
-
-((Drupal) => {
-  /**
-   * Overrides message theme function.
-   *
-   * @param {object} message
-   *   The message object.
-   * @param {string} message.text
-   *   The message text.
-   * @param {object} options
-   *   The message context.
-   * @param {string} options.type
-   *   The message type.
-   * @param {string} options.id
-   *   ID of the message, for reference.
-   *
-   * @return {HTMLElement}
-   *   A DOM Node.
-   */
-  Drupal.theme.message = ({ text }, { type, id }) => {
-    const messagesTypes = Drupal.Message.getMessageTypeLabels();
-    const messageWrapper = document.createElement('div');
-
-    messageWrapper.setAttribute(
-      'class',
-      `messages-list__item messages messages--${type}`,
-    );
-    messageWrapper.setAttribute('data-drupal-selector', 'messages');
-    messageWrapper.setAttribute(
-      'role',
-      type === 'error' || type === 'warning' ? 'alert' : 'status',
-    );
-    messageWrapper.setAttribute('aria-labelledby', `${id}-title`);
-    messageWrapper.setAttribute('data-drupal-message-id', id);
-    messageWrapper.setAttribute('data-drupal-message-type', type);
-    let svg = '';
-
-    if (['error', 'warning', 'status', 'info'].indexOf(type) > -1) {
-      svg =
-        '<div class="messages__icon"><svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">';
-    }
-
-    if (type === 'error') {
-      svg +=
-        '<path d="M0.117801 16.7381C0.202622 17.9153 0.292289 18.562 0.481317 19.3904C0.922384 21.3161 1.6785 23.0626 2.76178 24.6589C4.58178 27.3355 7.18213 29.3823 10.1993 30.5062C12.458 31.3467 14.942 31.6495 17.3461 31.3782C22.5831 30.7872 27.1246 27.6164 29.4875 22.9027C30.3769 21.132 30.8616 19.3929 31.0797 17.1983C31.1209 16.7768 31.1209 15.1733 31.0797 14.7518C30.8786 12.7195 30.4714 11.1693 29.7032 9.49549C28.3848 6.62269 26.1722 4.18589 23.4289 2.58235C19.4399 0.249712 14.5373 -0.171762 10.1993 1.44389C5.82985 3.07165 2.38372 6.62753 0.915114 11.0215C0.512822 12.223 0.289865 13.2863 0.161423 14.604C0.127495 14.9674 0.0959901 16.4425 0.117801 16.7381ZM4.02924 14.9577C4.2837 12.2108 5.46391 9.69412 7.40024 7.76115C9.15966 6.00743 11.3529 4.89319 13.8224 4.49352C14.4234 4.39905 14.8717 4.36514 15.6012 4.36271C16.6941 4.36271 17.4793 4.45718 18.5093 4.71636C19.2969 4.91257 20.0143 5.17902 20.7873 5.55931C21.2526 5.78943 21.9409 6.18183 21.9554 6.22786C21.9651 6.25692 5.90498 22.3093 5.86621 22.3093C5.82501 22.3093 5.46391 21.6916 5.21915 21.2071C4.51877 19.8071 4.10921 18.2956 4.005 16.7138C3.98077 16.336 3.99288 15.3453 4.02924 14.9577ZM25.3725 9.6384C25.4428 9.7038 25.816 10.3602 26.0341 10.8035C26.6618 12.0776 27.0301 13.359 27.1876 14.8366C27.2385 15.2968 27.2458 16.5225 27.2022 16.9561C27.0859 18.0776 26.8847 18.9786 26.526 19.9669C26.2377 20.7663 25.7748 21.6843 25.2998 22.394C23.8748 24.5232 21.7882 26.1364 19.3987 26.9576C18.1046 27.4009 16.985 27.585 15.5891 27.585C14.8232 27.585 14.4646 27.5607 13.786 27.4541C12.2568 27.2192 10.6574 26.6209 9.40685 25.8191L9.23237 25.7077L17.2879 17.6609C23.3562 11.598 25.3507 9.61903 25.3725 9.6384Z"/>';
-    } else if (type === 'warning') {
-      svg +=
-        '<path d="M16 0C7.16667 0 0 7.16667 0 16C0 24.8333 7.16667 32 16 32C24.8333 32 32 24.8333 32 16C32 7.16667 24.8333 0 16 0ZM18.6667 25.9792C18.6667 26.3542 18.375 26.6667 18.0208 26.6667H14.0208C13.6458 26.6667 13.3333 26.3542 13.3333 25.9792V22.0208C13.3333 21.6458 13.6458 21.3333 14.0208 21.3333H18.0208C18.375 21.3333 18.6667 21.6458 18.6667 22.0208V25.9792ZM18.625 18.8125C18.6042 19.1042 18.2917 19.3333 17.9167 19.3333H14.0625C13.6667 19.3333 13.3542 19.1042 13.3542 18.8125L13 5.875C13 5.72917 13.0625 5.58333 13.2083 5.5C13.3333 5.39583 13.5208 5.33333 13.7083 5.33333H18.2917C18.4792 5.33333 18.6667 5.39583 18.7917 5.5C18.9375 5.58333 19 5.72917 19 5.875L18.625 18.8125Z"/>';
-    } else if (type === 'status') {
-      svg +=
-        '<path d="M26.75 12.625C26.75 12.9792 26.625 13.3125 26.375 13.5625L15.0625 24.875C14.8125 25.125 14.4583 25.2708 14.1042 25.2708C13.7708 25.2708 13.4167 25.125 13.1667 24.875L5.625 17.3333C5.375 17.0833 5.25 16.75 5.25 16.3958C5.25 16.0417 5.375 15.6875 5.625 15.4375L7.52083 13.5625C7.77083 13.3125 8.10417 13.1667 8.45833 13.1667C8.8125 13.1667 9.14583 13.3125 9.39583 13.5625L14.1042 18.2708L22.6042 9.79167C22.8542 9.54167 23.1875 9.39583 23.5417 9.39583C23.8958 9.39583 24.2292 9.54167 24.4792 9.79167L26.375 11.6667C26.625 11.9167 26.75 12.2708 26.75 12.625ZM32 16C32 7.16667 24.8333 0 16 0C7.16667 0 0 7.16667 0 16C0 24.8333 7.16667 32 16 32C24.8333 32 32 24.8333 32 16Z"/>';
-    } else if (type === 'info') {
-      svg +=
-        '<path d="M32,16c0,8.8-7.2,16-16,16S0,24.8,0,16C0,7.2,7.2,0,16,0S32,7.2,32,16z M16.4,5.3c-3.5,0-5.8,1.5-7.5,4.1c-0.2,0.3-0.2,0.8,0.2,1l2.2,1.7c0.3,0.3,0.8,0.2,1.1-0.1c1.2-1.5,1.9-2.3,3.7-2.3c1.3,0,2.9,0.8,2.9,2.1c0,1-0.8,1.5-2.1,2.2c-1.5,0.9-3.5,1.9-3.5,4.6v0.3c0,0.4,0.3,0.8,0.8,0.8h3.6c0.4,0,0.8-0.3,0.8-0.8v-0.1c0-1.8,5.4-1.9,5.4-6.9C23.9,8.1,20.1,5.3,16.4,5.3z M16,21.3c-1.6,0-3,1.3-3,3c0,1.6,1.3,3,3,3s3-1.3,3-3C19,22.6,17.6,21.3,16,21.3z"/>';
-    }
-
-    if (['error', 'warning', 'status', 'info'].indexOf(type) > -1) {
-      svg += '</svg></div>';
-    }
-
-    messageWrapper.innerHTML = `
-    <div class="messages__container" data-drupal-selector="messages-container">
-      <div class="messages__header${!svg ? ' no-icon' : ''}">
-        <h2 class="visually-hidden">${messagesTypes[type]}</h2>
-        ${svg}
-      </div>
-      <div class="messages__content">
-        ${text}
-      </div>
-    </div>
-    `;
-
-    Drupal.olivero.closeMessage(messageWrapper);
-
-    return messageWrapper;
-  };
-})(Drupal);
diff --git a/core/themes/olivero/js/message.theme.js b/core/themes/olivero/js/message.theme.js
index f0e03d6b1686..5d439c2a0fcc 100644
--- a/core/themes/olivero/js/message.theme.js
+++ b/core/themes/olivero/js/message.theme.js
@@ -1,41 +1,61 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(Drupal => {
-  Drupal.theme.message = (_ref, _ref2) => {
-    let {
-      text
-    } = _ref;
-    let {
-      type,
-      id
-    } = _ref2;
+ * @file
+ * Overriding core's message functions to add icon and a remove button to each message.
+ */
+
+((Drupal) => {
+  /**
+   * Overrides message theme function.
+   *
+   * @param {object} message
+   *   The message object.
+   * @param {string} message.text
+   *   The message text.
+   * @param {object} options
+   *   The message context.
+   * @param {string} options.type
+   *   The message type.
+   * @param {string} options.id
+   *   ID of the message, for reference.
+   *
+   * @return {HTMLElement}
+   *   A DOM Node.
+   */
+  Drupal.theme.message = ({ text }, { type, id }) => {
     const messagesTypes = Drupal.Message.getMessageTypeLabels();
     const messageWrapper = document.createElement('div');
-    messageWrapper.setAttribute('class', `messages-list__item messages messages--${type}`);
+
+    messageWrapper.setAttribute(
+      'class',
+      `messages-list__item messages messages--${type}`,
+    );
     messageWrapper.setAttribute('data-drupal-selector', 'messages');
-    messageWrapper.setAttribute('role', type === 'error' || type === 'warning' ? 'alert' : 'status');
+    messageWrapper.setAttribute(
+      'role',
+      type === 'error' || type === 'warning' ? 'alert' : 'status',
+    );
     messageWrapper.setAttribute('aria-labelledby', `${id}-title`);
     messageWrapper.setAttribute('data-drupal-message-id', id);
     messageWrapper.setAttribute('data-drupal-message-type', type);
     let svg = '';
 
     if (['error', 'warning', 'status', 'info'].indexOf(type) > -1) {
-      svg = '<div class="messages__icon"><svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">';
+      svg =
+        '<div class="messages__icon"><svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">';
     }
 
     if (type === 'error') {
-      svg += '<path d="M0.117801 16.7381C0.202622 17.9153 0.292289 18.562 0.481317 19.3904C0.922384 21.3161 1.6785 23.0626 2.76178 24.6589C4.58178 27.3355 7.18213 29.3823 10.1993 30.5062C12.458 31.3467 14.942 31.6495 17.3461 31.3782C22.5831 30.7872 27.1246 27.6164 29.4875 22.9027C30.3769 21.132 30.8616 19.3929 31.0797 17.1983C31.1209 16.7768 31.1209 15.1733 31.0797 14.7518C30.8786 12.7195 30.4714 11.1693 29.7032 9.49549C28.3848 6.62269 26.1722 4.18589 23.4289 2.58235C19.4399 0.249712 14.5373 -0.171762 10.1993 1.44389C5.82985 3.07165 2.38372 6.62753 0.915114 11.0215C0.512822 12.223 0.289865 13.2863 0.161423 14.604C0.127495 14.9674 0.0959901 16.4425 0.117801 16.7381ZM4.02924 14.9577C4.2837 12.2108 5.46391 9.69412 7.40024 7.76115C9.15966 6.00743 11.3529 4.89319 13.8224 4.49352C14.4234 4.39905 14.8717 4.36514 15.6012 4.36271C16.6941 4.36271 17.4793 4.45718 18.5093 4.71636C19.2969 4.91257 20.0143 5.17902 20.7873 5.55931C21.2526 5.78943 21.9409 6.18183 21.9554 6.22786C21.9651 6.25692 5.90498 22.3093 5.86621 22.3093C5.82501 22.3093 5.46391 21.6916 5.21915 21.2071C4.51877 19.8071 4.10921 18.2956 4.005 16.7138C3.98077 16.336 3.99288 15.3453 4.02924 14.9577ZM25.3725 9.6384C25.4428 9.7038 25.816 10.3602 26.0341 10.8035C26.6618 12.0776 27.0301 13.359 27.1876 14.8366C27.2385 15.2968 27.2458 16.5225 27.2022 16.9561C27.0859 18.0776 26.8847 18.9786 26.526 19.9669C26.2377 20.7663 25.7748 21.6843 25.2998 22.394C23.8748 24.5232 21.7882 26.1364 19.3987 26.9576C18.1046 27.4009 16.985 27.585 15.5891 27.585C14.8232 27.585 14.4646 27.5607 13.786 27.4541C12.2568 27.2192 10.6574 26.6209 9.40685 25.8191L9.23237 25.7077L17.2879 17.6609C23.3562 11.598 25.3507 9.61903 25.3725 9.6384Z"/>';
+      svg +=
+        '<path d="M0.117801 16.7381C0.202622 17.9153 0.292289 18.562 0.481317 19.3904C0.922384 21.3161 1.6785 23.0626 2.76178 24.6589C4.58178 27.3355 7.18213 29.3823 10.1993 30.5062C12.458 31.3467 14.942 31.6495 17.3461 31.3782C22.5831 30.7872 27.1246 27.6164 29.4875 22.9027C30.3769 21.132 30.8616 19.3929 31.0797 17.1983C31.1209 16.7768 31.1209 15.1733 31.0797 14.7518C30.8786 12.7195 30.4714 11.1693 29.7032 9.49549C28.3848 6.62269 26.1722 4.18589 23.4289 2.58235C19.4399 0.249712 14.5373 -0.171762 10.1993 1.44389C5.82985 3.07165 2.38372 6.62753 0.915114 11.0215C0.512822 12.223 0.289865 13.2863 0.161423 14.604C0.127495 14.9674 0.0959901 16.4425 0.117801 16.7381ZM4.02924 14.9577C4.2837 12.2108 5.46391 9.69412 7.40024 7.76115C9.15966 6.00743 11.3529 4.89319 13.8224 4.49352C14.4234 4.39905 14.8717 4.36514 15.6012 4.36271C16.6941 4.36271 17.4793 4.45718 18.5093 4.71636C19.2969 4.91257 20.0143 5.17902 20.7873 5.55931C21.2526 5.78943 21.9409 6.18183 21.9554 6.22786C21.9651 6.25692 5.90498 22.3093 5.86621 22.3093C5.82501 22.3093 5.46391 21.6916 5.21915 21.2071C4.51877 19.8071 4.10921 18.2956 4.005 16.7138C3.98077 16.336 3.99288 15.3453 4.02924 14.9577ZM25.3725 9.6384C25.4428 9.7038 25.816 10.3602 26.0341 10.8035C26.6618 12.0776 27.0301 13.359 27.1876 14.8366C27.2385 15.2968 27.2458 16.5225 27.2022 16.9561C27.0859 18.0776 26.8847 18.9786 26.526 19.9669C26.2377 20.7663 25.7748 21.6843 25.2998 22.394C23.8748 24.5232 21.7882 26.1364 19.3987 26.9576C18.1046 27.4009 16.985 27.585 15.5891 27.585C14.8232 27.585 14.4646 27.5607 13.786 27.4541C12.2568 27.2192 10.6574 26.6209 9.40685 25.8191L9.23237 25.7077L17.2879 17.6609C23.3562 11.598 25.3507 9.61903 25.3725 9.6384Z"/>';
     } else if (type === 'warning') {
-      svg += '<path d="M16 0C7.16667 0 0 7.16667 0 16C0 24.8333 7.16667 32 16 32C24.8333 32 32 24.8333 32 16C32 7.16667 24.8333 0 16 0ZM18.6667 25.9792C18.6667 26.3542 18.375 26.6667 18.0208 26.6667H14.0208C13.6458 26.6667 13.3333 26.3542 13.3333 25.9792V22.0208C13.3333 21.6458 13.6458 21.3333 14.0208 21.3333H18.0208C18.375 21.3333 18.6667 21.6458 18.6667 22.0208V25.9792ZM18.625 18.8125C18.6042 19.1042 18.2917 19.3333 17.9167 19.3333H14.0625C13.6667 19.3333 13.3542 19.1042 13.3542 18.8125L13 5.875C13 5.72917 13.0625 5.58333 13.2083 5.5C13.3333 5.39583 13.5208 5.33333 13.7083 5.33333H18.2917C18.4792 5.33333 18.6667 5.39583 18.7917 5.5C18.9375 5.58333 19 5.72917 19 5.875L18.625 18.8125Z"/>';
+      svg +=
+        '<path d="M16 0C7.16667 0 0 7.16667 0 16C0 24.8333 7.16667 32 16 32C24.8333 32 32 24.8333 32 16C32 7.16667 24.8333 0 16 0ZM18.6667 25.9792C18.6667 26.3542 18.375 26.6667 18.0208 26.6667H14.0208C13.6458 26.6667 13.3333 26.3542 13.3333 25.9792V22.0208C13.3333 21.6458 13.6458 21.3333 14.0208 21.3333H18.0208C18.375 21.3333 18.6667 21.6458 18.6667 22.0208V25.9792ZM18.625 18.8125C18.6042 19.1042 18.2917 19.3333 17.9167 19.3333H14.0625C13.6667 19.3333 13.3542 19.1042 13.3542 18.8125L13 5.875C13 5.72917 13.0625 5.58333 13.2083 5.5C13.3333 5.39583 13.5208 5.33333 13.7083 5.33333H18.2917C18.4792 5.33333 18.6667 5.39583 18.7917 5.5C18.9375 5.58333 19 5.72917 19 5.875L18.625 18.8125Z"/>';
     } else if (type === 'status') {
-      svg += '<path d="M26.75 12.625C26.75 12.9792 26.625 13.3125 26.375 13.5625L15.0625 24.875C14.8125 25.125 14.4583 25.2708 14.1042 25.2708C13.7708 25.2708 13.4167 25.125 13.1667 24.875L5.625 17.3333C5.375 17.0833 5.25 16.75 5.25 16.3958C5.25 16.0417 5.375 15.6875 5.625 15.4375L7.52083 13.5625C7.77083 13.3125 8.10417 13.1667 8.45833 13.1667C8.8125 13.1667 9.14583 13.3125 9.39583 13.5625L14.1042 18.2708L22.6042 9.79167C22.8542 9.54167 23.1875 9.39583 23.5417 9.39583C23.8958 9.39583 24.2292 9.54167 24.4792 9.79167L26.375 11.6667C26.625 11.9167 26.75 12.2708 26.75 12.625ZM32 16C32 7.16667 24.8333 0 16 0C7.16667 0 0 7.16667 0 16C0 24.8333 7.16667 32 16 32C24.8333 32 32 24.8333 32 16Z"/>';
+      svg +=
+        '<path d="M26.75 12.625C26.75 12.9792 26.625 13.3125 26.375 13.5625L15.0625 24.875C14.8125 25.125 14.4583 25.2708 14.1042 25.2708C13.7708 25.2708 13.4167 25.125 13.1667 24.875L5.625 17.3333C5.375 17.0833 5.25 16.75 5.25 16.3958C5.25 16.0417 5.375 15.6875 5.625 15.4375L7.52083 13.5625C7.77083 13.3125 8.10417 13.1667 8.45833 13.1667C8.8125 13.1667 9.14583 13.3125 9.39583 13.5625L14.1042 18.2708L22.6042 9.79167C22.8542 9.54167 23.1875 9.39583 23.5417 9.39583C23.8958 9.39583 24.2292 9.54167 24.4792 9.79167L26.375 11.6667C26.625 11.9167 26.75 12.2708 26.75 12.625ZM32 16C32 7.16667 24.8333 0 16 0C7.16667 0 0 7.16667 0 16C0 24.8333 7.16667 32 16 32C24.8333 32 32 24.8333 32 16Z"/>';
     } else if (type === 'info') {
-      svg += '<path d="M32,16c0,8.8-7.2,16-16,16S0,24.8,0,16C0,7.2,7.2,0,16,0S32,7.2,32,16z M16.4,5.3c-3.5,0-5.8,1.5-7.5,4.1c-0.2,0.3-0.2,0.8,0.2,1l2.2,1.7c0.3,0.3,0.8,0.2,1.1-0.1c1.2-1.5,1.9-2.3,3.7-2.3c1.3,0,2.9,0.8,2.9,2.1c0,1-0.8,1.5-2.1,2.2c-1.5,0.9-3.5,1.9-3.5,4.6v0.3c0,0.4,0.3,0.8,0.8,0.8h3.6c0.4,0,0.8-0.3,0.8-0.8v-0.1c0-1.8,5.4-1.9,5.4-6.9C23.9,8.1,20.1,5.3,16.4,5.3z M16,21.3c-1.6,0-3,1.3-3,3c0,1.6,1.3,3,3,3s3-1.3,3-3C19,22.6,17.6,21.3,16,21.3z"/>';
+      svg +=
+        '<path d="M32,16c0,8.8-7.2,16-16,16S0,24.8,0,16C0,7.2,7.2,0,16,0S32,7.2,32,16z M16.4,5.3c-3.5,0-5.8,1.5-7.5,4.1c-0.2,0.3-0.2,0.8,0.2,1l2.2,1.7c0.3,0.3,0.8,0.2,1.1-0.1c1.2-1.5,1.9-2.3,3.7-2.3c1.3,0,2.9,0.8,2.9,2.1c0,1-0.8,1.5-2.1,2.2c-1.5,0.9-3.5,1.9-3.5,4.6v0.3c0,0.4,0.3,0.8,0.8,0.8h3.6c0.4,0,0.8-0.3,0.8-0.8v-0.1c0-1.8,5.4-1.9,5.4-6.9C23.9,8.1,20.1,5.3,16.4,5.3z M16,21.3c-1.6,0-3,1.3-3,3c0,1.6,1.3,3,3,3s3-1.3,3-3C19,22.6,17.6,21.3,16,21.3z"/>';
     }
 
     if (['error', 'warning', 'status', 'info'].indexOf(type) > -1) {
@@ -53,7 +73,9 @@
       </div>
     </div>
     `;
+
     Drupal.olivero.closeMessage(messageWrapper);
+
     return messageWrapper;
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/themes/olivero/js/messages.es6.js b/core/themes/olivero/js/messages.es6.js
deleted file mode 100644
index 942e7ca40887..000000000000
--- a/core/themes/olivero/js/messages.es6.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * @file
- * Customization of messages.
- */
-
-((Drupal, once) => {
-  /**
-   * Adds a close button to the message.
-   *
-   * @param {object} message
-   *   The message object.
-   */
-  const closeMessage = (message) => {
-    const messageContainer = message.querySelector(
-      '[data-drupal-selector="messages-container"]',
-    );
-
-    const closeBtnWrapper = document.createElement('div');
-    closeBtnWrapper.setAttribute('class', 'messages__button');
-
-    const closeBtn = document.createElement('button');
-    closeBtn.setAttribute('type', 'button');
-    closeBtn.setAttribute('class', 'messages__close');
-
-    const closeBtnText = document.createElement('span');
-    closeBtnText.setAttribute('class', 'visually-hidden');
-    closeBtnText.innerText = Drupal.t('Close message');
-
-    messageContainer.appendChild(closeBtnWrapper);
-    closeBtnWrapper.appendChild(closeBtn);
-    closeBtn.appendChild(closeBtnText);
-
-    closeBtn.addEventListener('click', () => {
-      message.classList.add('hidden');
-    });
-  };
-
-  /**
-   * Get messages from context.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the close button behavior for messages.
-   */
-  Drupal.behaviors.messages = {
-    attach(context) {
-      once('messages', '[data-drupal-selector="messages"]', context).forEach(
-        closeMessage,
-      );
-    },
-  };
-
-  Drupal.olivero.closeMessage = closeMessage;
-})(Drupal, once);
diff --git a/core/themes/olivero/js/messages.js b/core/themes/olivero/js/messages.js
index cd67c5dca585..942e7ca40887 100644
--- a/core/themes/olivero/js/messages.js
+++ b/core/themes/olivero/js/messages.js
@@ -1,34 +1,55 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Customization of messages.
+ */
 
 ((Drupal, once) => {
-  const closeMessage = message => {
-    const messageContainer = message.querySelector('[data-drupal-selector="messages-container"]');
+  /**
+   * Adds a close button to the message.
+   *
+   * @param {object} message
+   *   The message object.
+   */
+  const closeMessage = (message) => {
+    const messageContainer = message.querySelector(
+      '[data-drupal-selector="messages-container"]',
+    );
+
     const closeBtnWrapper = document.createElement('div');
     closeBtnWrapper.setAttribute('class', 'messages__button');
+
     const closeBtn = document.createElement('button');
     closeBtn.setAttribute('type', 'button');
     closeBtn.setAttribute('class', 'messages__close');
+
     const closeBtnText = document.createElement('span');
     closeBtnText.setAttribute('class', 'visually-hidden');
     closeBtnText.innerText = Drupal.t('Close message');
+
     messageContainer.appendChild(closeBtnWrapper);
     closeBtnWrapper.appendChild(closeBtn);
     closeBtn.appendChild(closeBtnText);
+
     closeBtn.addEventListener('click', () => {
       message.classList.add('hidden');
     });
   };
 
+  /**
+   * Get messages from context.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the close button behavior for messages.
+   */
   Drupal.behaviors.messages = {
     attach(context) {
-      once('messages', '[data-drupal-selector="messages"]', context).forEach(closeMessage);
-    }
-
+      once('messages', '[data-drupal-selector="messages"]', context).forEach(
+        closeMessage,
+      );
+    },
   };
+
   Drupal.olivero.closeMessage = closeMessage;
-})(Drupal, once);
\ No newline at end of file
+})(Drupal, once);
diff --git a/core/themes/olivero/js/nav-resize.es6.js b/core/themes/olivero/js/nav-resize.es6.js
deleted file mode 100644
index 387bbb447dc9..000000000000
--- a/core/themes/olivero/js/nav-resize.es6.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * @file
- * This script watches the desktop version of the primary navigation. If it
- * wraps to two lines, it will automatically transition to a mobile navigation
- * and remember where it wrapped so it can transition back.
- */
-((Drupal, once) => {
-  /**
-   * Handles the transition from mobile navigation to desktop navigation.
-   *
-   * @param {Element} navWrapper - The primary navigation's top-level <ul> element.
-   * @param {Element} navItem - The first item within the primary navigation.
-   */
-  function transitionToDesktopNavigation(navWrapper, navItem) {
-    document.body.classList.remove('is-always-mobile-nav');
-
-    // Double check to see if the navigation is wrapping, and if so, re-enable
-    // mobile navigation. This solves an edge cases where if the amount of
-    // navigation items always causes the primary navigation to wrap, and the
-    // page is loaded at a narrower viewport and then widened, the mobile nav
-    // may not be enabled.
-    if (navWrapper.clientHeight > navItem.clientHeight) {
-      document.body.classList.add('is-always-mobile-nav');
-    }
-  }
-
-  /**
-   * Callback from Resize Observer. This checks if the primary navigation is
-   * wrapping, and if so, transitions to the mobile navigation.
-   *
-   * @param {ResizeObserverEntry} entries - Object passed from ResizeObserver.
-   */
-  function checkIfDesktopNavigationWraps(entries) {
-    const navItem = document.querySelector('.primary-nav__menu-item');
-
-    if (
-      Drupal.olivero.isDesktopNav() &&
-      entries[0].contentRect.height > navItem.clientHeight
-    ) {
-      const navMediaQuery = window.matchMedia(
-        `(max-width: ${window.innerWidth + 15}px)`, // 5px adds a small buffer before switching back.
-      );
-      document.body.classList.add('is-always-mobile-nav');
-
-      // In the event that the viewport was resized, we remember the viewport
-      // width with a one-time event listener ,so we can attempt to transition
-      // from mobile navigation to desktop navigation.
-      navMediaQuery.addEventListener(
-        'change',
-        () => {
-          transitionToDesktopNavigation(entries[0].target, navItem);
-        },
-        { once: true },
-      );
-    }
-  }
-
-  /**
-   * Set up Resize Observer to listen for changes to the size of the primary
-   * navigation.
-   *
-   * @param {Element} primaryNav - The primary navigation's top-level <ul> element.
-   */
-  function init(primaryNav) {
-    const resizeObserver = new ResizeObserver(checkIfDesktopNavigationWraps);
-    resizeObserver.observe(primaryNav);
-  }
-
-  /**
-   * Initialize the automatic navigation transition.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attach context and settings for navigation.
-   */
-  Drupal.behaviors.automaticMobileNav = {
-    attach(context) {
-      once(
-        'olivero-automatic-mobile-nav',
-        '[data-drupal-selector="primary-nav-menu--level-1"]',
-        context,
-      ).forEach(init);
-    },
-  };
-})(Drupal, once);
diff --git a/core/themes/olivero/js/nav-resize.js b/core/themes/olivero/js/nav-resize.js
index 3f3f8a20882f..387bbb447dc9 100644
--- a/core/themes/olivero/js/nav-resize.js
+++ b/core/themes/olivero/js/nav-resize.js
@@ -1,42 +1,86 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
+ * @file
+ * This script watches the desktop version of the primary navigation. If it
+ * wraps to two lines, it will automatically transition to a mobile navigation
+ * and remember where it wrapped so it can transition back.
+ */
 ((Drupal, once) => {
+  /**
+   * Handles the transition from mobile navigation to desktop navigation.
+   *
+   * @param {Element} navWrapper - The primary navigation's top-level <ul> element.
+   * @param {Element} navItem - The first item within the primary navigation.
+   */
   function transitionToDesktopNavigation(navWrapper, navItem) {
     document.body.classList.remove('is-always-mobile-nav');
 
+    // Double check to see if the navigation is wrapping, and if so, re-enable
+    // mobile navigation. This solves an edge cases where if the amount of
+    // navigation items always causes the primary navigation to wrap, and the
+    // page is loaded at a narrower viewport and then widened, the mobile nav
+    // may not be enabled.
     if (navWrapper.clientHeight > navItem.clientHeight) {
       document.body.classList.add('is-always-mobile-nav');
     }
   }
 
+  /**
+   * Callback from Resize Observer. This checks if the primary navigation is
+   * wrapping, and if so, transitions to the mobile navigation.
+   *
+   * @param {ResizeObserverEntry} entries - Object passed from ResizeObserver.
+   */
   function checkIfDesktopNavigationWraps(entries) {
     const navItem = document.querySelector('.primary-nav__menu-item');
 
-    if (Drupal.olivero.isDesktopNav() && entries[0].contentRect.height > navItem.clientHeight) {
-      const navMediaQuery = window.matchMedia(`(max-width: ${window.innerWidth + 15}px)`);
+    if (
+      Drupal.olivero.isDesktopNav() &&
+      entries[0].contentRect.height > navItem.clientHeight
+    ) {
+      const navMediaQuery = window.matchMedia(
+        `(max-width: ${window.innerWidth + 15}px)`, // 5px adds a small buffer before switching back.
+      );
       document.body.classList.add('is-always-mobile-nav');
-      navMediaQuery.addEventListener('change', () => {
-        transitionToDesktopNavigation(entries[0].target, navItem);
-      }, {
-        once: true
-      });
+
+      // In the event that the viewport was resized, we remember the viewport
+      // width with a one-time event listener ,so we can attempt to transition
+      // from mobile navigation to desktop navigation.
+      navMediaQuery.addEventListener(
+        'change',
+        () => {
+          transitionToDesktopNavigation(entries[0].target, navItem);
+        },
+        { once: true },
+      );
     }
   }
 
+  /**
+   * Set up Resize Observer to listen for changes to the size of the primary
+   * navigation.
+   *
+   * @param {Element} primaryNav - The primary navigation's top-level <ul> element.
+   */
   function init(primaryNav) {
     const resizeObserver = new ResizeObserver(checkIfDesktopNavigationWraps);
     resizeObserver.observe(primaryNav);
   }
 
+  /**
+   * Initialize the automatic navigation transition.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach context and settings for navigation.
+   */
   Drupal.behaviors.automaticMobileNav = {
     attach(context) {
-      once('olivero-automatic-mobile-nav', '[data-drupal-selector="primary-nav-menu--level-1"]', context).forEach(init);
-    }
-
+      once(
+        'olivero-automatic-mobile-nav',
+        '[data-drupal-selector="primary-nav-menu--level-1"]',
+        context,
+      ).forEach(init);
+    },
   };
-})(Drupal, once);
\ No newline at end of file
+})(Drupal, once);
diff --git a/core/themes/olivero/js/navigation-utils.es6.js b/core/themes/olivero/js/navigation-utils.es6.js
deleted file mode 100644
index 4530c9a03b3a..000000000000
--- a/core/themes/olivero/js/navigation-utils.es6.js
+++ /dev/null
@@ -1,222 +0,0 @@
-/**
- * @file
- * Controls the visibility of desktop navigation.
- *
- * Shows and hides the desktop navigation based on scroll position and controls
- * the functionality of the button that shows/hides the navigation.
- */
-
-/* eslint-disable no-inner-declarations */
-((Drupal) => {
-  /**
-   * Olivero helper functions.
-   *
-   * @namespace
-   */
-  Drupal.olivero = {};
-
-  /**
-   * Checks if the mobile navigation button is visible.
-   *
-   * @return {boolean}
-   *   True if navButtons is hidden, false if not.
-   */
-  function isDesktopNav() {
-    const navButtons = document.querySelector(
-      '[data-drupal-selector="mobile-buttons"]',
-    );
-    return navButtons
-      ? window.getComputedStyle(navButtons).getPropertyValue('display') ===
-          'none'
-      : false;
-  }
-
-  Drupal.olivero.isDesktopNav = isDesktopNav;
-
-  const stickyHeaderToggleButton = document.querySelector(
-    '[data-drupal-selector="sticky-header-toggle"]',
-  );
-  const siteHeaderFixable = document.querySelector(
-    '[data-drupal-selector="site-header-fixable"]',
-  );
-
-  /**
-   * Checks if the sticky header is enabled.
-   *
-   * @return {boolean}
-   *   True if sticky header is enabled, false if not.
-   */
-  function stickyHeaderIsEnabled() {
-    return stickyHeaderToggleButton.getAttribute('aria-checked') === 'true';
-  }
-
-  /**
-   * Save the current sticky header expanded state to localStorage, and set
-   * it to expire after two weeks.
-   *
-   * @param {boolean} expandedState
-   *   Current state of the sticky header button.
-   */
-  function setStickyHeaderStorage(expandedState) {
-    const now = new Date();
-
-    const item = {
-      value: expandedState,
-      expiry: now.getTime() + 20160000, // 2 weeks from now.
-    };
-    localStorage.setItem(
-      'Drupal.olivero.stickyHeaderState',
-      JSON.stringify(item),
-    );
-  }
-
-  /**
-   * Toggle the state of the sticky header between always pinned and
-   * only pinned when scrolled to the top of the viewport.
-   *
-   * @param {boolean} pinnedState
-   *   State to change the sticky header to.
-   */
-  function toggleStickyHeaderState(pinnedState) {
-    if (isDesktopNav()) {
-      if (pinnedState === true) {
-        siteHeaderFixable.classList.add('is-expanded');
-      } else {
-        siteHeaderFixable.classList.remove('is-expanded');
-      }
-
-      stickyHeaderToggleButton.setAttribute('aria-checked', pinnedState);
-      setStickyHeaderStorage(pinnedState);
-    }
-  }
-
-  /**
-   * Return the sticky header's stored state from localStorage.
-   *
-   * @return {boolean}
-   *   Stored state of the sticky header.
-   */
-  function getStickyHeaderStorage() {
-    const stickyHeaderState = localStorage.getItem(
-      'Drupal.olivero.stickyHeaderState',
-    );
-
-    if (!stickyHeaderState) return false;
-
-    const item = JSON.parse(stickyHeaderState);
-    const now = new Date();
-
-    // Compare the expiry time of the item with the current time.
-    if (now.getTime() > item.expiry) {
-      // If the item is expired, delete the item from storage and return null.
-      localStorage.removeItem('Drupal.olivero.stickyHeaderState');
-      return false;
-    }
-    return item.value;
-  }
-
-  // Only enable scroll interactivity if the browser supports Intersection
-  // Observer.
-  // @see https://github.com/w3c/IntersectionObserver/blob/master/polyfill/intersection-observer.js#L19-L21
-  if (
-    'IntersectionObserver' in window &&
-    'IntersectionObserverEntry' in window &&
-    'intersectionRatio' in window.IntersectionObserverEntry.prototype
-  ) {
-    const fixableElements = document.querySelectorAll(
-      '[data-drupal-selector="site-header-fixable"], [data-drupal-selector="social-bar-inner"]',
-    );
-
-    function toggleDesktopNavVisibility(entries) {
-      if (!isDesktopNav()) return;
-
-      entries.forEach((entry) => {
-        // Firefox doesn't seem to support entry.isIntersecting properly,
-        // so we check the intersectionRatio.
-        if (entry.intersectionRatio < 1) {
-          fixableElements.forEach((el) => el.classList.add('is-fixed'));
-        } else {
-          fixableElements.forEach((el) => el.classList.remove('is-fixed'));
-        }
-      });
-    }
-
-    /**
-     * Gets the root margin by checking for various toolbar classes.
-     *
-     * @return {string}
-     *   Root margin for the Intersection Observer options object.
-     */
-    function getRootMargin() {
-      let rootMarginTop = 72;
-      const { body } = document;
-
-      if (body.classList.contains('toolbar-fixed')) {
-        rootMarginTop -= 39;
-      }
-
-      if (
-        body.classList.contains('toolbar-horizontal') &&
-        body.classList.contains('toolbar-tray-open')
-      ) {
-        rootMarginTop -= 40;
-      }
-
-      return `${rootMarginTop}px 0px 0px 0px`;
-    }
-
-    /**
-     * Monitor the navigation position.
-     */
-    function monitorNavPosition() {
-      const primaryNav = document.querySelector(
-        '[data-drupal-selector="site-header"]',
-      );
-      const options = {
-        rootMargin: getRootMargin(),
-        threshold: [0.999, 1],
-      };
-
-      const observer = new IntersectionObserver(
-        toggleDesktopNavVisibility,
-        options,
-      );
-
-      if (primaryNav) {
-        observer.observe(primaryNav);
-      }
-    }
-
-    if (stickyHeaderToggleButton) {
-      stickyHeaderToggleButton.addEventListener('click', () => {
-        toggleStickyHeaderState(!stickyHeaderIsEnabled());
-      });
-    }
-
-    // If header is pinned open and a header element gains focus, scroll to the
-    // top of the page to ensure that the header elements can be seen.
-    const siteHeaderInner = document.querySelector(
-      '[data-drupal-selector="site-header-inner"]',
-    );
-    if (siteHeaderInner) {
-      siteHeaderInner.addEventListener('focusin', () => {
-        if (isDesktopNav() && !stickyHeaderIsEnabled()) {
-          const header = document.querySelector(
-            '[data-drupal-selector="site-header"]',
-          );
-          const headerNav = header.querySelector(
-            '[data-drupal-selector="header-nav"]',
-          );
-          const headerMargin = header.clientHeight - headerNav.clientHeight;
-          if (window.scrollY > headerMargin) {
-            window.scrollTo(0, headerMargin);
-          }
-        }
-      });
-    }
-
-    monitorNavPosition();
-    setStickyHeaderStorage(getStickyHeaderStorage());
-    toggleStickyHeaderState(getStickyHeaderStorage());
-  }
-})(Drupal);
diff --git a/core/themes/olivero/js/navigation-utils.js b/core/themes/olivero/js/navigation-utils.js
index fb22bee3eafa..4530c9a03b3a 100644
--- a/core/themes/olivero/js/navigation-utils.js
+++ b/core/themes/olivero/js/navigation-utils.js
@@ -1,35 +1,82 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(Drupal => {
+ * @file
+ * Controls the visibility of desktop navigation.
+ *
+ * Shows and hides the desktop navigation based on scroll position and controls
+ * the functionality of the button that shows/hides the navigation.
+ */
+
+/* eslint-disable no-inner-declarations */
+((Drupal) => {
+  /**
+   * Olivero helper functions.
+   *
+   * @namespace
+   */
   Drupal.olivero = {};
 
+  /**
+   * Checks if the mobile navigation button is visible.
+   *
+   * @return {boolean}
+   *   True if navButtons is hidden, false if not.
+   */
   function isDesktopNav() {
-    const navButtons = document.querySelector('[data-drupal-selector="mobile-buttons"]');
-    return navButtons ? window.getComputedStyle(navButtons).getPropertyValue('display') === 'none' : false;
+    const navButtons = document.querySelector(
+      '[data-drupal-selector="mobile-buttons"]',
+    );
+    return navButtons
+      ? window.getComputedStyle(navButtons).getPropertyValue('display') ===
+          'none'
+      : false;
   }
 
   Drupal.olivero.isDesktopNav = isDesktopNav;
-  const stickyHeaderToggleButton = document.querySelector('[data-drupal-selector="sticky-header-toggle"]');
-  const siteHeaderFixable = document.querySelector('[data-drupal-selector="site-header-fixable"]');
 
+  const stickyHeaderToggleButton = document.querySelector(
+    '[data-drupal-selector="sticky-header-toggle"]',
+  );
+  const siteHeaderFixable = document.querySelector(
+    '[data-drupal-selector="site-header-fixable"]',
+  );
+
+  /**
+   * Checks if the sticky header is enabled.
+   *
+   * @return {boolean}
+   *   True if sticky header is enabled, false if not.
+   */
   function stickyHeaderIsEnabled() {
     return stickyHeaderToggleButton.getAttribute('aria-checked') === 'true';
   }
 
+  /**
+   * Save the current sticky header expanded state to localStorage, and set
+   * it to expire after two weeks.
+   *
+   * @param {boolean} expandedState
+   *   Current state of the sticky header button.
+   */
   function setStickyHeaderStorage(expandedState) {
     const now = new Date();
+
     const item = {
       value: expandedState,
-      expiry: now.getTime() + 20160000
+      expiry: now.getTime() + 20160000, // 2 weeks from now.
     };
-    localStorage.setItem('Drupal.olivero.stickyHeaderState', JSON.stringify(item));
+    localStorage.setItem(
+      'Drupal.olivero.stickyHeaderState',
+      JSON.stringify(item),
+    );
   }
 
+  /**
+   * Toggle the state of the sticky header between always pinned and
+   * only pinned when scrolled to the top of the viewport.
+   *
+   * @param {boolean} pinnedState
+   *   State to change the sticky header to.
+   */
   function toggleStickyHeaderState(pinnedState) {
     if (isDesktopNav()) {
       if (pinnedState === true) {
@@ -43,58 +90,97 @@
     }
   }
 
+  /**
+   * Return the sticky header's stored state from localStorage.
+   *
+   * @return {boolean}
+   *   Stored state of the sticky header.
+   */
   function getStickyHeaderStorage() {
-    const stickyHeaderState = localStorage.getItem('Drupal.olivero.stickyHeaderState');
+    const stickyHeaderState = localStorage.getItem(
+      'Drupal.olivero.stickyHeaderState',
+    );
+
     if (!stickyHeaderState) return false;
+
     const item = JSON.parse(stickyHeaderState);
     const now = new Date();
 
+    // Compare the expiry time of the item with the current time.
     if (now.getTime() > item.expiry) {
+      // If the item is expired, delete the item from storage and return null.
       localStorage.removeItem('Drupal.olivero.stickyHeaderState');
       return false;
     }
-
     return item.value;
   }
 
-  if ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype) {
-    const fixableElements = document.querySelectorAll('[data-drupal-selector="site-header-fixable"], [data-drupal-selector="social-bar-inner"]');
+  // Only enable scroll interactivity if the browser supports Intersection
+  // Observer.
+  // @see https://github.com/w3c/IntersectionObserver/blob/master/polyfill/intersection-observer.js#L19-L21
+  if (
+    'IntersectionObserver' in window &&
+    'IntersectionObserverEntry' in window &&
+    'intersectionRatio' in window.IntersectionObserverEntry.prototype
+  ) {
+    const fixableElements = document.querySelectorAll(
+      '[data-drupal-selector="site-header-fixable"], [data-drupal-selector="social-bar-inner"]',
+    );
 
     function toggleDesktopNavVisibility(entries) {
       if (!isDesktopNav()) return;
-      entries.forEach(entry => {
+
+      entries.forEach((entry) => {
+        // Firefox doesn't seem to support entry.isIntersecting properly,
+        // so we check the intersectionRatio.
         if (entry.intersectionRatio < 1) {
-          fixableElements.forEach(el => el.classList.add('is-fixed'));
+          fixableElements.forEach((el) => el.classList.add('is-fixed'));
         } else {
-          fixableElements.forEach(el => el.classList.remove('is-fixed'));
+          fixableElements.forEach((el) => el.classList.remove('is-fixed'));
         }
       });
     }
 
+    /**
+     * Gets the root margin by checking for various toolbar classes.
+     *
+     * @return {string}
+     *   Root margin for the Intersection Observer options object.
+     */
     function getRootMargin() {
       let rootMarginTop = 72;
-      const {
-        body
-      } = document;
+      const { body } = document;
 
       if (body.classList.contains('toolbar-fixed')) {
         rootMarginTop -= 39;
       }
 
-      if (body.classList.contains('toolbar-horizontal') && body.classList.contains('toolbar-tray-open')) {
+      if (
+        body.classList.contains('toolbar-horizontal') &&
+        body.classList.contains('toolbar-tray-open')
+      ) {
         rootMarginTop -= 40;
       }
 
       return `${rootMarginTop}px 0px 0px 0px`;
     }
 
+    /**
+     * Monitor the navigation position.
+     */
     function monitorNavPosition() {
-      const primaryNav = document.querySelector('[data-drupal-selector="site-header"]');
+      const primaryNav = document.querySelector(
+        '[data-drupal-selector="site-header"]',
+      );
       const options = {
         rootMargin: getRootMargin(),
-        threshold: [0.999, 1]
+        threshold: [0.999, 1],
       };
-      const observer = new IntersectionObserver(toggleDesktopNavVisibility, options);
+
+      const observer = new IntersectionObserver(
+        toggleDesktopNavVisibility,
+        options,
+      );
 
       if (primaryNav) {
         observer.observe(primaryNav);
@@ -107,15 +193,21 @@
       });
     }
 
-    const siteHeaderInner = document.querySelector('[data-drupal-selector="site-header-inner"]');
-
+    // If header is pinned open and a header element gains focus, scroll to the
+    // top of the page to ensure that the header elements can be seen.
+    const siteHeaderInner = document.querySelector(
+      '[data-drupal-selector="site-header-inner"]',
+    );
     if (siteHeaderInner) {
       siteHeaderInner.addEventListener('focusin', () => {
         if (isDesktopNav() && !stickyHeaderIsEnabled()) {
-          const header = document.querySelector('[data-drupal-selector="site-header"]');
-          const headerNav = header.querySelector('[data-drupal-selector="header-nav"]');
+          const header = document.querySelector(
+            '[data-drupal-selector="site-header"]',
+          );
+          const headerNav = header.querySelector(
+            '[data-drupal-selector="header-nav"]',
+          );
           const headerMargin = header.clientHeight - headerNav.clientHeight;
-
           if (window.scrollY > headerMargin) {
             window.scrollTo(0, headerMargin);
           }
@@ -127,4 +219,4 @@
     setStickyHeaderStorage(getStickyHeaderStorage());
     toggleStickyHeaderState(getStickyHeaderStorage());
   }
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/themes/olivero/js/navigation.es6.js b/core/themes/olivero/js/navigation.es6.js
deleted file mode 100644
index f24e6c901f1f..000000000000
--- a/core/themes/olivero/js/navigation.es6.js
+++ /dev/null
@@ -1,167 +0,0 @@
-/**
- * @file
- * Customization of navigation.
- */
-
-((Drupal, once, tabbable) => {
-  /**
-   * Checks if navWrapper contains "is-active" class.
-   *
-   * @param {Element} navWrapper
-   *   Header navigation.
-   *
-   * @return {boolean}
-   *   True if navWrapper contains "is-active" class, false if not.
-   */
-  function isNavOpen(navWrapper) {
-    return navWrapper.classList.contains('is-active');
-  }
-
-  /**
-   * Opens or closes the header navigation.
-   *
-   * @param {object} props
-   *   Navigation props.
-   * @param {boolean} state
-   *   State which to transition the header navigation menu into.
-   */
-  function toggleNav(props, state) {
-    const value = !!state;
-    props.navButton.setAttribute('aria-expanded', value);
-
-    if (value) {
-      props.body.classList.add('is-overlay-active');
-      props.body.classList.add('is-fixed');
-      props.navWrapper.classList.add('is-active');
-    } else {
-      props.body.classList.remove('is-overlay-active');
-      props.body.classList.remove('is-fixed');
-      props.navWrapper.classList.remove('is-active');
-    }
-  }
-
-  /**
-   * Initialize the header navigation.
-   *
-   * @param {object} props
-   *   Navigation props.
-   */
-  function init(props) {
-    props.navButton.setAttribute('aria-controls', props.navWrapperId);
-    props.navButton.setAttribute('aria-expanded', 'false');
-
-    props.navButton.addEventListener('click', () => {
-      toggleNav(props, !isNavOpen(props.navWrapper));
-    });
-
-    // Close any open sub-navigation first, then close the header navigation.
-    document.addEventListener('keyup', (e) => {
-      if (e.key === 'Escape') {
-        if (props.olivero.areAnySubNavsOpen()) {
-          props.olivero.closeAllSubNav();
-        } else {
-          toggleNav(props, false);
-        }
-      }
-    });
-
-    props.overlay.addEventListener('click', () => {
-      toggleNav(props, false);
-    });
-
-    props.overlay.addEventListener('touchstart', () => {
-      toggleNav(props, false);
-    });
-
-    // Focus trap. This is added to the header element because the navButton
-    // element is not a child element of the navWrapper element, and the keydown
-    // event would not fire if focus is on the navButton element.
-    props.header.addEventListener('keydown', (e) => {
-      if (e.key === 'Tab' && isNavOpen(props.navWrapper)) {
-        const tabbableNavElements = tabbable.tabbable(props.navWrapper);
-        tabbableNavElements.unshift(props.navButton);
-        const firstTabbableEl = tabbableNavElements[0];
-        const lastTabbableEl =
-          tabbableNavElements[tabbableNavElements.length - 1];
-
-        if (e.shiftKey) {
-          if (
-            document.activeElement === firstTabbableEl &&
-            !props.olivero.isDesktopNav()
-          ) {
-            lastTabbableEl.focus();
-            e.preventDefault();
-          }
-        } else if (
-          document.activeElement === lastTabbableEl &&
-          !props.olivero.isDesktopNav()
-        ) {
-          firstTabbableEl.focus();
-          e.preventDefault();
-        }
-      }
-    });
-
-    // Remove overlays when browser is resized and desktop nav appears.
-    window.addEventListener('resize', () => {
-      if (props.olivero.isDesktopNav()) {
-        toggleNav(props, false);
-        props.body.classList.remove('is-overlay-active');
-        props.body.classList.remove('is-fixed');
-      }
-
-      // Ensure that all sub-navigation menus close when the browser is resized.
-      Drupal.olivero.closeAllSubNav();
-    });
-
-    // If hyperlink links to an anchor in the current page, close the
-    // mobile menu after the click.
-    props.navWrapper.addEventListener('click', (e) => {
-      if (
-        e.target.matches(
-          `[href*="${window.location.pathname}#"], [href*="${window.location.pathname}#"] *, [href^="#"], [href^="#"] *`,
-        )
-      ) {
-        toggleNav(props, false);
-      }
-    });
-  }
-
-  /**
-   * Initialize the navigation.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attach context and settings for navigation.
-   */
-  Drupal.behaviors.oliveroNavigation = {
-    attach(context) {
-      const headerId = 'header';
-      const header = once('navigation', `#${headerId}`, context).shift();
-      const navWrapperId = 'header-nav';
-
-      if (header) {
-        const navWrapper = header.querySelector(`#${navWrapperId}`);
-        const { olivero } = Drupal;
-        const navButton = context.querySelector(
-          '[data-drupal-selector="mobile-nav-button"]',
-        );
-        const body = context.querySelector('body');
-        const overlay = context.querySelector(
-          '[data-drupal-selector="header-nav-overlay"]',
-        );
-
-        init({
-          olivero,
-          header,
-          navWrapperId,
-          navWrapper,
-          navButton,
-          body,
-          overlay,
-        });
-      }
-    },
-  };
-})(Drupal, once, tabbable);
diff --git a/core/themes/olivero/js/navigation.js b/core/themes/olivero/js/navigation.js
index eb0b8a401594..f24e6c901f1f 100644
--- a/core/themes/olivero/js/navigation.js
+++ b/core/themes/olivero/js/navigation.js
@@ -1,15 +1,30 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Customization of navigation.
+ */
 
 ((Drupal, once, tabbable) => {
+  /**
+   * Checks if navWrapper contains "is-active" class.
+   *
+   * @param {Element} navWrapper
+   *   Header navigation.
+   *
+   * @return {boolean}
+   *   True if navWrapper contains "is-active" class, false if not.
+   */
   function isNavOpen(navWrapper) {
     return navWrapper.classList.contains('is-active');
   }
 
+  /**
+   * Opens or closes the header navigation.
+   *
+   * @param {object} props
+   *   Navigation props.
+   * @param {boolean} state
+   *   State which to transition the header navigation menu into.
+   */
   function toggleNav(props, state) {
     const value = !!state;
     props.navButton.setAttribute('aria-expanded', value);
@@ -25,13 +40,22 @@
     }
   }
 
+  /**
+   * Initialize the header navigation.
+   *
+   * @param {object} props
+   *   Navigation props.
+   */
   function init(props) {
     props.navButton.setAttribute('aria-controls', props.navWrapperId);
     props.navButton.setAttribute('aria-expanded', 'false');
+
     props.navButton.addEventListener('click', () => {
       toggleNav(props, !isNavOpen(props.navWrapper));
     });
-    document.addEventListener('keyup', e => {
+
+    // Close any open sub-navigation first, then close the header navigation.
+    document.addEventListener('keyup', (e) => {
       if (e.key === 'Escape') {
         if (props.olivero.areAnySubNavsOpen()) {
           props.olivero.closeAllSubNav();
@@ -40,30 +64,45 @@
         }
       }
     });
+
     props.overlay.addEventListener('click', () => {
       toggleNav(props, false);
     });
+
     props.overlay.addEventListener('touchstart', () => {
       toggleNav(props, false);
     });
-    props.header.addEventListener('keydown', e => {
+
+    // Focus trap. This is added to the header element because the navButton
+    // element is not a child element of the navWrapper element, and the keydown
+    // event would not fire if focus is on the navButton element.
+    props.header.addEventListener('keydown', (e) => {
       if (e.key === 'Tab' && isNavOpen(props.navWrapper)) {
         const tabbableNavElements = tabbable.tabbable(props.navWrapper);
         tabbableNavElements.unshift(props.navButton);
         const firstTabbableEl = tabbableNavElements[0];
-        const lastTabbableEl = tabbableNavElements[tabbableNavElements.length - 1];
+        const lastTabbableEl =
+          tabbableNavElements[tabbableNavElements.length - 1];
 
         if (e.shiftKey) {
-          if (document.activeElement === firstTabbableEl && !props.olivero.isDesktopNav()) {
+          if (
+            document.activeElement === firstTabbableEl &&
+            !props.olivero.isDesktopNav()
+          ) {
             lastTabbableEl.focus();
             e.preventDefault();
           }
-        } else if (document.activeElement === lastTabbableEl && !props.olivero.isDesktopNav()) {
+        } else if (
+          document.activeElement === lastTabbableEl &&
+          !props.olivero.isDesktopNav()
+        ) {
           firstTabbableEl.focus();
           e.preventDefault();
         }
       }
     });
+
+    // Remove overlays when browser is resized and desktop nav appears.
     window.addEventListener('resize', () => {
       if (props.olivero.isDesktopNav()) {
         toggleNav(props, false);
@@ -71,15 +110,31 @@
         props.body.classList.remove('is-fixed');
       }
 
+      // Ensure that all sub-navigation menus close when the browser is resized.
       Drupal.olivero.closeAllSubNav();
     });
-    props.navWrapper.addEventListener('click', e => {
-      if (e.target.matches(`[href*="${window.location.pathname}#"], [href*="${window.location.pathname}#"] *, [href^="#"], [href^="#"] *`)) {
+
+    // If hyperlink links to an anchor in the current page, close the
+    // mobile menu after the click.
+    props.navWrapper.addEventListener('click', (e) => {
+      if (
+        e.target.matches(
+          `[href*="${window.location.pathname}#"], [href*="${window.location.pathname}#"] *, [href^="#"], [href^="#"] *`,
+        )
+      ) {
         toggleNav(props, false);
       }
     });
   }
 
+  /**
+   * Initialize the navigation.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach context and settings for navigation.
+   */
   Drupal.behaviors.oliveroNavigation = {
     attach(context) {
       const headerId = 'header';
@@ -88,12 +143,15 @@
 
       if (header) {
         const navWrapper = header.querySelector(`#${navWrapperId}`);
-        const {
-          olivero
-        } = Drupal;
-        const navButton = context.querySelector('[data-drupal-selector="mobile-nav-button"]');
+        const { olivero } = Drupal;
+        const navButton = context.querySelector(
+          '[data-drupal-selector="mobile-nav-button"]',
+        );
         const body = context.querySelector('body');
-        const overlay = context.querySelector('[data-drupal-selector="header-nav-overlay"]');
+        const overlay = context.querySelector(
+          '[data-drupal-selector="header-nav-overlay"]',
+        );
+
         init({
           olivero,
           header,
@@ -101,10 +159,9 @@
           navWrapper,
           navButton,
           body,
-          overlay
+          overlay,
         });
       }
-    }
-
+    },
   };
-})(Drupal, once, tabbable);
\ No newline at end of file
+})(Drupal, once, tabbable);
diff --git a/core/themes/olivero/js/search.es6.js b/core/themes/olivero/js/search.es6.js
deleted file mode 100644
index 7626fd07f1c4..000000000000
--- a/core/themes/olivero/js/search.es6.js
+++ /dev/null
@@ -1,155 +0,0 @@
-/**
- * @file
- * Wide viewport search bar interactions.
- */
-
-((Drupal) => {
-  const searchWideButtonSelector =
-    '[data-drupal-selector="block-search-wide-button"]';
-  const searchWideButton = document.querySelector(searchWideButtonSelector);
-  const searchWideWrapperSelector =
-    '[data-drupal-selector="block-search-wide-wrapper"]';
-  const searchWideWrapper = document.querySelector(searchWideWrapperSelector);
-
-  /**
-   * Determine if search is visible.
-   *
-   * @return {boolean}
-   *   True if the search wrapper contains "is-active" class, false if not.
-   */
-  function searchIsVisible() {
-    return searchWideWrapper.classList.contains('is-active');
-  }
-  Drupal.olivero.searchIsVisible = searchIsVisible;
-
-  /**
-   * Closes search bar when a click event does not happen at an (x,y) coordinate
-   * that does not overlap with either the search wrapper or button.
-   *
-   * @see https://bugs.webkit.org/show_bug.cgi?id=229895
-   *
-   * @param {Event} e click event
-   */
-  function watchForClickOut(e) {
-    const clickInSearchArea = e.target.matches(`
-      ${searchWideWrapperSelector},
-      ${searchWideWrapperSelector} *,
-      ${searchWideButtonSelector},
-      ${searchWideButtonSelector} *
-    `);
-    if (!clickInSearchArea && searchIsVisible()) {
-      // eslint-disable-next-line no-use-before-define
-      toggleSearchVisibility(false);
-    }
-  }
-
-  /**
-   * Closes search bar when focus moves to another target.
-   * Avoids closing search bar if event does not have related target - required for Safari.
-   *
-   * @see https://bugs.webkit.org/show_bug.cgi?id=229895
-   *
-   * @param {Event} e focusout event
-   */
-  function watchForFocusOut(e) {
-    if (e.relatedTarget) {
-      const inSearchBar = e.relatedTarget.matches(
-        `${searchWideWrapperSelector}, ${searchWideWrapperSelector} *`,
-      );
-      const inSearchButton = e.relatedTarget.matches(
-        `${searchWideButtonSelector}, ${searchWideButtonSelector} *`,
-      );
-
-      if (!inSearchBar && !inSearchButton) {
-        // eslint-disable-next-line no-use-before-define
-        toggleSearchVisibility(false);
-      }
-    }
-  }
-
-  /**
-   * Closes search bar on escape keyup, if open.
-   *
-   * @param {Event} e keyup event
-   */
-  function watchForEscapeOut(e) {
-    if (e.key === 'Escape') {
-      // eslint-disable-next-line no-use-before-define
-      toggleSearchVisibility(false);
-    }
-  }
-
-  /**
-   * Set focus for the search input element.
-   */
-  function handleFocus() {
-    if (searchIsVisible()) {
-      searchWideWrapper.querySelector('input[type="search"]').focus();
-    } else if (searchWideWrapper.contains(document.activeElement)) {
-      // Return focus to button only if focus was inside of the search wrapper.
-      searchWideButton.focus();
-    }
-  }
-
-  /**
-   * Toggle search functionality visibility.
-   *
-   * @param {boolean} visibility
-   *   True if we want to show the form, false if we want to hide it.
-   */
-  function toggleSearchVisibility(visibility) {
-    searchWideButton.setAttribute('aria-expanded', visibility === true);
-    searchWideWrapper.addEventListener('transitionend', handleFocus, {
-      once: true,
-    });
-
-    if (visibility === true) {
-      Drupal.olivero.closeAllSubNav();
-      searchWideWrapper.classList.add('is-active');
-
-      document.addEventListener('click', watchForClickOut, { capture: true });
-      document.addEventListener('focusout', watchForFocusOut, {
-        capture: true,
-      });
-      document.addEventListener('keyup', watchForEscapeOut, { capture: true });
-    } else {
-      searchWideWrapper.classList.remove('is-active');
-
-      document.removeEventListener('click', watchForClickOut, {
-        capture: true,
-      });
-      document.removeEventListener('focusout', watchForFocusOut, {
-        capture: true,
-      });
-      document.removeEventListener('keyup', watchForEscapeOut, {
-        capture: true,
-      });
-    }
-  }
-
-  Drupal.olivero.toggleSearchVisibility = toggleSearchVisibility;
-
-  /**
-   * Initializes the search wide button.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *  Adds aria-expanded attribute to the search wide button.
-   */
-  Drupal.behaviors.searchWide = {
-    attach(context) {
-      const searchWideButtonEl = once(
-        'search-wide',
-        searchWideButtonSelector,
-        context,
-      ).shift();
-      if (searchWideButtonEl) {
-        searchWideButtonEl.setAttribute('aria-expanded', searchIsVisible());
-        searchWideButtonEl.addEventListener('click', () => {
-          toggleSearchVisibility(!searchIsVisible());
-        });
-      }
-    },
-  };
-})(Drupal);
diff --git a/core/themes/olivero/js/search.js b/core/themes/olivero/js/search.js
index ab51b273b1da..7626fd07f1c4 100644
--- a/core/themes/olivero/js/search.js
+++ b/core/themes/olivero/js/search.js
@@ -1,22 +1,35 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Wide viewport search bar interactions.
+ */
 
-(Drupal => {
-  const searchWideButtonSelector = '[data-drupal-selector="block-search-wide-button"]';
+((Drupal) => {
+  const searchWideButtonSelector =
+    '[data-drupal-selector="block-search-wide-button"]';
   const searchWideButton = document.querySelector(searchWideButtonSelector);
-  const searchWideWrapperSelector = '[data-drupal-selector="block-search-wide-wrapper"]';
+  const searchWideWrapperSelector =
+    '[data-drupal-selector="block-search-wide-wrapper"]';
   const searchWideWrapper = document.querySelector(searchWideWrapperSelector);
 
+  /**
+   * Determine if search is visible.
+   *
+   * @return {boolean}
+   *   True if the search wrapper contains "is-active" class, false if not.
+   */
   function searchIsVisible() {
     return searchWideWrapper.classList.contains('is-active');
   }
-
   Drupal.olivero.searchIsVisible = searchIsVisible;
 
+  /**
+   * Closes search bar when a click event does not happen at an (x,y) coordinate
+   * that does not overlap with either the search wrapper or button.
+   *
+   * @see https://bugs.webkit.org/show_bug.cgi?id=229895
+   *
+   * @param {Event} e click event
+   */
   function watchForClickOut(e) {
     const clickInSearchArea = e.target.matches(`
       ${searchWideWrapperSelector},
@@ -24,81 +37,119 @@
       ${searchWideButtonSelector},
       ${searchWideButtonSelector} *
     `);
-
     if (!clickInSearchArea && searchIsVisible()) {
+      // eslint-disable-next-line no-use-before-define
       toggleSearchVisibility(false);
     }
   }
 
+  /**
+   * Closes search bar when focus moves to another target.
+   * Avoids closing search bar if event does not have related target - required for Safari.
+   *
+   * @see https://bugs.webkit.org/show_bug.cgi?id=229895
+   *
+   * @param {Event} e focusout event
+   */
   function watchForFocusOut(e) {
     if (e.relatedTarget) {
-      const inSearchBar = e.relatedTarget.matches(`${searchWideWrapperSelector}, ${searchWideWrapperSelector} *`);
-      const inSearchButton = e.relatedTarget.matches(`${searchWideButtonSelector}, ${searchWideButtonSelector} *`);
+      const inSearchBar = e.relatedTarget.matches(
+        `${searchWideWrapperSelector}, ${searchWideWrapperSelector} *`,
+      );
+      const inSearchButton = e.relatedTarget.matches(
+        `${searchWideButtonSelector}, ${searchWideButtonSelector} *`,
+      );
 
       if (!inSearchBar && !inSearchButton) {
+        // eslint-disable-next-line no-use-before-define
         toggleSearchVisibility(false);
       }
     }
   }
 
+  /**
+   * Closes search bar on escape keyup, if open.
+   *
+   * @param {Event} e keyup event
+   */
   function watchForEscapeOut(e) {
     if (e.key === 'Escape') {
+      // eslint-disable-next-line no-use-before-define
       toggleSearchVisibility(false);
     }
   }
 
+  /**
+   * Set focus for the search input element.
+   */
   function handleFocus() {
     if (searchIsVisible()) {
       searchWideWrapper.querySelector('input[type="search"]').focus();
     } else if (searchWideWrapper.contains(document.activeElement)) {
+      // Return focus to button only if focus was inside of the search wrapper.
       searchWideButton.focus();
     }
   }
 
+  /**
+   * Toggle search functionality visibility.
+   *
+   * @param {boolean} visibility
+   *   True if we want to show the form, false if we want to hide it.
+   */
   function toggleSearchVisibility(visibility) {
     searchWideButton.setAttribute('aria-expanded', visibility === true);
     searchWideWrapper.addEventListener('transitionend', handleFocus, {
-      once: true
+      once: true,
     });
 
     if (visibility === true) {
       Drupal.olivero.closeAllSubNav();
       searchWideWrapper.classList.add('is-active');
-      document.addEventListener('click', watchForClickOut, {
-        capture: true
-      });
+
+      document.addEventListener('click', watchForClickOut, { capture: true });
       document.addEventListener('focusout', watchForFocusOut, {
-        capture: true
-      });
-      document.addEventListener('keyup', watchForEscapeOut, {
-        capture: true
+        capture: true,
       });
+      document.addEventListener('keyup', watchForEscapeOut, { capture: true });
     } else {
       searchWideWrapper.classList.remove('is-active');
+
       document.removeEventListener('click', watchForClickOut, {
-        capture: true
+        capture: true,
       });
       document.removeEventListener('focusout', watchForFocusOut, {
-        capture: true
+        capture: true,
       });
       document.removeEventListener('keyup', watchForEscapeOut, {
-        capture: true
+        capture: true,
       });
     }
   }
 
   Drupal.olivero.toggleSearchVisibility = toggleSearchVisibility;
+
+  /**
+   * Initializes the search wide button.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *  Adds aria-expanded attribute to the search wide button.
+   */
   Drupal.behaviors.searchWide = {
     attach(context) {
-      const searchWideButtonEl = once('search-wide', searchWideButtonSelector, context).shift();
-
+      const searchWideButtonEl = once(
+        'search-wide',
+        searchWideButtonSelector,
+        context,
+      ).shift();
       if (searchWideButtonEl) {
         searchWideButtonEl.setAttribute('aria-expanded', searchIsVisible());
         searchWideButtonEl.addEventListener('click', () => {
           toggleSearchVisibility(!searchIsVisible());
         });
       }
-    }
-
+    },
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/themes/olivero/js/second-level-navigation.es6.js b/core/themes/olivero/js/second-level-navigation.es6.js
deleted file mode 100644
index f8f9a98c5c3f..000000000000
--- a/core/themes/olivero/js/second-level-navigation.es6.js
+++ /dev/null
@@ -1,203 +0,0 @@
-/**
- * @file
- * Provides functionality for second level submenu navigation.
- */
-
-((Drupal) => {
-  const { isDesktopNav } = Drupal.olivero;
-  const secondLevelNavMenus = document.querySelectorAll(
-    '[data-drupal-selector="primary-nav-menu-item-has-children"]',
-  );
-
-  /**
-   * Shows and hides the specified menu item's second level submenu.
-   *
-   * @param {Element} topLevelMenuItem
-   *   The <li> element that is the container for the menu and submenus.
-   * @param {boolean} [toState]
-   *   Optional state where we want the submenu to end up.
-   */
-  function toggleSubNav(topLevelMenuItem, toState) {
-    const buttonSelector =
-      '[data-drupal-selector="primary-nav-submenu-toggle-button"]';
-    const button = topLevelMenuItem.querySelector(buttonSelector);
-    const state =
-      toState !== undefined
-        ? toState
-        : button.getAttribute('aria-expanded') !== 'true';
-
-    if (state) {
-      // If desktop nav, ensure all menus close before expanding new one.
-      if (isDesktopNav()) {
-        secondLevelNavMenus.forEach((el) => {
-          el.querySelector(buttonSelector).setAttribute(
-            'aria-expanded',
-            'false',
-          );
-          el.querySelector(
-            '[data-drupal-selector="primary-nav-menu--level-2"]',
-          ).classList.remove('is-active-menu-parent');
-          el.querySelector(
-            '[data-drupal-selector="primary-nav-menu-🥕"]',
-          ).classList.remove('is-active-menu-parent');
-        });
-      }
-      button.setAttribute('aria-expanded', 'true');
-      topLevelMenuItem
-        .querySelector('[data-drupal-selector="primary-nav-menu--level-2"]')
-        .classList.add('is-active-menu-parent');
-      topLevelMenuItem
-        .querySelector('[data-drupal-selector="primary-nav-menu-🥕"]')
-        .classList.add('is-active-menu-parent');
-    } else {
-      button.setAttribute('aria-expanded', 'false');
-      topLevelMenuItem.classList.remove('is-touch-event');
-      topLevelMenuItem
-        .querySelector('[data-drupal-selector="primary-nav-menu--level-2"]')
-        .classList.remove('is-active-menu-parent');
-      topLevelMenuItem
-        .querySelector('[data-drupal-selector="primary-nav-menu-🥕"]')
-        .classList.remove('is-active-menu-parent');
-    }
-  }
-
-  Drupal.olivero.toggleSubNav = toggleSubNav;
-
-  /**
-   * Sets a timeout and closes current desktop navigation submenu if it
-   * does not contain the focused element.
-   *
-   * @param {Event} e
-   *   The event object.
-   */
-  function handleBlur(e) {
-    if (!Drupal.olivero.isDesktopNav()) return;
-
-    setTimeout(() => {
-      const menuParentItem = e.target.closest(
-        '[data-drupal-selector="primary-nav-menu-item-has-children"]',
-      );
-      if (!menuParentItem.contains(document.activeElement)) {
-        toggleSubNav(menuParentItem, false);
-      }
-    }, 200);
-  }
-
-  // Add event listeners onto each sub navigation parent and button.
-  secondLevelNavMenus.forEach((el) => {
-    const button = el.querySelector(
-      '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
-    );
-
-    button.removeAttribute('aria-hidden');
-    button.removeAttribute('tabindex');
-
-    // If touch event, prevent mouseover event from triggering the submenu.
-    el.addEventListener(
-      'touchstart',
-      () => {
-        el.classList.add('is-touch-event');
-      },
-      { passive: true },
-    );
-
-    el.addEventListener('mouseover', () => {
-      if (isDesktopNav() && !el.classList.contains('is-touch-event')) {
-        el.classList.add('is-active-mouseover-event');
-        toggleSubNav(el, true);
-
-        // Timeout is added to ensure that users of assistive devices (such as
-        // mouse grid tools) do not simultaneously trigger both the mouseover
-        // and click events. When these events are triggered together, the
-        // submenu to appear to not open.
-        setTimeout(() => {
-          el.classList.remove('is-active-mouseover-event');
-        }, 500);
-      }
-    });
-
-    button.addEventListener('click', () => {
-      if (!el.classList.contains('is-active-mouseover-event')) {
-        toggleSubNav(el);
-      }
-    });
-
-    el.addEventListener('mouseout', () => {
-      if (
-        isDesktopNav() &&
-        !document.activeElement.matches(
-          '[aria-expanded="true"], .is-active-menu-parent *',
-        )
-      ) {
-        toggleSubNav(el, false);
-      }
-    });
-
-    el.addEventListener('blur', handleBlur, true);
-  });
-
-  /**
-   * Close all second level sub navigation menus.
-   */
-  function closeAllSubNav() {
-    secondLevelNavMenus.forEach((el) => {
-      // Return focus to the toggle button if the submenu contains focus.
-      if (el.contains(document.activeElement)) {
-        el.querySelector(
-          '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
-        ).focus();
-      }
-      toggleSubNav(el, false);
-    });
-  }
-
-  Drupal.olivero.closeAllSubNav = closeAllSubNav;
-
-  /**
-   * Checks if any sub navigation items are currently active.
-   *
-   * @return {boolean}
-   *   If sub navigation is currently open.
-   */
-  function areAnySubNavsOpen() {
-    let subNavsAreOpen = false;
-
-    secondLevelNavMenus.forEach((el) => {
-      const button = el.querySelector(
-        '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
-      );
-      const state = button.getAttribute('aria-expanded') === 'true';
-
-      if (state) {
-        subNavsAreOpen = true;
-      }
-    });
-
-    return subNavsAreOpen;
-  }
-
-  Drupal.olivero.areAnySubNavsOpen = areAnySubNavsOpen;
-
-  // Ensure that desktop submenus close when escape key is pressed.
-  document.addEventListener('keyup', (e) => {
-    if (e.key === 'Escape') {
-      if (isDesktopNav()) closeAllSubNav();
-    }
-  });
-
-  // If user taps outside of menu, close all menus.
-  document.addEventListener(
-    'touchstart',
-    (e) => {
-      if (
-        areAnySubNavsOpen() &&
-        !e.target.matches(
-          '[data-drupal-selector="header-nav"], [data-drupal-selector="header-nav"] *',
-        )
-      ) {
-        closeAllSubNav();
-      }
-    },
-    { passive: true },
-  );
-})(Drupal);
diff --git a/core/themes/olivero/js/second-level-navigation.js b/core/themes/olivero/js/second-level-navigation.js
index e02c01b47895..f8f9a98c5c3f 100644
--- a/core/themes/olivero/js/second-level-navigation.js
+++ b/core/themes/olivero/js/second-level-navigation.js
@@ -1,121 +1,203 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(Drupal => {
-  const {
-    isDesktopNav
-  } = Drupal.olivero;
-  const secondLevelNavMenus = document.querySelectorAll('[data-drupal-selector="primary-nav-menu-item-has-children"]');
+ * @file
+ * Provides functionality for second level submenu navigation.
+ */
 
+((Drupal) => {
+  const { isDesktopNav } = Drupal.olivero;
+  const secondLevelNavMenus = document.querySelectorAll(
+    '[data-drupal-selector="primary-nav-menu-item-has-children"]',
+  );
+
+  /**
+   * Shows and hides the specified menu item's second level submenu.
+   *
+   * @param {Element} topLevelMenuItem
+   *   The <li> element that is the container for the menu and submenus.
+   * @param {boolean} [toState]
+   *   Optional state where we want the submenu to end up.
+   */
   function toggleSubNav(topLevelMenuItem, toState) {
-    const buttonSelector = '[data-drupal-selector="primary-nav-submenu-toggle-button"]';
+    const buttonSelector =
+      '[data-drupal-selector="primary-nav-submenu-toggle-button"]';
     const button = topLevelMenuItem.querySelector(buttonSelector);
-    const state = toState !== undefined ? toState : button.getAttribute('aria-expanded') !== 'true';
+    const state =
+      toState !== undefined
+        ? toState
+        : button.getAttribute('aria-expanded') !== 'true';
 
     if (state) {
+      // If desktop nav, ensure all menus close before expanding new one.
       if (isDesktopNav()) {
-        secondLevelNavMenus.forEach(el => {
-          el.querySelector(buttonSelector).setAttribute('aria-expanded', 'false');
-          el.querySelector('[data-drupal-selector="primary-nav-menu--level-2"]').classList.remove('is-active-menu-parent');
-          el.querySelector('[data-drupal-selector="primary-nav-menu-🥕"]').classList.remove('is-active-menu-parent');
+        secondLevelNavMenus.forEach((el) => {
+          el.querySelector(buttonSelector).setAttribute(
+            'aria-expanded',
+            'false',
+          );
+          el.querySelector(
+            '[data-drupal-selector="primary-nav-menu--level-2"]',
+          ).classList.remove('is-active-menu-parent');
+          el.querySelector(
+            '[data-drupal-selector="primary-nav-menu-🥕"]',
+          ).classList.remove('is-active-menu-parent');
         });
       }
-
       button.setAttribute('aria-expanded', 'true');
-      topLevelMenuItem.querySelector('[data-drupal-selector="primary-nav-menu--level-2"]').classList.add('is-active-menu-parent');
-      topLevelMenuItem.querySelector('[data-drupal-selector="primary-nav-menu-🥕"]').classList.add('is-active-menu-parent');
+      topLevelMenuItem
+        .querySelector('[data-drupal-selector="primary-nav-menu--level-2"]')
+        .classList.add('is-active-menu-parent');
+      topLevelMenuItem
+        .querySelector('[data-drupal-selector="primary-nav-menu-🥕"]')
+        .classList.add('is-active-menu-parent');
     } else {
       button.setAttribute('aria-expanded', 'false');
       topLevelMenuItem.classList.remove('is-touch-event');
-      topLevelMenuItem.querySelector('[data-drupal-selector="primary-nav-menu--level-2"]').classList.remove('is-active-menu-parent');
-      topLevelMenuItem.querySelector('[data-drupal-selector="primary-nav-menu-🥕"]').classList.remove('is-active-menu-parent');
+      topLevelMenuItem
+        .querySelector('[data-drupal-selector="primary-nav-menu--level-2"]')
+        .classList.remove('is-active-menu-parent');
+      topLevelMenuItem
+        .querySelector('[data-drupal-selector="primary-nav-menu-🥕"]')
+        .classList.remove('is-active-menu-parent');
     }
   }
 
   Drupal.olivero.toggleSubNav = toggleSubNav;
 
+  /**
+   * Sets a timeout and closes current desktop navigation submenu if it
+   * does not contain the focused element.
+   *
+   * @param {Event} e
+   *   The event object.
+   */
   function handleBlur(e) {
     if (!Drupal.olivero.isDesktopNav()) return;
-    setTimeout(() => {
-      const menuParentItem = e.target.closest('[data-drupal-selector="primary-nav-menu-item-has-children"]');
 
+    setTimeout(() => {
+      const menuParentItem = e.target.closest(
+        '[data-drupal-selector="primary-nav-menu-item-has-children"]',
+      );
       if (!menuParentItem.contains(document.activeElement)) {
         toggleSubNav(menuParentItem, false);
       }
     }, 200);
   }
 
-  secondLevelNavMenus.forEach(el => {
-    const button = el.querySelector('[data-drupal-selector="primary-nav-submenu-toggle-button"]');
+  // Add event listeners onto each sub navigation parent and button.
+  secondLevelNavMenus.forEach((el) => {
+    const button = el.querySelector(
+      '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
+    );
+
     button.removeAttribute('aria-hidden');
     button.removeAttribute('tabindex');
-    el.addEventListener('touchstart', () => {
-      el.classList.add('is-touch-event');
-    }, {
-      passive: true
-    });
+
+    // If touch event, prevent mouseover event from triggering the submenu.
+    el.addEventListener(
+      'touchstart',
+      () => {
+        el.classList.add('is-touch-event');
+      },
+      { passive: true },
+    );
+
     el.addEventListener('mouseover', () => {
       if (isDesktopNav() && !el.classList.contains('is-touch-event')) {
         el.classList.add('is-active-mouseover-event');
         toggleSubNav(el, true);
+
+        // Timeout is added to ensure that users of assistive devices (such as
+        // mouse grid tools) do not simultaneously trigger both the mouseover
+        // and click events. When these events are triggered together, the
+        // submenu to appear to not open.
         setTimeout(() => {
           el.classList.remove('is-active-mouseover-event');
         }, 500);
       }
     });
+
     button.addEventListener('click', () => {
       if (!el.classList.contains('is-active-mouseover-event')) {
         toggleSubNav(el);
       }
     });
+
     el.addEventListener('mouseout', () => {
-      if (isDesktopNav() && !document.activeElement.matches('[aria-expanded="true"], .is-active-menu-parent *')) {
+      if (
+        isDesktopNav() &&
+        !document.activeElement.matches(
+          '[aria-expanded="true"], .is-active-menu-parent *',
+        )
+      ) {
         toggleSubNav(el, false);
       }
     });
+
     el.addEventListener('blur', handleBlur, true);
   });
 
+  /**
+   * Close all second level sub navigation menus.
+   */
   function closeAllSubNav() {
-    secondLevelNavMenus.forEach(el => {
+    secondLevelNavMenus.forEach((el) => {
+      // Return focus to the toggle button if the submenu contains focus.
       if (el.contains(document.activeElement)) {
-        el.querySelector('[data-drupal-selector="primary-nav-submenu-toggle-button"]').focus();
+        el.querySelector(
+          '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
+        ).focus();
       }
-
       toggleSubNav(el, false);
     });
   }
 
   Drupal.olivero.closeAllSubNav = closeAllSubNav;
 
+  /**
+   * Checks if any sub navigation items are currently active.
+   *
+   * @return {boolean}
+   *   If sub navigation is currently open.
+   */
   function areAnySubNavsOpen() {
     let subNavsAreOpen = false;
-    secondLevelNavMenus.forEach(el => {
-      const button = el.querySelector('[data-drupal-selector="primary-nav-submenu-toggle-button"]');
+
+    secondLevelNavMenus.forEach((el) => {
+      const button = el.querySelector(
+        '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
+      );
       const state = button.getAttribute('aria-expanded') === 'true';
 
       if (state) {
         subNavsAreOpen = true;
       }
     });
+
     return subNavsAreOpen;
   }
 
   Drupal.olivero.areAnySubNavsOpen = areAnySubNavsOpen;
-  document.addEventListener('keyup', e => {
+
+  // Ensure that desktop submenus close when escape key is pressed.
+  document.addEventListener('keyup', (e) => {
     if (e.key === 'Escape') {
       if (isDesktopNav()) closeAllSubNav();
     }
   });
-  document.addEventListener('touchstart', e => {
-    if (areAnySubNavsOpen() && !e.target.matches('[data-drupal-selector="header-nav"], [data-drupal-selector="header-nav"] *')) {
-      closeAllSubNav();
-    }
-  }, {
-    passive: true
-  });
-})(Drupal);
\ No newline at end of file
+
+  // If user taps outside of menu, close all menus.
+  document.addEventListener(
+    'touchstart',
+    (e) => {
+      if (
+        areAnySubNavsOpen() &&
+        !e.target.matches(
+          '[data-drupal-selector="header-nav"], [data-drupal-selector="header-nav"] *',
+        )
+      ) {
+        closeAllSubNav();
+      }
+    },
+    { passive: true },
+  );
+})(Drupal);
diff --git a/core/themes/olivero/js/tabs.es6.js b/core/themes/olivero/js/tabs.es6.js
deleted file mode 100644
index c5d3e0d52892..000000000000
--- a/core/themes/olivero/js/tabs.es6.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * @file
- * Provides interactivity for showing and hiding the primary tabs at mobile widths.
- */
-
-((Drupal, once) => {
-  /**
-   * Initialize the primary tabs.
-   *
-   * @param {HTMLElement} el
-   *   The DOM element containing the primary tabs.
-   */
-  function init(el) {
-    const tabs = el.querySelector('.tabs');
-    const expandedClass = 'is-expanded';
-    const activeTab = tabs.querySelector('.is-active');
-
-    /**
-     * Determines if primary tabs are expanded for mobile layouts.
-     *
-     * @return {boolean}
-     *   Whether the tabs trigger element is expanded.
-     */
-    function isTabsMobileLayout() {
-      return tabs.querySelector('.tabs__trigger').clientHeight > 0;
-    }
-
-    /**
-     * Controls primary tab visibility on click events.
-     *
-     * @param {Event} e
-     *   The event object.
-     */
-    function handleTriggerClick(e) {
-      if (!tabs.classList.contains(expandedClass)) {
-        e.currentTarget.setAttribute('aria-expanded', 'true');
-        tabs.classList.add(expandedClass);
-      } else {
-        e.currentTarget.setAttribute('aria-expanded', 'false');
-        tabs.classList.remove(expandedClass);
-      }
-    }
-
-    if (isTabsMobileLayout() && !activeTab.matches('.tabs__tab:first-child')) {
-      const newActiveTab = activeTab.cloneNode(true);
-      const firstTab = tabs.querySelector('.tabs__tab:first-child');
-      tabs.insertBefore(newActiveTab, firstTab);
-      tabs.removeChild(activeTab);
-    }
-
-    tabs
-      .querySelector('.tabs__trigger')
-      .addEventListener('click', handleTriggerClick);
-  }
-
-  /**
-   * Initialize the primary tabs.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Display primary tabs according to the screen width.
-   */
-  Drupal.behaviors.primaryTabs = {
-    attach(context) {
-      once('olivero-tabs', '[data-drupal-nav-primary-tabs]', context).forEach(
-        init,
-      );
-    },
-  };
-})(Drupal, once);
diff --git a/core/themes/olivero/js/tabs.js b/core/themes/olivero/js/tabs.js
index 418b2e45e1a9..c5d3e0d52892 100644
--- a/core/themes/olivero/js/tabs.js
+++ b/core/themes/olivero/js/tabs.js
@@ -1,20 +1,36 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Provides interactivity for showing and hiding the primary tabs at mobile widths.
+ */
 
 ((Drupal, once) => {
+  /**
+   * Initialize the primary tabs.
+   *
+   * @param {HTMLElement} el
+   *   The DOM element containing the primary tabs.
+   */
   function init(el) {
     const tabs = el.querySelector('.tabs');
     const expandedClass = 'is-expanded';
     const activeTab = tabs.querySelector('.is-active');
 
+    /**
+     * Determines if primary tabs are expanded for mobile layouts.
+     *
+     * @return {boolean}
+     *   Whether the tabs trigger element is expanded.
+     */
     function isTabsMobileLayout() {
       return tabs.querySelector('.tabs__trigger').clientHeight > 0;
     }
 
+    /**
+     * Controls primary tab visibility on click events.
+     *
+     * @param {Event} e
+     *   The event object.
+     */
     function handleTriggerClick(e) {
       if (!tabs.classList.contains(expandedClass)) {
         e.currentTarget.setAttribute('aria-expanded', 'true');
@@ -32,13 +48,24 @@
       tabs.removeChild(activeTab);
     }
 
-    tabs.querySelector('.tabs__trigger').addEventListener('click', handleTriggerClick);
+    tabs
+      .querySelector('.tabs__trigger')
+      .addEventListener('click', handleTriggerClick);
   }
 
+  /**
+   * Initialize the primary tabs.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Display primary tabs according to the screen width.
+   */
   Drupal.behaviors.primaryTabs = {
     attach(context) {
-      once('olivero-tabs', '[data-drupal-nav-primary-tabs]', context).forEach(init);
-    }
-
+      once('olivero-tabs', '[data-drupal-nav-primary-tabs]', context).forEach(
+        init,
+      );
+    },
   };
-})(Drupal, once);
\ No newline at end of file
+})(Drupal, once);
diff --git a/core/themes/stable/js/ajax.es6.js b/core/themes/stable/js/ajax.es6.js
deleted file mode 100644
index 648de6c03c7e..000000000000
--- a/core/themes/stable/js/ajax.es6.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * @file
- * Provides backwards compatibility layer for Ajax-related markup.
- */
-
-((Drupal) => {
-  /**
-   * Override the default ajaxProgressBar for backwards compatibility.
-   *
-   * @param {jQuery} $element
-   *   Progress bar element.
-   * @return {string}
-   *   The HTML markup for the progress bar.
-   */
-  Drupal.theme.ajaxProgressBar = ($element) =>
-    $element.addClass('ajax-progress ajax-progress-bar');
-})(Drupal);
diff --git a/core/themes/stable/js/ajax.js b/core/themes/stable/js/ajax.js
index 2f9546f12a7d..648de6c03c7e 100644
--- a/core/themes/stable/js/ajax.js
+++ b/core/themes/stable/js/ajax.js
@@ -1,10 +1,17 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Provides backwards compatibility layer for Ajax-related markup.
+ */
 
-(Drupal => {
-  Drupal.theme.ajaxProgressBar = $element => $element.addClass('ajax-progress ajax-progress-bar');
-})(Drupal);
\ No newline at end of file
+((Drupal) => {
+  /**
+   * Override the default ajaxProgressBar for backwards compatibility.
+   *
+   * @param {jQuery} $element
+   *   Progress bar element.
+   * @return {string}
+   *   The HTML markup for the progress bar.
+   */
+  Drupal.theme.ajaxProgressBar = ($element) =>
+    $element.addClass('ajax-progress ajax-progress-bar');
+})(Drupal);
diff --git a/core/themes/stable/js/tour.es6.js b/core/themes/stable/js/tour.es6.js
deleted file mode 100644
index 3a565ee19107..000000000000
--- a/core/themes/stable/js/tour.es6.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * @file
- * Provides backwards compatibility for Tours that no longer use Joyride.
- */
-
-((Drupal) => {
-  /**
-   * Converts the markup of a Shepherd tour tip to match Joyride.
-   *
-   * @param {Tour} shepherdTour
-   *   A ShepherdJS tour object.
-   *
-   * @internal
-   */
-  Drupal.tour.convertToJoyrideMarkup = (shepherdTour) => {
-    /**
-     * Changes the tag of an element.
-     *
-     * @param {HTMLElement} element
-     *  The element that will have its tag changed.
-     * @param {string} tag
-     *  The tag the element should be changed to.
-     */
-    const changeTag = (element, tag) => {
-      if (element) {
-        const newTagElement = document.createElement(tag);
-        [...element.attributes].forEach((attr) => {
-          newTagElement.setAttribute(attr.name, attr.value);
-        });
-        newTagElement.innerHTML = element.innerHTML;
-        element.parentNode.replaceChild(newTagElement, element);
-      }
-    };
-
-    // Create variables for the elements that will be rearranged.
-    const shepherdElement = shepherdTour.currentStep.el;
-    const shepherdContent = shepherdElement.querySelector('.shepherd-content');
-    const shepherdCancel = shepherdElement.querySelector(
-      '.shepherd-cancel-icon',
-    );
-    const shepherdTitle = shepherdElement.querySelector('.shepherd-title');
-    const shepherdText = shepherdElement.querySelector('.shepherd-text');
-    const shepherdNext = shepherdElement.querySelector('footer .button');
-    const tourProgress = shepherdElement.querySelector('.tour-progress');
-
-    // Add attributes to the elements so they match what they were when Joyride
-    // was providing Tour functionality.
-    shepherdElement.classList.add('joyride-tip-guide');
-    shepherdContent.classList.add('joyride-content-wrapper');
-    shepherdNext.classList.add('joyride-next-tip');
-    shepherdNext.setAttribute('href', '#');
-    shepherdNext.setAttribute('role', 'button');
-    shepherdNext.removeAttribute('type');
-    shepherdCancel.classList.add('joyride-close-tip');
-    shepherdCancel.removeAttribute('type');
-    shepherdCancel.setAttribute('href', '#');
-    shepherdCancel.setAttribute('role', 'button');
-    shepherdElement.setAttribute(
-      'data-index',
-      shepherdTour.currentStep.options.index,
-    );
-    shepherdElement.querySelector('footer').remove();
-
-    // Rearrange elements so their structure matches Joyride's.
-    shepherdContent.insertBefore(shepherdTitle, shepherdContent.firstChild);
-    shepherdContent.insertBefore(tourProgress, shepherdText.nextSibling);
-    shepherdContent.appendChild(shepherdCancel);
-    shepherdContent.querySelector('.shepherd-header').remove();
-    shepherdContent.insertBefore(shepherdNext, tourProgress.nextSibling);
-    shepherdCancel.innerHTML = '<span aria-hidden="true">×</span>';
-    shepherdTitle.classList.add('tour-tip-label');
-
-    // Convert elements to use the tags they used in Joyride.
-    changeTag(shepherdTitle, 'h2');
-
-    // Remove the wrapper Shepherd adds for tip content.
-    shepherdText.outerHTML = shepherdText.innerHTML;
-
-    // Convert the next and cancel buttons to links so they match Joyride's
-    // markup. They must be re-queried as they were potentially moved elsewhere
-    // in the DOM.
-    changeTag(shepherdElement.querySelector('.joyride-close-tip'), 'a');
-    changeTag(shepherdElement.querySelector('.joyride-next-tip'), 'a');
-
-    // The arrow protruding from a tip pointing to the element it references.
-    const shepherdArrow = shepherdElement.querySelector('.shepherd-arrow');
-
-    if (shepherdArrow) {
-      shepherdArrow.classList.add('joyride-nub');
-
-      if (shepherdTour.currentStep.options.attachTo.on) {
-        // Shepherd's positions are opposite of Joyride's as they specify the
-        // tip location relative to the corresponding element as opposed to
-        // their location on the tip itself.
-        const stepToTipPosition = {
-          bottom: 'top',
-          top: 'bottom',
-          left: 'right',
-          right: 'left',
-        };
-        shepherdArrow.classList.add(
-          // Split at '-' as shepherd positioning accommodates dash-delimited
-          // secondary axis positioning.
-          // shepherdTour.currentStep.options.attachTo.on.split('-')[0]
-          stepToTipPosition[
-            // Split at '-' as shepherd positioning accommodates dash-delimited
-            // secondary axis positioning.
-            shepherdTour.currentStep.options.attachTo.on.split('-')[0]
-          ],
-        );
-      }
-      changeTag(shepherdArrow, 'span');
-    } else {
-      // If there is no Shepherd arrow, there still needs to be markup for a
-      // non-displayed nub to match Joyride's markup.
-      const nub = document.createElement('span');
-      nub.classList.add('joyride-nub');
-      nub.setAttribute('style', 'display: none;');
-      shepherdElement.insertBefore(nub, shepherdElement.firstChild);
-    }
-
-    // When the next and cancel buttons were converted to links, they became
-    // new DOM elements that no longer have their associated event listeners.
-    // The events must be reintroduced here.
-    shepherdElement
-      .querySelector('.joyride-next-tip')
-      .addEventListener('click', (e) => {
-        e.preventDefault();
-        shepherdTour.next();
-      });
-    shepherdElement
-      .querySelector('.joyride-close-tip')
-      .addEventListener('click', (e) => {
-        e.preventDefault();
-        shepherdTour.cancel();
-      });
-    shepherdElement.querySelector('.joyride-next-tip').focus();
-  };
-})(Drupal);
diff --git a/core/themes/stable/js/tour.js b/core/themes/stable/js/tour.js
index 7962bdfdf293..3a565ee19107 100644
--- a/core/themes/stable/js/tour.js
+++ b/core/themes/stable/js/tour.js
@@ -1,16 +1,30 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Provides backwards compatibility for Tours that no longer use Joyride.
+ */
 
-(Drupal => {
-  Drupal.tour.convertToJoyrideMarkup = shepherdTour => {
+((Drupal) => {
+  /**
+   * Converts the markup of a Shepherd tour tip to match Joyride.
+   *
+   * @param {Tour} shepherdTour
+   *   A ShepherdJS tour object.
+   *
+   * @internal
+   */
+  Drupal.tour.convertToJoyrideMarkup = (shepherdTour) => {
+    /**
+     * Changes the tag of an element.
+     *
+     * @param {HTMLElement} element
+     *  The element that will have its tag changed.
+     * @param {string} tag
+     *  The tag the element should be changed to.
+     */
     const changeTag = (element, tag) => {
       if (element) {
         const newTagElement = document.createElement(tag);
-        [...element.attributes].forEach(attr => {
+        [...element.attributes].forEach((attr) => {
           newTagElement.setAttribute(attr.name, attr.value);
         });
         newTagElement.innerHTML = element.innerHTML;
@@ -18,13 +32,19 @@
       }
     };
 
+    // Create variables for the elements that will be rearranged.
     const shepherdElement = shepherdTour.currentStep.el;
     const shepherdContent = shepherdElement.querySelector('.shepherd-content');
-    const shepherdCancel = shepherdElement.querySelector('.shepherd-cancel-icon');
+    const shepherdCancel = shepherdElement.querySelector(
+      '.shepherd-cancel-icon',
+    );
     const shepherdTitle = shepherdElement.querySelector('.shepherd-title');
     const shepherdText = shepherdElement.querySelector('.shepherd-text');
     const shepherdNext = shepherdElement.querySelector('footer .button');
     const tourProgress = shepherdElement.querySelector('.tour-progress');
+
+    // Add attributes to the elements so they match what they were when Joyride
+    // was providing Tour functionality.
     shepherdElement.classList.add('joyride-tip-guide');
     shepherdContent.classList.add('joyride-content-wrapper');
     shepherdNext.classList.add('joyride-next-tip');
@@ -35,8 +55,13 @@
     shepherdCancel.removeAttribute('type');
     shepherdCancel.setAttribute('href', '#');
     shepherdCancel.setAttribute('role', 'button');
-    shepherdElement.setAttribute('data-index', shepherdTour.currentStep.options.index);
+    shepherdElement.setAttribute(
+      'data-index',
+      shepherdTour.currentStep.options.index,
+    );
     shepherdElement.querySelector('footer').remove();
+
+    // Rearrange elements so their structure matches Joyride's.
     shepherdContent.insertBefore(shepherdTitle, shepherdContent.firstChild);
     shepherdContent.insertBefore(tourProgress, shepherdText.nextSibling);
     shepherdContent.appendChild(shepherdCancel);
@@ -44,41 +69,71 @@
     shepherdContent.insertBefore(shepherdNext, tourProgress.nextSibling);
     shepherdCancel.innerHTML = '<span aria-hidden="true">×</span>';
     shepherdTitle.classList.add('tour-tip-label');
+
+    // Convert elements to use the tags they used in Joyride.
     changeTag(shepherdTitle, 'h2');
+
+    // Remove the wrapper Shepherd adds for tip content.
     shepherdText.outerHTML = shepherdText.innerHTML;
+
+    // Convert the next and cancel buttons to links so they match Joyride's
+    // markup. They must be re-queried as they were potentially moved elsewhere
+    // in the DOM.
     changeTag(shepherdElement.querySelector('.joyride-close-tip'), 'a');
     changeTag(shepherdElement.querySelector('.joyride-next-tip'), 'a');
+
+    // The arrow protruding from a tip pointing to the element it references.
     const shepherdArrow = shepherdElement.querySelector('.shepherd-arrow');
 
     if (shepherdArrow) {
       shepherdArrow.classList.add('joyride-nub');
 
       if (shepherdTour.currentStep.options.attachTo.on) {
+        // Shepherd's positions are opposite of Joyride's as they specify the
+        // tip location relative to the corresponding element as opposed to
+        // their location on the tip itself.
         const stepToTipPosition = {
           bottom: 'top',
           top: 'bottom',
           left: 'right',
-          right: 'left'
+          right: 'left',
         };
-        shepherdArrow.classList.add(stepToTipPosition[shepherdTour.currentStep.options.attachTo.on.split('-')[0]]);
+        shepherdArrow.classList.add(
+          // Split at '-' as shepherd positioning accommodates dash-delimited
+          // secondary axis positioning.
+          // shepherdTour.currentStep.options.attachTo.on.split('-')[0]
+          stepToTipPosition[
+            // Split at '-' as shepherd positioning accommodates dash-delimited
+            // secondary axis positioning.
+            shepherdTour.currentStep.options.attachTo.on.split('-')[0]
+          ],
+        );
       }
-
       changeTag(shepherdArrow, 'span');
     } else {
+      // If there is no Shepherd arrow, there still needs to be markup for a
+      // non-displayed nub to match Joyride's markup.
       const nub = document.createElement('span');
       nub.classList.add('joyride-nub');
       nub.setAttribute('style', 'display: none;');
       shepherdElement.insertBefore(nub, shepherdElement.firstChild);
     }
 
-    shepherdElement.querySelector('.joyride-next-tip').addEventListener('click', e => {
-      e.preventDefault();
-      shepherdTour.next();
-    });
-    shepherdElement.querySelector('.joyride-close-tip').addEventListener('click', e => {
-      e.preventDefault();
-      shepherdTour.cancel();
-    });
+    // When the next and cancel buttons were converted to links, they became
+    // new DOM elements that no longer have their associated event listeners.
+    // The events must be reintroduced here.
+    shepherdElement
+      .querySelector('.joyride-next-tip')
+      .addEventListener('click', (e) => {
+        e.preventDefault();
+        shepherdTour.next();
+      });
+    shepherdElement
+      .querySelector('.joyride-close-tip')
+      .addEventListener('click', (e) => {
+        e.preventDefault();
+        shepherdTour.cancel();
+      });
     shepherdElement.querySelector('.joyride-next-tip').focus();
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/themes/stable/js/user.theme.es6.js b/core/themes/stable/js/user.theme.es6.js
deleted file mode 100644
index beeae102ac74..000000000000
--- a/core/themes/stable/js/user.theme.es6.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * @file
- * Stable theme overrides for user password forms.
- */
-
-((Drupal) => {
-  /**
-   * Constructs a password confirm message element
-   *
-   * @return {string}
-   *   A string representing a DOM fragment.
-   */
-  Drupal.theme.passwordConfirmMessage = (translate) =>
-    `<div aria-live="polite" aria-atomic="true" class="password-confirm js-password-confirm js-password-confirm-message" data-drupal-selector="password-confirm-message">${translate.confirmTitle} <span data-drupal-selector="password-match-status-text"></span></div>`;
-
-  /**
-   * Constructs a password strength message.
-   *
-   * @param {object} passwordSettings
-   *   An object containing password related settings and translated text to
-   *   display.
-   * @param {string} passwordSettings.strengthTitle
-   *   The title that precedes the strength text.
-   *
-   * @return {string}
-   *   Markup for password strength message.
-   */
-  Drupal.theme.passwordStrength = ({ strengthTitle }) => {
-    const strengthIndicator =
-      '<div class="password-strength__indicator js-password-strength__indicator" data-drupal-selector="password-strength-indicator"></div>';
-    const strengthText =
-      '<span class="password-strength__text js-password-strength__text" data-drupal-selector="password-strength-text"></span>';
-    return `
-      <div class="password-strength">
-        <div class="password-strength__meter" data-drupal-selector="password-strength-meter">${strengthIndicator}</div>
-        <div aria-live="polite" aria-atomic="true" class="password-strength__title">${strengthTitle} ${strengthText}</div>
-      </div>
-    `;
-  };
-})(Drupal);
diff --git a/core/themes/stable/js/user.theme.js b/core/themes/stable/js/user.theme.js
index 46614f11ba1f..beeae102ac74 100644
--- a/core/themes/stable/js/user.theme.js
+++ b/core/themes/stable/js/user.theme.js
@@ -1,19 +1,35 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Stable theme overrides for user password forms.
+ */
 
-(Drupal => {
-  Drupal.theme.passwordConfirmMessage = translate => `<div aria-live="polite" aria-atomic="true" class="password-confirm js-password-confirm js-password-confirm-message" data-drupal-selector="password-confirm-message">${translate.confirmTitle} <span data-drupal-selector="password-match-status-text"></span></div>`;
+((Drupal) => {
+  /**
+   * Constructs a password confirm message element
+   *
+   * @return {string}
+   *   A string representing a DOM fragment.
+   */
+  Drupal.theme.passwordConfirmMessage = (translate) =>
+    `<div aria-live="polite" aria-atomic="true" class="password-confirm js-password-confirm js-password-confirm-message" data-drupal-selector="password-confirm-message">${translate.confirmTitle} <span data-drupal-selector="password-match-status-text"></span></div>`;
 
-  Drupal.theme.passwordStrength = _ref => {
-    let {
-      strengthTitle
-    } = _ref;
-    const strengthIndicator = '<div class="password-strength__indicator js-password-strength__indicator" data-drupal-selector="password-strength-indicator"></div>';
-    const strengthText = '<span class="password-strength__text js-password-strength__text" data-drupal-selector="password-strength-text"></span>';
+  /**
+   * Constructs a password strength message.
+   *
+   * @param {object} passwordSettings
+   *   An object containing password related settings and translated text to
+   *   display.
+   * @param {string} passwordSettings.strengthTitle
+   *   The title that precedes the strength text.
+   *
+   * @return {string}
+   *   Markup for password strength message.
+   */
+  Drupal.theme.passwordStrength = ({ strengthTitle }) => {
+    const strengthIndicator =
+      '<div class="password-strength__indicator js-password-strength__indicator" data-drupal-selector="password-strength-indicator"></div>';
+    const strengthText =
+      '<span class="password-strength__text js-password-strength__text" data-drupal-selector="password-strength-text"></span>';
     return `
       <div class="password-strength">
         <div class="password-strength__meter" data-drupal-selector="password-strength-meter">${strengthIndicator}</div>
@@ -21,4 +37,4 @@
       </div>
     `;
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/themes/stable9/js/tour.es6.js b/core/themes/stable9/js/tour.es6.js
deleted file mode 100644
index 3a565ee19107..000000000000
--- a/core/themes/stable9/js/tour.es6.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * @file
- * Provides backwards compatibility for Tours that no longer use Joyride.
- */
-
-((Drupal) => {
-  /**
-   * Converts the markup of a Shepherd tour tip to match Joyride.
-   *
-   * @param {Tour} shepherdTour
-   *   A ShepherdJS tour object.
-   *
-   * @internal
-   */
-  Drupal.tour.convertToJoyrideMarkup = (shepherdTour) => {
-    /**
-     * Changes the tag of an element.
-     *
-     * @param {HTMLElement} element
-     *  The element that will have its tag changed.
-     * @param {string} tag
-     *  The tag the element should be changed to.
-     */
-    const changeTag = (element, tag) => {
-      if (element) {
-        const newTagElement = document.createElement(tag);
-        [...element.attributes].forEach((attr) => {
-          newTagElement.setAttribute(attr.name, attr.value);
-        });
-        newTagElement.innerHTML = element.innerHTML;
-        element.parentNode.replaceChild(newTagElement, element);
-      }
-    };
-
-    // Create variables for the elements that will be rearranged.
-    const shepherdElement = shepherdTour.currentStep.el;
-    const shepherdContent = shepherdElement.querySelector('.shepherd-content');
-    const shepherdCancel = shepherdElement.querySelector(
-      '.shepherd-cancel-icon',
-    );
-    const shepherdTitle = shepherdElement.querySelector('.shepherd-title');
-    const shepherdText = shepherdElement.querySelector('.shepherd-text');
-    const shepherdNext = shepherdElement.querySelector('footer .button');
-    const tourProgress = shepherdElement.querySelector('.tour-progress');
-
-    // Add attributes to the elements so they match what they were when Joyride
-    // was providing Tour functionality.
-    shepherdElement.classList.add('joyride-tip-guide');
-    shepherdContent.classList.add('joyride-content-wrapper');
-    shepherdNext.classList.add('joyride-next-tip');
-    shepherdNext.setAttribute('href', '#');
-    shepherdNext.setAttribute('role', 'button');
-    shepherdNext.removeAttribute('type');
-    shepherdCancel.classList.add('joyride-close-tip');
-    shepherdCancel.removeAttribute('type');
-    shepherdCancel.setAttribute('href', '#');
-    shepherdCancel.setAttribute('role', 'button');
-    shepherdElement.setAttribute(
-      'data-index',
-      shepherdTour.currentStep.options.index,
-    );
-    shepherdElement.querySelector('footer').remove();
-
-    // Rearrange elements so their structure matches Joyride's.
-    shepherdContent.insertBefore(shepherdTitle, shepherdContent.firstChild);
-    shepherdContent.insertBefore(tourProgress, shepherdText.nextSibling);
-    shepherdContent.appendChild(shepherdCancel);
-    shepherdContent.querySelector('.shepherd-header').remove();
-    shepherdContent.insertBefore(shepherdNext, tourProgress.nextSibling);
-    shepherdCancel.innerHTML = '<span aria-hidden="true">×</span>';
-    shepherdTitle.classList.add('tour-tip-label');
-
-    // Convert elements to use the tags they used in Joyride.
-    changeTag(shepherdTitle, 'h2');
-
-    // Remove the wrapper Shepherd adds for tip content.
-    shepherdText.outerHTML = shepherdText.innerHTML;
-
-    // Convert the next and cancel buttons to links so they match Joyride's
-    // markup. They must be re-queried as they were potentially moved elsewhere
-    // in the DOM.
-    changeTag(shepherdElement.querySelector('.joyride-close-tip'), 'a');
-    changeTag(shepherdElement.querySelector('.joyride-next-tip'), 'a');
-
-    // The arrow protruding from a tip pointing to the element it references.
-    const shepherdArrow = shepherdElement.querySelector('.shepherd-arrow');
-
-    if (shepherdArrow) {
-      shepherdArrow.classList.add('joyride-nub');
-
-      if (shepherdTour.currentStep.options.attachTo.on) {
-        // Shepherd's positions are opposite of Joyride's as they specify the
-        // tip location relative to the corresponding element as opposed to
-        // their location on the tip itself.
-        const stepToTipPosition = {
-          bottom: 'top',
-          top: 'bottom',
-          left: 'right',
-          right: 'left',
-        };
-        shepherdArrow.classList.add(
-          // Split at '-' as shepherd positioning accommodates dash-delimited
-          // secondary axis positioning.
-          // shepherdTour.currentStep.options.attachTo.on.split('-')[0]
-          stepToTipPosition[
-            // Split at '-' as shepherd positioning accommodates dash-delimited
-            // secondary axis positioning.
-            shepherdTour.currentStep.options.attachTo.on.split('-')[0]
-          ],
-        );
-      }
-      changeTag(shepherdArrow, 'span');
-    } else {
-      // If there is no Shepherd arrow, there still needs to be markup for a
-      // non-displayed nub to match Joyride's markup.
-      const nub = document.createElement('span');
-      nub.classList.add('joyride-nub');
-      nub.setAttribute('style', 'display: none;');
-      shepherdElement.insertBefore(nub, shepherdElement.firstChild);
-    }
-
-    // When the next and cancel buttons were converted to links, they became
-    // new DOM elements that no longer have their associated event listeners.
-    // The events must be reintroduced here.
-    shepherdElement
-      .querySelector('.joyride-next-tip')
-      .addEventListener('click', (e) => {
-        e.preventDefault();
-        shepherdTour.next();
-      });
-    shepherdElement
-      .querySelector('.joyride-close-tip')
-      .addEventListener('click', (e) => {
-        e.preventDefault();
-        shepherdTour.cancel();
-      });
-    shepherdElement.querySelector('.joyride-next-tip').focus();
-  };
-})(Drupal);
diff --git a/core/themes/stable9/js/tour.js b/core/themes/stable9/js/tour.js
index 7962bdfdf293..3a565ee19107 100644
--- a/core/themes/stable9/js/tour.js
+++ b/core/themes/stable9/js/tour.js
@@ -1,16 +1,30 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Provides backwards compatibility for Tours that no longer use Joyride.
+ */
 
-(Drupal => {
-  Drupal.tour.convertToJoyrideMarkup = shepherdTour => {
+((Drupal) => {
+  /**
+   * Converts the markup of a Shepherd tour tip to match Joyride.
+   *
+   * @param {Tour} shepherdTour
+   *   A ShepherdJS tour object.
+   *
+   * @internal
+   */
+  Drupal.tour.convertToJoyrideMarkup = (shepherdTour) => {
+    /**
+     * Changes the tag of an element.
+     *
+     * @param {HTMLElement} element
+     *  The element that will have its tag changed.
+     * @param {string} tag
+     *  The tag the element should be changed to.
+     */
     const changeTag = (element, tag) => {
       if (element) {
         const newTagElement = document.createElement(tag);
-        [...element.attributes].forEach(attr => {
+        [...element.attributes].forEach((attr) => {
           newTagElement.setAttribute(attr.name, attr.value);
         });
         newTagElement.innerHTML = element.innerHTML;
@@ -18,13 +32,19 @@
       }
     };
 
+    // Create variables for the elements that will be rearranged.
     const shepherdElement = shepherdTour.currentStep.el;
     const shepherdContent = shepherdElement.querySelector('.shepherd-content');
-    const shepherdCancel = shepherdElement.querySelector('.shepherd-cancel-icon');
+    const shepherdCancel = shepherdElement.querySelector(
+      '.shepherd-cancel-icon',
+    );
     const shepherdTitle = shepherdElement.querySelector('.shepherd-title');
     const shepherdText = shepherdElement.querySelector('.shepherd-text');
     const shepherdNext = shepherdElement.querySelector('footer .button');
     const tourProgress = shepherdElement.querySelector('.tour-progress');
+
+    // Add attributes to the elements so they match what they were when Joyride
+    // was providing Tour functionality.
     shepherdElement.classList.add('joyride-tip-guide');
     shepherdContent.classList.add('joyride-content-wrapper');
     shepherdNext.classList.add('joyride-next-tip');
@@ -35,8 +55,13 @@
     shepherdCancel.removeAttribute('type');
     shepherdCancel.setAttribute('href', '#');
     shepherdCancel.setAttribute('role', 'button');
-    shepherdElement.setAttribute('data-index', shepherdTour.currentStep.options.index);
+    shepherdElement.setAttribute(
+      'data-index',
+      shepherdTour.currentStep.options.index,
+    );
     shepherdElement.querySelector('footer').remove();
+
+    // Rearrange elements so their structure matches Joyride's.
     shepherdContent.insertBefore(shepherdTitle, shepherdContent.firstChild);
     shepherdContent.insertBefore(tourProgress, shepherdText.nextSibling);
     shepherdContent.appendChild(shepherdCancel);
@@ -44,41 +69,71 @@
     shepherdContent.insertBefore(shepherdNext, tourProgress.nextSibling);
     shepherdCancel.innerHTML = '<span aria-hidden="true">×</span>';
     shepherdTitle.classList.add('tour-tip-label');
+
+    // Convert elements to use the tags they used in Joyride.
     changeTag(shepherdTitle, 'h2');
+
+    // Remove the wrapper Shepherd adds for tip content.
     shepherdText.outerHTML = shepherdText.innerHTML;
+
+    // Convert the next and cancel buttons to links so they match Joyride's
+    // markup. They must be re-queried as they were potentially moved elsewhere
+    // in the DOM.
     changeTag(shepherdElement.querySelector('.joyride-close-tip'), 'a');
     changeTag(shepherdElement.querySelector('.joyride-next-tip'), 'a');
+
+    // The arrow protruding from a tip pointing to the element it references.
     const shepherdArrow = shepherdElement.querySelector('.shepherd-arrow');
 
     if (shepherdArrow) {
       shepherdArrow.classList.add('joyride-nub');
 
       if (shepherdTour.currentStep.options.attachTo.on) {
+        // Shepherd's positions are opposite of Joyride's as they specify the
+        // tip location relative to the corresponding element as opposed to
+        // their location on the tip itself.
         const stepToTipPosition = {
           bottom: 'top',
           top: 'bottom',
           left: 'right',
-          right: 'left'
+          right: 'left',
         };
-        shepherdArrow.classList.add(stepToTipPosition[shepherdTour.currentStep.options.attachTo.on.split('-')[0]]);
+        shepherdArrow.classList.add(
+          // Split at '-' as shepherd positioning accommodates dash-delimited
+          // secondary axis positioning.
+          // shepherdTour.currentStep.options.attachTo.on.split('-')[0]
+          stepToTipPosition[
+            // Split at '-' as shepherd positioning accommodates dash-delimited
+            // secondary axis positioning.
+            shepherdTour.currentStep.options.attachTo.on.split('-')[0]
+          ],
+        );
       }
-
       changeTag(shepherdArrow, 'span');
     } else {
+      // If there is no Shepherd arrow, there still needs to be markup for a
+      // non-displayed nub to match Joyride's markup.
       const nub = document.createElement('span');
       nub.classList.add('joyride-nub');
       nub.setAttribute('style', 'display: none;');
       shepherdElement.insertBefore(nub, shepherdElement.firstChild);
     }
 
-    shepherdElement.querySelector('.joyride-next-tip').addEventListener('click', e => {
-      e.preventDefault();
-      shepherdTour.next();
-    });
-    shepherdElement.querySelector('.joyride-close-tip').addEventListener('click', e => {
-      e.preventDefault();
-      shepherdTour.cancel();
-    });
+    // When the next and cancel buttons were converted to links, they became
+    // new DOM elements that no longer have their associated event listeners.
+    // The events must be reintroduced here.
+    shepherdElement
+      .querySelector('.joyride-next-tip')
+      .addEventListener('click', (e) => {
+        e.preventDefault();
+        shepherdTour.next();
+      });
+    shepherdElement
+      .querySelector('.joyride-close-tip')
+      .addEventListener('click', (e) => {
+        e.preventDefault();
+        shepherdTour.cancel();
+      });
     shepherdElement.querySelector('.joyride-next-tip').focus();
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/themes/stable9/js/user.theme.es6.js b/core/themes/stable9/js/user.theme.es6.js
deleted file mode 100644
index 972121d1527d..000000000000
--- a/core/themes/stable9/js/user.theme.es6.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @file
- * Stable theme overrides for user password forms.
- */
-
-((Drupal) => {
-  /**
-   * Constructs a password confirm message element.
-   *
-   * @param {object} passwordSettings
-   *   An object containing password related settings and translated text to
-   *   display.
-   * @param {string} passwordSettings.confirmTitle
-   *   The translated confirm description that labels the actual confirm text.
-   *
-   * @return {string}
-   *   Markup for the password confirm message.
-   */
-  Drupal.theme.passwordConfirmMessage = ({ confirmTitle }) => {
-    const confirmTextWrapper =
-      '<span data-drupal-selector="password-match-status-text"></span>';
-    return `<div aria-live="polite" aria-atomic="true" class="password-confirm-message js-password-confirm-message" data-drupal-selector="password-confirm-message">${confirmTitle} ${confirmTextWrapper}</div>`;
-  };
-
-  /**
-   * Constructs a password strength message.
-   *
-   * @param {object} passwordSettings
-   *   An object containing password related settings and translated text to
-   *   display.
-   * @param {string} passwordSettings.strengthTitle
-   *   The title that precedes the strength text.
-   *
-   * @return {string}
-   *   Markup for password strength message.
-   */
-  Drupal.theme.passwordStrength = ({ strengthTitle }) => {
-    const strengthIndicator =
-      '<div class="password-strength__indicator js-password-strength__indicator" data-drupal-selector="password-strength-indicator"></div>';
-    const strengthText =
-      '<span class="password-strength__text js-password-strength__text" data-drupal-selector="password-strength-text"></span>';
-    return `
-      <div class="password-strength">
-        <div class="password-strength__meter" data-drupal-selector="password-strength-meter">${strengthIndicator}</div>
-        <div aria-live="polite" aria-atomic="true" class="password-strength__title">${strengthTitle} ${strengthText}</div>
-      </div>
-    `;
-  };
-})(Drupal);
diff --git a/core/themes/stable9/js/user.theme.js b/core/themes/stable9/js/user.theme.js
index 177fd7ac8b7a..972121d1527d 100644
--- a/core/themes/stable9/js/user.theme.js
+++ b/core/themes/stable9/js/user.theme.js
@@ -1,25 +1,44 @@
 /**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Stable theme overrides for user password forms.
+ */
 
-(Drupal => {
-  Drupal.theme.passwordConfirmMessage = _ref => {
-    let {
-      confirmTitle
-    } = _ref;
-    const confirmTextWrapper = '<span data-drupal-selector="password-match-status-text"></span>';
+((Drupal) => {
+  /**
+   * Constructs a password confirm message element.
+   *
+   * @param {object} passwordSettings
+   *   An object containing password related settings and translated text to
+   *   display.
+   * @param {string} passwordSettings.confirmTitle
+   *   The translated confirm description that labels the actual confirm text.
+   *
+   * @return {string}
+   *   Markup for the password confirm message.
+   */
+  Drupal.theme.passwordConfirmMessage = ({ confirmTitle }) => {
+    const confirmTextWrapper =
+      '<span data-drupal-selector="password-match-status-text"></span>';
     return `<div aria-live="polite" aria-atomic="true" class="password-confirm-message js-password-confirm-message" data-drupal-selector="password-confirm-message">${confirmTitle} ${confirmTextWrapper}</div>`;
   };
 
-  Drupal.theme.passwordStrength = _ref2 => {
-    let {
-      strengthTitle
-    } = _ref2;
-    const strengthIndicator = '<div class="password-strength__indicator js-password-strength__indicator" data-drupal-selector="password-strength-indicator"></div>';
-    const strengthText = '<span class="password-strength__text js-password-strength__text" data-drupal-selector="password-strength-text"></span>';
+  /**
+   * Constructs a password strength message.
+   *
+   * @param {object} passwordSettings
+   *   An object containing password related settings and translated text to
+   *   display.
+   * @param {string} passwordSettings.strengthTitle
+   *   The title that precedes the strength text.
+   *
+   * @return {string}
+   *   Markup for password strength message.
+   */
+  Drupal.theme.passwordStrength = ({ strengthTitle }) => {
+    const strengthIndicator =
+      '<div class="password-strength__indicator js-password-strength__indicator" data-drupal-selector="password-strength-indicator"></div>';
+    const strengthText =
+      '<span class="password-strength__text js-password-strength__text" data-drupal-selector="password-strength-text"></span>';
     return `
       <div class="password-strength">
         <div class="password-strength__meter" data-drupal-selector="password-strength-meter">${strengthIndicator}</div>
@@ -27,4 +46,4 @@
       </div>
     `;
   };
-})(Drupal);
\ No newline at end of file
+})(Drupal);
diff --git a/core/yarn.lock b/core/yarn.lock
index 889270da2de6..f4e23def8161 100644
--- a/core/yarn.lock
+++ b/core/yarn.lock
@@ -17,32 +17,11 @@
   dependencies:
     "@babel/highlight" "^7.18.6"
 
-"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8", "@babel/compat-data@^7.19.0":
+"@babel/compat-data@^7.19.0":
   version "7.19.0"
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.0.tgz#2a592fd89bacb1fcde68de31bee4f2f2dacb0e86"
   integrity sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==
 
-"@babel/core@^7.0.0":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.0.tgz#d2f5f4f2033c00de8096be3c9f45772563e150c3"
-  integrity sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==
-  dependencies:
-    "@ampproject/remapping" "^2.1.0"
-    "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.19.0"
-    "@babel/helper-compilation-targets" "^7.19.0"
-    "@babel/helper-module-transforms" "^7.19.0"
-    "@babel/helpers" "^7.19.0"
-    "@babel/parser" "^7.19.0"
-    "@babel/template" "^7.18.10"
-    "@babel/traverse" "^7.19.0"
-    "@babel/types" "^7.19.0"
-    convert-source-map "^1.7.0"
-    debug "^4.1.0"
-    gensync "^1.0.0-beta.2"
-    json5 "^2.2.1"
-    semver "^6.3.0"
-
 "@babel/core@^7.8.4":
   version "7.17.10"
   resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.10.tgz#74ef0fbf56b7dfc3f198fc2d927f4f03e12f4b05"
@@ -73,22 +52,7 @@
     "@jridgewell/gen-mapping" "^0.3.2"
     jsesc "^2.5.1"
 
-"@babel/helper-annotate-as-pure@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
-  integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb"
-  integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==
-  dependencies:
-    "@babel/helper-explode-assignable-expression" "^7.18.6"
-    "@babel/types" "^7.18.9"
-
-"@babel/helper-compilation-targets@^7.17.10", "@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.19.0":
+"@babel/helper-compilation-targets@^7.17.10":
   version "7.19.0"
   resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz#537ec8339d53e806ed422f1e06c8f17d55b96bb0"
   integrity sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==
@@ -98,52 +62,12 @@
     browserslist "^4.20.2"
     semver "^6.3.0"
 
-"@babel/helper-create-class-features-plugin@^7.18.6":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz#bfd6904620df4e46470bae4850d66be1054c404b"
-  integrity sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==
-  dependencies:
-    "@babel/helper-annotate-as-pure" "^7.18.6"
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-function-name" "^7.19.0"
-    "@babel/helper-member-expression-to-functions" "^7.18.9"
-    "@babel/helper-optimise-call-expression" "^7.18.6"
-    "@babel/helper-replace-supers" "^7.18.9"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-
-"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz#7976aca61c0984202baca73d84e2337a5424a41b"
-  integrity sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==
-  dependencies:
-    "@babel/helper-annotate-as-pure" "^7.18.6"
-    regexpu-core "^5.1.0"
-
-"@babel/helper-define-polyfill-provider@^0.3.2":
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz#bd10d0aca18e8ce012755395b05a79f45eca5073"
-  integrity sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==
-  dependencies:
-    "@babel/helper-compilation-targets" "^7.17.7"
-    "@babel/helper-plugin-utils" "^7.16.7"
-    debug "^4.1.1"
-    lodash.debounce "^4.0.8"
-    resolve "^1.14.2"
-    semver "^6.1.2"
-
 "@babel/helper-environment-visitor@^7.18.9":
   version "7.18.9"
   resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
   integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
 
-"@babel/helper-explode-assignable-expression@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096"
-  integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0":
+"@babel/helper-function-name@^7.19.0":
   version "7.19.0"
   resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c"
   integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==
@@ -158,13 +82,6 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
-"@babel/helper-member-expression-to-functions@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815"
-  integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==
-  dependencies:
-    "@babel/types" "^7.18.9"
-
 "@babel/helper-module-imports@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
@@ -172,7 +89,7 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
-"@babel/helper-module-transforms@^7.17.7", "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.19.0":
+"@babel/helper-module-transforms@^7.17.7":
   version "7.19.0"
   resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz#309b230f04e22c58c6a2c0c0c7e50b216d350c30"
   integrity sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==
@@ -186,39 +103,6 @@
     "@babel/traverse" "^7.19.0"
     "@babel/types" "^7.19.0"
 
-"@babel/helper-optimise-call-expression@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe"
-  integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz#4796bb14961521f0f8715990bee2fb6e51ce21bf"
-  integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==
-
-"@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519"
-  integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==
-  dependencies:
-    "@babel/helper-annotate-as-pure" "^7.18.6"
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-wrap-function" "^7.18.9"
-    "@babel/types" "^7.18.9"
-
-"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz#1092e002feca980fbbb0bd4d51b74a65c6a500e6"
-  integrity sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==
-  dependencies:
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-member-expression-to-functions" "^7.18.9"
-    "@babel/helper-optimise-call-expression" "^7.18.6"
-    "@babel/traverse" "^7.18.9"
-    "@babel/types" "^7.18.9"
-
 "@babel/helper-simple-access@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea"
@@ -226,13 +110,6 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
-"@babel/helper-skip-transparent-expression-wrappers@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz#778d87b3a758d90b471e7b9918f34a9a02eb5818"
-  integrity sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==
-  dependencies:
-    "@babel/types" "^7.18.9"
-
 "@babel/helper-split-export-declaration@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
@@ -255,17 +132,7 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
   integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
 
-"@babel/helper-wrap-function@^7.18.9":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz#89f18335cff1152373222f76a4b37799636ae8b1"
-  integrity sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==
-  dependencies:
-    "@babel/helper-function-name" "^7.19.0"
-    "@babel/template" "^7.18.10"
-    "@babel/traverse" "^7.19.0"
-    "@babel/types" "^7.19.0"
-
-"@babel/helpers@^7.17.9", "@babel/helpers@^7.19.0":
+"@babel/helpers@^7.17.9":
   version "7.19.0"
   resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.19.0.tgz#f30534657faf246ae96551d88dd31e9d1fa1fc18"
   integrity sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==
@@ -288,612 +155,6 @@
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.0.tgz#497fcafb1d5b61376959c1c338745ef0577aa02c"
   integrity sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==
 
-"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
-  integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz#a11af19aa373d68d561f08e0a57242350ed0ec50"
-  integrity sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-    "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
-    "@babel/plugin-proposal-optional-chaining" "^7.18.9"
-
-"@babel/plugin-proposal-async-generator-functions@^7.19.0":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.0.tgz#cf5740194f170467df20581712400487efc79ff1"
-  integrity sha512-nhEByMUTx3uZueJ/QkJuSlCfN4FGg+xy+vRsfGQGzSauq5ks2Deid2+05Q3KhfaUjvec1IGhw/Zm3cFm8JigTQ==
-  dependencies:
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-plugin-utils" "^7.19.0"
-    "@babel/helper-remap-async-to-generator" "^7.18.9"
-    "@babel/plugin-syntax-async-generators" "^7.8.4"
-
-"@babel/plugin-proposal-class-properties@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3"
-  integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==
-  dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-proposal-class-static-block@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz#8aa81d403ab72d3962fc06c26e222dacfc9b9020"
-  integrity sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==
-  dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/plugin-syntax-class-static-block" "^7.14.5"
-
-"@babel/plugin-proposal-dynamic-import@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94"
-  integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/plugin-syntax-dynamic-import" "^7.8.3"
-
-"@babel/plugin-proposal-export-namespace-from@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203"
-  integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-    "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
-
-"@babel/plugin-proposal-json-strings@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b"
-  integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/plugin-syntax-json-strings" "^7.8.3"
-
-"@babel/plugin-proposal-logical-assignment-operators@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz#8148cbb350483bf6220af06fa6db3690e14b2e23"
-  integrity sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-    "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
-
-"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1"
-  integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
-
-"@babel/plugin-proposal-numeric-separator@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75"
-  integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/plugin-syntax-numeric-separator" "^7.10.4"
-
-"@babel/plugin-proposal-object-rest-spread@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz#f9434f6beb2c8cae9dfcf97d2a5941bbbf9ad4e7"
-  integrity sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==
-  dependencies:
-    "@babel/compat-data" "^7.18.8"
-    "@babel/helper-compilation-targets" "^7.18.9"
-    "@babel/helper-plugin-utils" "^7.18.9"
-    "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
-    "@babel/plugin-transform-parameters" "^7.18.8"
-
-"@babel/plugin-proposal-optional-catch-binding@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb"
-  integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
-
-"@babel/plugin-proposal-optional-chaining@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz#e8e8fe0723f2563960e4bf5e9690933691915993"
-  integrity sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-    "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
-    "@babel/plugin-syntax-optional-chaining" "^7.8.3"
-
-"@babel/plugin-proposal-private-methods@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea"
-  integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==
-  dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-proposal-private-property-in-object@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz#a64137b232f0aca3733a67eb1a144c192389c503"
-  integrity sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==
-  dependencies:
-    "@babel/helper-annotate-as-pure" "^7.18.6"
-    "@babel/helper-create-class-features-plugin" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
-
-"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e"
-  integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==
-  dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-syntax-async-generators@^7.8.4":
-  version "7.8.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
-  integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-class-properties@^7.12.13":
-  version "7.12.13"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10"
-  integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-syntax-class-static-block@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406"
-  integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-syntax-dynamic-import@^7.8.3":
-  version "7.8.3"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
-  integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-export-namespace-from@^7.8.3":
-  version "7.8.3"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a"
-  integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.8.3"
-
-"@babel/plugin-syntax-import-assertions@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz#cd6190500a4fa2fe31990a963ffab4b63e4505e4"
-  integrity sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-syntax-json-strings@^7.8.3":
-  version "7.8.3"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
-  integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-logical-assignment-operators@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
-  integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-
-"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
-  version "7.8.3"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
-  integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-numeric-separator@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97"
-  integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-
-"@babel/plugin-syntax-object-rest-spread@^7.8.3":
-  version "7.8.3"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
-  integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-optional-catch-binding@^7.8.3":
-  version "7.8.3"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
-  integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-optional-chaining@^7.8.3":
-  version "7.8.3"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
-  integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-private-property-in-object@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad"
-  integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-syntax-top-level-await@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c"
-  integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-arrow-functions@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz#19063fcf8771ec7b31d742339dac62433d0611fe"
-  integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-async-to-generator@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz#ccda3d1ab9d5ced5265fdb13f1882d5476c71615"
-  integrity sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==
-  dependencies:
-    "@babel/helper-module-imports" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/helper-remap-async-to-generator" "^7.18.6"
-
-"@babel/plugin-transform-block-scoped-functions@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8"
-  integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-block-scoping@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz#f9b7e018ac3f373c81452d6ada8bd5a18928926d"
-  integrity sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-
-"@babel/plugin-transform-classes@^7.19.0":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz#0e61ec257fba409c41372175e7c1e606dc79bb20"
-  integrity sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==
-  dependencies:
-    "@babel/helper-annotate-as-pure" "^7.18.6"
-    "@babel/helper-compilation-targets" "^7.19.0"
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-function-name" "^7.19.0"
-    "@babel/helper-optimise-call-expression" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.19.0"
-    "@babel/helper-replace-supers" "^7.18.9"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-    globals "^11.1.0"
-
-"@babel/plugin-transform-computed-properties@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz#2357a8224d402dad623caf6259b611e56aec746e"
-  integrity sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-
-"@babel/plugin-transform-destructuring@^7.18.13":
-  version "7.18.13"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.13.tgz#9e03bc4a94475d62b7f4114938e6c5c33372cbf5"
-  integrity sha512-TodpQ29XekIsex2A+YJPj5ax2plkGa8YYY6mFjCohk/IG9IY42Rtuj1FuDeemfg2ipxIFLzPeA83SIBnlhSIow==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-
-"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8"
-  integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==
-  dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-duplicate-keys@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e"
-  integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-
-"@babel/plugin-transform-exponentiation-operator@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd"
-  integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==
-  dependencies:
-    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-for-of@^7.18.8":
-  version "7.18.8"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1"
-  integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-function-name@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0"
-  integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==
-  dependencies:
-    "@babel/helper-compilation-targets" "^7.18.9"
-    "@babel/helper-function-name" "^7.18.9"
-    "@babel/helper-plugin-utils" "^7.18.9"
-
-"@babel/plugin-transform-literals@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc"
-  integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-
-"@babel/plugin-transform-member-expression-literals@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e"
-  integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-modules-amd@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz#8c91f8c5115d2202f277549848874027d7172d21"
-  integrity sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==
-  dependencies:
-    "@babel/helper-module-transforms" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-    babel-plugin-dynamic-import-node "^2.3.3"
-
-"@babel/plugin-transform-modules-commonjs@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz#afd243afba166cca69892e24a8fd8c9f2ca87883"
-  integrity sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==
-  dependencies:
-    "@babel/helper-module-transforms" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/helper-simple-access" "^7.18.6"
-    babel-plugin-dynamic-import-node "^2.3.3"
-
-"@babel/plugin-transform-modules-systemjs@^7.19.0":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz#5f20b471284430f02d9c5059d9b9a16d4b085a1f"
-  integrity sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A==
-  dependencies:
-    "@babel/helper-hoist-variables" "^7.18.6"
-    "@babel/helper-module-transforms" "^7.19.0"
-    "@babel/helper-plugin-utils" "^7.19.0"
-    "@babel/helper-validator-identifier" "^7.18.6"
-    babel-plugin-dynamic-import-node "^2.3.3"
-
-"@babel/plugin-transform-modules-umd@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9"
-  integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==
-  dependencies:
-    "@babel/helper-module-transforms" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-named-capturing-groups-regex@^7.19.0":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.0.tgz#58c52422e4f91a381727faed7d513c89d7f41ada"
-  integrity sha512-HDSuqOQzkU//kfGdiHBt71/hkDTApw4U/cMVgKgX7PqfB3LOaK+2GtCEsBu1dL9CkswDm0Gwehht1dCr421ULQ==
-  dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.19.0"
-    "@babel/helper-plugin-utils" "^7.19.0"
-
-"@babel/plugin-transform-new-target@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8"
-  integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-object-super@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c"
-  integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/helper-replace-supers" "^7.18.6"
-
-"@babel/plugin-transform-parameters@^7.18.8":
-  version "7.18.8"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz#ee9f1a0ce6d78af58d0956a9378ea3427cccb48a"
-  integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-property-literals@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3"
-  integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-regenerator@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz#585c66cb84d4b4bf72519a34cfce761b8676ca73"
-  integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-    regenerator-transform "^0.15.0"
-
-"@babel/plugin-transform-reserved-words@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a"
-  integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-shorthand-properties@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9"
-  integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-spread@^7.19.0":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz#dd60b4620c2fec806d60cfaae364ec2188d593b6"
-  integrity sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.19.0"
-    "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
-
-"@babel/plugin-transform-sticky-regex@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc"
-  integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-template-literals@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e"
-  integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-
-"@babel/plugin-transform-typeof-symbol@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0"
-  integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-
-"@babel/plugin-transform-unicode-escapes@^7.18.10":
-  version "7.18.10"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246"
-  integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.9"
-
-"@babel/plugin-transform-unicode-regex@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca"
-  integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==
-  dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/preset-env@^7.0.0":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.19.0.tgz#fd18caf499a67d6411b9ded68dc70d01ed1e5da7"
-  integrity sha512-1YUju1TAFuzjIQqNM9WsF4U6VbD/8t3wEAlw3LFYuuEr+ywqLRcSXxFKz4DCEj+sN94l/XTDiUXYRrsvMpz9WQ==
-  dependencies:
-    "@babel/compat-data" "^7.19.0"
-    "@babel/helper-compilation-targets" "^7.19.0"
-    "@babel/helper-plugin-utils" "^7.19.0"
-    "@babel/helper-validator-option" "^7.18.6"
-    "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6"
-    "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9"
-    "@babel/plugin-proposal-async-generator-functions" "^7.19.0"
-    "@babel/plugin-proposal-class-properties" "^7.18.6"
-    "@babel/plugin-proposal-class-static-block" "^7.18.6"
-    "@babel/plugin-proposal-dynamic-import" "^7.18.6"
-    "@babel/plugin-proposal-export-namespace-from" "^7.18.9"
-    "@babel/plugin-proposal-json-strings" "^7.18.6"
-    "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9"
-    "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6"
-    "@babel/plugin-proposal-numeric-separator" "^7.18.6"
-    "@babel/plugin-proposal-object-rest-spread" "^7.18.9"
-    "@babel/plugin-proposal-optional-catch-binding" "^7.18.6"
-    "@babel/plugin-proposal-optional-chaining" "^7.18.9"
-    "@babel/plugin-proposal-private-methods" "^7.18.6"
-    "@babel/plugin-proposal-private-property-in-object" "^7.18.6"
-    "@babel/plugin-proposal-unicode-property-regex" "^7.18.6"
-    "@babel/plugin-syntax-async-generators" "^7.8.4"
-    "@babel/plugin-syntax-class-properties" "^7.12.13"
-    "@babel/plugin-syntax-class-static-block" "^7.14.5"
-    "@babel/plugin-syntax-dynamic-import" "^7.8.3"
-    "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
-    "@babel/plugin-syntax-import-assertions" "^7.18.6"
-    "@babel/plugin-syntax-json-strings" "^7.8.3"
-    "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
-    "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
-    "@babel/plugin-syntax-numeric-separator" "^7.10.4"
-    "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
-    "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
-    "@babel/plugin-syntax-optional-chaining" "^7.8.3"
-    "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
-    "@babel/plugin-syntax-top-level-await" "^7.14.5"
-    "@babel/plugin-transform-arrow-functions" "^7.18.6"
-    "@babel/plugin-transform-async-to-generator" "^7.18.6"
-    "@babel/plugin-transform-block-scoped-functions" "^7.18.6"
-    "@babel/plugin-transform-block-scoping" "^7.18.9"
-    "@babel/plugin-transform-classes" "^7.19.0"
-    "@babel/plugin-transform-computed-properties" "^7.18.9"
-    "@babel/plugin-transform-destructuring" "^7.18.13"
-    "@babel/plugin-transform-dotall-regex" "^7.18.6"
-    "@babel/plugin-transform-duplicate-keys" "^7.18.9"
-    "@babel/plugin-transform-exponentiation-operator" "^7.18.6"
-    "@babel/plugin-transform-for-of" "^7.18.8"
-    "@babel/plugin-transform-function-name" "^7.18.9"
-    "@babel/plugin-transform-literals" "^7.18.9"
-    "@babel/plugin-transform-member-expression-literals" "^7.18.6"
-    "@babel/plugin-transform-modules-amd" "^7.18.6"
-    "@babel/plugin-transform-modules-commonjs" "^7.18.6"
-    "@babel/plugin-transform-modules-systemjs" "^7.19.0"
-    "@babel/plugin-transform-modules-umd" "^7.18.6"
-    "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.0"
-    "@babel/plugin-transform-new-target" "^7.18.6"
-    "@babel/plugin-transform-object-super" "^7.18.6"
-    "@babel/plugin-transform-parameters" "^7.18.8"
-    "@babel/plugin-transform-property-literals" "^7.18.6"
-    "@babel/plugin-transform-regenerator" "^7.18.6"
-    "@babel/plugin-transform-reserved-words" "^7.18.6"
-    "@babel/plugin-transform-shorthand-properties" "^7.18.6"
-    "@babel/plugin-transform-spread" "^7.19.0"
-    "@babel/plugin-transform-sticky-regex" "^7.18.6"
-    "@babel/plugin-transform-template-literals" "^7.18.9"
-    "@babel/plugin-transform-typeof-symbol" "^7.18.9"
-    "@babel/plugin-transform-unicode-escapes" "^7.18.10"
-    "@babel/plugin-transform-unicode-regex" "^7.18.6"
-    "@babel/preset-modules" "^0.1.5"
-    "@babel/types" "^7.19.0"
-    babel-plugin-polyfill-corejs2 "^0.3.2"
-    babel-plugin-polyfill-corejs3 "^0.5.3"
-    babel-plugin-polyfill-regenerator "^0.4.0"
-    core-js-compat "^3.22.1"
-    semver "^6.3.0"
-
-"@babel/preset-modules@^0.1.5":
-  version "0.1.5"
-  resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9"
-  integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.0.0"
-    "@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
-    "@babel/plugin-transform-dotall-regex" "^7.4.4"
-    "@babel/types" "^7.4.4"
-    esutils "^2.0.2"
-
-"@babel/register@^7.7.7":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.18.9.tgz#1888b24bc28d5cc41c412feb015e9ff6b96e439c"
-  integrity sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==
-  dependencies:
-    clone-deep "^4.0.1"
-    find-cache-dir "^2.0.0"
-    make-dir "^2.1.0"
-    pirates "^4.0.5"
-    source-map-support "^0.5.16"
-
 "@babel/register@^7.8.3":
   version "7.17.7"
   resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.17.7.tgz#5eef3e0f4afc07e25e847720e7b987ae33f08d0b"
@@ -905,13 +166,6 @@
     pirates "^4.0.5"
     source-map-support "^0.5.16"
 
-"@babel/runtime@^7.8.4":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
-  integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
-  dependencies:
-    regenerator-runtime "^0.13.4"
-
 "@babel/template@^7.16.7", "@babel/template@^7.18.10":
   version "7.18.10"
   resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
@@ -921,7 +175,7 @@
     "@babel/parser" "^7.18.10"
     "@babel/types" "^7.18.10"
 
-"@babel/traverse@^7.17.10", "@babel/traverse@^7.18.9", "@babel/traverse@^7.19.0":
+"@babel/traverse@^7.17.10", "@babel/traverse@^7.19.0":
   version "7.19.0"
   resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.0.tgz#eb9c561c7360005c592cc645abafe0c3c4548eed"
   integrity sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==
@@ -937,7 +191,7 @@
     debug "^4.1.0"
     globals "^11.1.0"
 
-"@babel/types@^7.17.10", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.4.4":
+"@babel/types@^7.17.10", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0":
   version "7.19.0"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600"
   integrity sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==
@@ -2065,42 +1319,6 @@ axios@^0.24.0:
   dependencies:
     follow-redirects "^1.14.4"
 
-babel-plugin-add-header-comment@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/babel-plugin-add-header-comment/-/babel-plugin-add-header-comment-1.0.3.tgz#511c4901062640d5a480b4ac3edd6944195850ec"
-  integrity sha1-URxJAQYmQNWkgLSsPt1pRBlYUOw=
-
-babel-plugin-dynamic-import-node@^2.3.3:
-  version "2.3.3"
-  resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3"
-  integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==
-  dependencies:
-    object.assign "^4.1.0"
-
-babel-plugin-polyfill-corejs2@^0.3.2:
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz#e4c31d4c89b56f3cf85b92558954c66b54bd972d"
-  integrity sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q==
-  dependencies:
-    "@babel/compat-data" "^7.17.7"
-    "@babel/helper-define-polyfill-provider" "^0.3.2"
-    semver "^6.1.1"
-
-babel-plugin-polyfill-corejs3@^0.5.3:
-  version "0.5.3"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz#d7e09c9a899079d71a8b670c6181af56ec19c5c7"
-  integrity sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==
-  dependencies:
-    "@babel/helper-define-polyfill-provider" "^0.3.2"
-    core-js-compat "^3.21.0"
-
-babel-plugin-polyfill-regenerator@^0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz#8f51809b6d5883e07e71548d75966ff7635527fe"
-  integrity sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw==
-  dependencies:
-    "@babel/helper-define-polyfill-provider" "^0.3.2"
-
 backbone@1.4.x:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.4.1.tgz#099a78184bc07b034048a8332229c2ccca1e3e62"
@@ -2199,7 +1417,7 @@ browserslist@^4.12.0, browserslist@^4.6.4:
     node-releases "^2.0.3"
     picocolors "^1.0.0"
 
-browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.21.3:
+browserslist@^4.14.5, browserslist@^4.20.2:
   version "4.21.3"
   resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a"
   integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==
@@ -2508,14 +1726,6 @@ convert-source-map@^1.7.0:
   dependencies:
     safe-buffer "~5.1.1"
 
-core-js-compat@^3.21.0, core-js-compat@^3.22.1:
-  version "3.25.0"
-  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.25.0.tgz#489affbfbf9cb3fa56192fe2dd9ebaee985a66c5"
-  integrity sha512-extKQM0g8/3GjFx9US12FAgx8KJawB7RCQ5y8ipYLbmfzEzmFRWdDjIlxDx82g7ygcNG85qMVUSRyABouELdow==
-  dependencies:
-    browserslist "^4.21.3"
-    semver "7.0.0"
-
 core-util-is@^1.0.3, core-util-is@~1.0.0:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
@@ -2532,14 +1742,7 @@ cosmiconfig@^7.0.1:
     path-type "^4.0.0"
     yaml "^1.10.0"
 
-cross-env@^7.0.2:
-  version "7.0.3"
-  resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
-  integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
-  dependencies:
-    cross-spawn "^7.0.1"
-
-cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
+cross-spawn@^7.0.2, cross-spawn@^7.0.3:
   version "7.0.3"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
   integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@@ -4049,11 +3252,6 @@ jsesc@^2.5.1:
   resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
   integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
 
-jsesc@~0.5.0:
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
-  integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==
-
 json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
   version "2.3.1"
   resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
@@ -4261,11 +3459,6 @@ lodash.clone@3.0.3:
     lodash._bindcallback "^3.0.0"
     lodash._isiterateecall "^3.0.0"
 
-lodash.debounce@^4.0.8:
-  version "4.0.8"
-  resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
-  integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
-
 lodash.defaultsdeep@4.6.1:
   version "4.6.1"
   resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6"
@@ -4639,16 +3832,6 @@ object-keys@^1.1.1:
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
   integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
 
-object.assign@^4.1.0:
-  version "4.1.4"
-  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f"
-  integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==
-  dependencies:
-    call-bind "^1.0.2"
-    define-properties "^1.1.4"
-    has-symbols "^1.0.3"
-    object-keys "^1.1.1"
-
 object.assign@^4.1.2:
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
@@ -5443,59 +4626,11 @@ redent@^3.0.0:
     indent-string "^4.0.0"
     strip-indent "^3.0.0"
 
-regenerate-unicode-properties@^10.0.1:
-  version "10.0.1"
-  resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56"
-  integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==
-  dependencies:
-    regenerate "^1.4.2"
-
-regenerate@^1.4.2:
-  version "1.4.2"
-  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
-  integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
-
-regenerator-runtime@^0.13.4:
-  version "0.13.9"
-  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
-  integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
-
-regenerator-transform@^0.15.0:
-  version "0.15.0"
-  resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537"
-  integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==
-  dependencies:
-    "@babel/runtime" "^7.8.4"
-
 regexpp@^3.2.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
   integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
 
-regexpu-core@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.1.0.tgz#2f8504c3fd0ebe11215783a41541e21c79942c6d"
-  integrity sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==
-  dependencies:
-    regenerate "^1.4.2"
-    regenerate-unicode-properties "^10.0.1"
-    regjsgen "^0.6.0"
-    regjsparser "^0.8.2"
-    unicode-match-property-ecmascript "^2.0.0"
-    unicode-match-property-value-ecmascript "^2.0.0"
-
-regjsgen@^0.6.0:
-  version "0.6.0"
-  resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d"
-  integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==
-
-regjsparser@^0.8.2:
-  version "0.8.4"
-  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f"
-  integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==
-  dependencies:
-    jsesc "~0.5.0"
-
 repeat-string@^1.6.1:
   version "1.6.1"
   resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
@@ -5544,7 +4679,7 @@ resolve@^1.1.7, resolve@^1.20.0, resolve@^1.22.0:
     path-parse "^1.0.7"
     supports-preserve-symlinks-flag "^1.0.0"
 
-resolve@^1.10.0, resolve@^1.14.2, resolve@^1.9.0:
+resolve@^1.10.0, resolve@^1.9.0:
   version "1.22.1"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
   integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@@ -5625,11 +4760,6 @@ selenium-webdriver@4.1.1:
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
   integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
 
-semver@7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
-  integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
-
 semver@7.3.5:
   version "7.3.5"
   resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
@@ -5637,7 +4767,7 @@ semver@7.3.5:
   dependencies:
     lru-cache "^6.0.0"
 
-semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
+semver@^6.0.0, semver@^6.3.0:
   version "6.3.0"
   resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
   integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
@@ -6144,29 +5274,6 @@ underscore@~1.13.4:
   resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.4.tgz#7886b46bbdf07f768e0052f1828e1dcab40c0dee"
   integrity sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==
 
-unicode-canonical-property-names-ecmascript@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"
-  integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==
-
-unicode-match-property-ecmascript@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3"
-  integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==
-  dependencies:
-    unicode-canonical-property-names-ecmascript "^2.0.0"
-    unicode-property-aliases-ecmascript "^2.0.0"
-
-unicode-match-property-value-ecmascript@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714"
-  integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==
-
-unicode-property-aliases-ecmascript@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8"
-  integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==
-
 uniq@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
-- 
GitLab