From 199f2b4bc522c81b6e0965d1a469484a0250168f Mon Sep 17 00:00:00 2001
From: Lauri Eskola <lauri.eskola@acquia.com>
Date: Thu, 12 May 2022 16:44:12 +0300
Subject: [PATCH] Issue #3101922 by bnjmnm, nod_, lauriii: Find replacement for
 Modernizr touchevent test and deprecate

---
 core/core.libraries.yml                       | 11 ++++-
 core/misc/modernizr-additional-tests.es6.js   | 43 -------------------
 core/misc/modernizr-additional-tests.js       | 23 ----------
 core/misc/touchevents-test.es6.js             | 11 +++++
 core/misc/touchevents-test.js                 |  8 ++++
 .../contextual/contextual.libraries.yml       |  1 +
 .../ContextualLinksTest.php                   |  3 ++
 .../Functional/Ajax/OffCanvasDialogTest.php   |  3 +-
 .../FunctionalJavascript/OffCanvasTest.php    |  3 ++
 .../ToolbarIntegrationTest.php                |  2 +
 core/modules/toolbar/toolbar.libraries.yml    |  6 +++
 .../TableDrag/TableDragTest.php               |  2 +
 core/themes/claro/claro.libraries.yml         | 11 ++---
 core/themes/seven/seven.theme                 |  8 ++--
 14 files changed, 57 insertions(+), 78 deletions(-)
 delete mode 100644 core/misc/modernizr-additional-tests.es6.js
 delete mode 100644 core/misc/modernizr-additional-tests.js
 create mode 100644 core/misc/touchevents-test.es6.js
 create mode 100644 core/misc/touchevents-test.js

diff --git a/core/core.libraries.yml b/core/core.libraries.yml
index 6bbedc837a0a..d8041ff11f4f 100644
--- a/core/core.libraries.yml
+++ b/core/core.libraries.yml
@@ -682,6 +682,7 @@ drupal.tabledrag:
     - core/drupal
     - core/drupalSettings
     - core/once
+    - core/drupal.touchevents-test
 
 drupal.tableheader:
   version: VERSION
@@ -723,6 +724,14 @@ drupal.timezone:
     - core/once
     - core/drupal
 
+drupal.touchevents-test:
+  header: true
+  version: VERSION
+  js:
+    # Set weight to -21 so it loads alongside Modernizr, the library previously
+    # responsible for this detection.
+    misc/touchevents-test.js: { weight: -21 }
+
 drupal.vertical-tabs:
   version: VERSION
   js:
@@ -990,7 +999,6 @@ modernizr:
   version: "3.11.7"
   js:
     assets/vendor/modernizr/modernizr.min.js: { preprocess: 0, weight: -21, minified: true }
-    misc/modernizr-additional-tests.js: { preprocess: 0, weight: -20 }
 
 normalize:
   remote: https://github.com/necolas/normalize.css
@@ -1116,6 +1124,7 @@ drupal.dialog.off_canvas:
     - core/drupal.announce
     - core/drupal.dialog
     - core/drupal.dialog.ajax
+    - core/drupal.touchevents-test
 
 js-cookie:
   remote: https://github.com/js-cookie/js-cookie
