From 55b7d232318d76dec02e4a47407d84bf8f86df25 Mon Sep 17 00:00:00 2001
From: Saurabh Kumar <theskumar@users.noreply.github.com>
Date: Mon, 2 Oct 2023 21:26:53 +0530
Subject: [PATCH] Performance improvement on application form (#3577)

This PR optimizes the code and logic responsible for unlocking
the application form on detecting human activity.

- makes the unlocking action DRY.
- move away from using jquery
- prevent the unlock action from firing on every mouse move, the unlock
  action is performed only once.
- Use more standard key names instead of keycodes.

---------

Co-authored-by: Fredrik Jonsson <frjo@xdeb.org>
---
 .../src/javascript/apply/application-form.js  | 121 +++++++++---------
 1 file changed, 60 insertions(+), 61 deletions(-)

diff --git a/hypha/static_src/src/javascript/apply/application-form.js b/hypha/static_src/src/javascript/apply/application-form.js
index 0c186933b..433d20795 100644
--- a/hypha/static_src/src/javascript/apply/application-form.js
+++ b/hypha/static_src/src/javascript/apply/application-form.js
@@ -1,72 +1,71 @@
-(function ($) {
+(function () {
     "use strict";
 
-    $(".application-form").each(function () {
-        var $application_form = $(this);
-        var $application_form_button = $application_form.find(
-            'button[type="submit"]'
-        );
+    const form = document.querySelector(".application-form");
+    const button = form.querySelector("[type=submit]");
+    const required = form.querySelectorAll("input[required]");
+    const groups = form.querySelectorAll(".form__group");
+    const errors = form.querySelectorAll(".form__error");
 
-        // set aria-required attribute true for required fields
-        $application_form
-            .find("input[required]")
-            .each(function (index, input_field) {
-                input_field.setAttribute("aria-required", true);
-            });
-
-        // add label_id as aria-describedby to help texts
-        $application_form
-            .find(".form__group")
-            .each(function (index, form_group) {
-                var label = form_group.querySelector("label");
-                if (label) {
-                    var label_id = label.getAttribute("for");
-                    if (form_group.querySelector(".form__help")) {
-                        form_group
-                            .querySelector(".form__help")
-                            .setAttribute("aria-describedby", label_id);
-                    }
-                }
-            });
-
-        // set aria-invalid for field with errors
-        var $error_fields = $application_form.find(".form__error");
-        if ($error_fields.length) {
-            // set focus to the first error field
-            $error_fields[0].querySelector("input").focus();
+    // Set aria-required attribute true for required fields.
+    required.forEach(function (field) {
+        field.setAttribute("aria-required", true);
+    });
 
-            $error_fields.each(function (index, error_field) {
-                const inputEl = error_field.querySelector("input, textarea");
-                if (inputEl) {
-                    inputEl.setAttribute("aria-invalid", true);
-                }
-            });
+    // Add label_id as aria-describedby to help text.
+    groups.forEach(function (group) {
+        const label = group.querySelector("label");
+        if (label) {
+            const label_id = label.getAttribute("for");
+            if (group.querySelector(".form__help")) {
+                group
+                    .querySelector(".form__help")
+                    .setAttribute("aria-describedby", label_id);
+            }
         }
+    });
 
-        // Remove the "no javascript" messages
-        $(".message-no-js").detach();
+    if (errors.length) {
+        // Set focus to the first error field.
+        const first_error = errors[0].querySelector("input");
+        if (first_error) {
+            first_error.focus();
+        }
 
-        // Wait for a mouse to move, indicating they are human.
-        $("body").mousemove(function () {
-            // Unlock the form.
-            $application_form.attr("action", "");
-            $application_form_button.attr("disabled", false);
+        // Set aria-invalid for field with errors.
+        errors.forEach(function (error) {
+            const input = error.querySelector("input, textarea");
+            if (input) {
+                input.setAttribute("aria-invalid", true);
+            }
         });
+    }
 
-        // Wait for a touch move event, indicating that they are human.
-        $("body").on("touchmove", function () {
-            // Unlock the form.
-            $application_form.attr("action", "");
-            $application_form_button.attr("disabled", false);
-        });
+    // Remove the "no javascript" messages
+    document.querySelector(".message-no-js").remove();
 
-        // A tab or enter key pressed can also indicate they are human.
-        $("body").keydown(function (e) {
-            if (e.keyCode === 9 || e.keyCode === 13) {
-                // Unlock the form.
-                $application_form.attr("action", "");
-                $application_form_button.attr("disabled", false);
-            }
-        });
+    const unlockApplicationForm = function () {
+        form.setAttribute("action", "");
+        button.removeAttribute("disabled");
+    };
+
+    // Unlock form on
+    // 1. mouse move
+    // 2. touch move
+    // 3. tab or enter key pressed
+    document.body.addEventListener("mousemove", unlockApplicationForm, {
+        once: true,
+    });
+    document.body.addEventListener("touchmove", unlockApplicationForm, {
+        once: true,
     });
-})(jQuery);
+    document.body.addEventListener(
+        "keydown",
+        function (e) {
+            if (e.key === "Tab" || e.key === "Enter") {
+                unlockApplicationForm();
+            }
+        },
+        { once: true }
+    );
+})();
-- 
GitLab