diff --git a/core/misc/modernizr-additional-tests.es6.js b/core/misc/modernizr-additional-tests.es6.js
deleted file mode 100644
index eb21361e4a8f..000000000000
--- a/core/misc/modernizr-additional-tests.es6.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * @file
- * Provides additional Modernizr tests.
- */
-((Modernizr) => {
-  // This is a copy of Modernizr's touchevents test from version 3.3.1. Drupal
-  // core has updated Modernizr to a version newer than 3.3.1, but this newer
-  // version does not include the touchevents test in its build. Modernizr's
-  // touchevents test is deprecated, and newer versions of this test do not work
-  // properly with Drupal as it significantly changes the criteria used for
-  // determining if touchevents are supported.
-  // The most recent known-to-work version, 3.3.1 is provided here. The only
-  // changes are refactoring the code to meet Drupal's JavaScript coding
-  // standards and calling prefixes and testStyles() via the Modernizr object
-  // as they are not in scope when adding a test via Modernizr.addTest();
-  // @todo find alternative to Modernizr's deprecated touchevent test in
-  //   http://drupal.org/node/3101922
-  // @see https://github.com/Modernizr/Modernizr/blob/v3.3.1/feature-detects/touchevents.js
-  Modernizr.addTest('touchevents', () => {
-    let bool;
-
-    if (
-      'ontouchstart' in window ||
-      (window.DocumentTouch && document instanceof window.DocumentTouch)
-    ) {
-      bool = true;
-    } else {
-      // include the 'heartz' as a way to have a non matching MQ to help
-      // terminate the join https://git.io/vznFH
-      const query = [
-        '@media (',
-        Modernizr._prefixes.join('touch-enabled),('),
-        'heartz',
-        ')',
-        '{#modernizr{top:9px;position:absolute}}',
-      ].join('');
-      Modernizr.testStyles(query, (node) => {
-        bool = node.offsetTop === 9;
-      });
-    }
-    return bool;
-  });
-})(Modernizr);
diff --git a/core/misc/modernizr-additional-tests.js b/core/misc/modernizr-additional-tests.js
deleted file mode 100644
index 35270745b7e6..000000000000
--- a/core/misc/modernizr-additional-tests.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-
-(Modernizr => {
-  Modernizr.addTest('touchevents', () => {
-    let bool;
-
-    if ('ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch) {
-      bool = true;
-    } else {
-      const query = ['@media (', Modernizr._prefixes.join('touch-enabled),('), 'heartz', ')', '{#modernizr{top:9px;position:absolute}}'].join('');
-      Modernizr.testStyles(query, node => {
-        bool = node.offsetTop === 9;
-      });
-    }
-
-    return bool;
-  });
-})(Modernizr);
\ No newline at end of file
diff --git a/core/misc/touchevents-test.es6.js b/core/misc/touchevents-test.es6.js
new file mode 100644
index 000000000000..8e7ab4831f85
--- /dev/null
+++ b/core/misc/touchevents-test.es6.js
@@ -0,0 +1,11 @@
+/**
+ * @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
new file mode 100644
index 000000000000..68efbdf9af81
--- /dev/null
+++ b/core/misc/touchevents-test.js
@@ -0,0 +1,8 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+document.documentElement.classList.add('ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch ? 'touchevents' : 'no-touchevents');
\ No newline at end of file
diff --git a/core/modules/contextual/contextual.libraries.yml b/core/modules/contextual/contextual.libraries.yml
index 7ae89909c420..bfc1c996c98f 100644
--- a/core/modules/contextual/contextual.libraries.yml
+++ b/core/modules/contextual/contextual.libraries.yml
@@ -25,6 +25,7 @@ drupal.contextual-links:
     # @todo Remove this in https://www.drupal.org/project/drupal/issues/3203920
     - core/internal.backbone
     - core/once
+    - core/drupal.touchevents-test
 
 drupal.contextual-toolbar:
   version: VERSION
diff --git a/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php b/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php
index 1d16440cbf50..726df7253c4f 100644
--- a/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php
+++ b/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php
@@ -59,6 +59,9 @@ public function testContextualLinksVisibility() {
     $contextualLinks = $this->assertSession()->waitForElement('css', '.contextual button');
     $this->assertNotEmpty($contextualLinks);
 
+    // Confirm touchevents detection is loaded with Contextual Links
+    $this->assertSession()->elementExists('css', 'html.no-touchevents');
+
     // Ensure visibility remains correct after cached paged load.
     $this->drupalGet('user');
     $contextualLinks = $this->assertSession()->waitForElement('css', '.contextual button');
diff --git a/core/modules/system/tests/src/Functional/Ajax/OffCanvasDialogTest.php b/core/modules/system/tests/src/Functional/Ajax/OffCanvasDialogTest.php
index cff73b818b0a..709b4eb6af7f 100644
--- a/core/modules/system/tests/src/Functional/Ajax/OffCanvasDialogTest.php
+++ b/core/modules/system/tests/src/Functional/Ajax/OffCanvasDialogTest.php
@@ -38,7 +38,6 @@ public function testDialog($position) {
     // Set up variables for this test.
     $dialog_renderable = AjaxTestController::dialogContents();
     $dialog_contents = \Drupal::service('renderer')->renderRoot($dialog_renderable);
-
     $off_canvas_expected_response = [
       'command' => 'openDialog',
       'selector' => '#drupal-off-canvas',
@@ -65,7 +64,7 @@ public function testDialog($position) {
     $wrapper_format = $position && ($position !== 'side') ? 'drupal_dialog.off_canvas_' . $position : 'drupal_dialog.off_canvas';
     $ajax_result = $this->drupalGet('ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => $wrapper_format]]);
     $ajax_result = Json::decode($ajax_result);
-    $this->assertEquals($off_canvas_expected_response, $ajax_result[3], 'off-canvas dialog JSON response matches.');
+    $this->assertEquals($off_canvas_expected_response, $ajax_result[4], 'off-canvas dialog JSON response matches.');
   }
 
   /**
diff --git a/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTest.php b/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTest.php
index c4f6a047aaac..6663a2766653 100644
--- a/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTest.php
+++ b/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTest.php
@@ -42,6 +42,9 @@ public function testOffCanvasLinks($theme) {
     $page = $this->getSession()->getPage();
     $web_assert = $this->assertSession();
 
+    // Confirm touchevents detection is loaded with Off Canvas assets.
+    $this->assertNotNull($web_assert->waitForElement('css', 'html.no-touchevents'));
+
     // Make sure off-canvas dialog is on page when first loaded.
     $web_assert->elementNotExists('css', '#drupal-off-canvas');
 
diff --git a/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarIntegrationTest.php b/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarIntegrationTest.php
index 9666a3af81db..62eeca51f5d7 100644
--- a/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarIntegrationTest.php
+++ b/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarIntegrationTest.php
@@ -37,6 +37,8 @@ public function testToolbarToggling() {
     $this->drupalGet('<front>');
     $this->assertNotEmpty($this->assertSession()->waitForElement('css', 'body.toolbar-horizontal'));
     $this->assertNotEmpty($this->assertSession()->waitForElementVisible('css', '.toolbar-tray'));
+    // Confirm touchevents detection is loaded with the toolbar.
+    $this->assertNotNull($this->assertSession()->waitForElement('css', 'html.no-touchevents'));
 
     $page = $this->getSession()->getPage();
 
diff --git a/core/modules/toolbar/toolbar.libraries.yml b/core/modules/toolbar/toolbar.libraries.yml
index eee3f4e2430c..146942e03119 100644
--- a/core/modules/toolbar/toolbar.libraries.yml
+++ b/core/modules/toolbar/toolbar.libraries.yml
@@ -19,6 +19,12 @@ toolbar:
       css/toolbar.icons.theme.css: {}
   dependencies:
     - core/modernizr
+    # Toolbar does not use touchevents detection, nor does it use Modernizr.
+    # Despite not using Modernizr, it loads it. Sites that expect modernizr to
+    # be available may be getting it due to it being part of Toolbar. Because
+    # of this, we must include drupal.touchevents-test so the expected
+    # `touchevents/no-touchevents` classes are still added to the page.
+    - core/drupal.touchevents-test
     - core/jquery
     - core/drupal
     - core/drupalSettings
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/TableDrag/TableDragTest.php b/core/tests/Drupal/FunctionalJavascriptTests/TableDrag/TableDragTest.php
index 4003ecf9e69e..9288ddaf7288 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/TableDrag/TableDragTest.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/TableDrag/TableDragTest.php
@@ -105,6 +105,8 @@ public function testDragAndDrop() {
     $session = $this->getSession();
     $page = $session->getPage();
 
+    // Confirm touchevents detection is loaded with Tabledrag
+    $this->assertNotNull($this->assertSession()->waitForElement('css', 'html.no-touchevents'));
     $weight_select1 = $page->findField("table[1][weight]");
     $weight_select2 = $page->findField("table[2][weight]");
     $weight_select3 = $page->findField("table[3][weight]");
diff --git a/core/themes/claro/claro.libraries.yml b/core/themes/claro/claro.libraries.yml
index 2a0bbc8c64f3..0f57051b9879 100644
--- a/core/themes/claro/claro.libraries.yml
+++ b/core/themes/claro/claro.libraries.yml
@@ -72,12 +72,13 @@ global-styling:
     # such as inputs, action links, buttons, dropbuttons. For usability and
     # accessibility reasons, we keep target sizes big enough on touch screen
     # devices (by not making these elements smaller than their default size).
-    # Modernizr is used for recognizing whether user is using a touch device or
+    # Modernizr was used for recognizing whether user is using a touch device or
     # not. This allows conditionally rendering small variation of the control
-    # elements on non-touch devices. In some cases, such as when rendering
-    # links, it is hard recognize when Modernizr should be attached, therefore
-    # it has to be always attached.
-    - core/modernizr
+    # elements on non-touch devices. Modernizr's touch detection has since been
+    # replaced by core/drupal.touchevents-test.
+    # In some cases, such as when rendering links, it is hard recognize when
+    # this detection should be attached, therefore it is always attached.
+    - core/drupal.touchevents-test
 
 node-form:
   version: VERSION
diff --git a/core/themes/seven/seven.theme b/core/themes/seven/seven.theme
index 8aa5ed8f717f..144f7c53be0d 100644
--- a/core/themes/seven/seven.theme
+++ b/core/themes/seven/seven.theme
@@ -118,17 +118,17 @@ function seven_preprocess_menu_local_action(array &$variables) {
   $variables['link']['#options']['attributes']['class'][] = 'button--primary';
   $variables['link']['#options']['attributes']['class'][] = 'button--small';
 
-  // We require Modernizr's touch test for button styling.
-  $variables['#attached']['library'][] = 'core/modernizr';
+  // We require the touchevents test for button styling.
+  $variables['#attached']['library'][] = 'core/drupal.touchevents-test';
 }
 
 /**
  * Implements hook_element_info_alter().
  */
 function seven_element_info_alter(&$type) {
-  // We require Modernizr for button styling.
+  // We require the touchevents test for button styling.
   if (isset($type['button'])) {
-    $type['button']['#attached']['library'][] = 'core/modernizr';
+    $type['button']['#attached']['library'][] = 'core/drupal.touchevents-test';
   }
 }
 
-- 
GitLab