From 9c48fb07aa555c89ad3d6cc59b74036ad467e9fa Mon Sep 17 00:00:00 2001
From: Florian Spreckelsen <f.spreckelsen@indiscale.com>
Date: Tue, 23 Jul 2024 16:48:51 +0200
Subject: [PATCH 1/2] TST: Add unit test for
 https://gitlab.com/linkahead/linkahead-webui/-/issues/258

---
 test/core/js/modules/form_panel.js.js | 47 +++++++++++++++++++++++----
 1 file changed, 40 insertions(+), 7 deletions(-)

diff --git a/test/core/js/modules/form_panel.js.js b/test/core/js/modules/form_panel.js.js
index f0cf3433..3a26aee2 100644
--- a/test/core/js/modules/form_panel.js.js
+++ b/test/core/js/modules/form_panel.js.js
@@ -23,25 +23,24 @@
 'use strict';
 
 QUnit.module("form_panel.js", {
-    before: function (assert) {
+    before: function(assert) {
 
     },
-    after: function (assert) {
-    }
+    after: function(assert) {}
 });
 
-QUnit.test("availability", function (assert) {
+QUnit.test("availability", function(assert) {
     assert.ok(form_panel.init, "init available");
-    assert.ok(form_panel.create_show_form_callback , "version available");
+    assert.ok(form_panel.create_show_form_callback, "version available");
 });
 
-QUnit.test("create_show_form_callback ", function (assert) {
+QUnit.test("create_show_form_callback ", function(assert) {
     const title = "Upload CSV File"; // title of the form and text in the toolbox
     const panel_id = "csv_upload_form_panel";
     const server_side_script = "csv_script.py";
     const tool_box = "Tools"; // Name of the drop-down menu where the button is added in the navbar
     const help_text = "something";
-    const accepted_files_formats = [ ".csv", "text/tsv", ] // Mime types and file endings.
+    const accepted_files_formats = [".csv", "text/tsv", ] // Mime types and file endings.
 
     const csv_form_config = {
         script: server_side_script,
@@ -80,3 +79,37 @@ QUnit.test("create_show_form_callback ", function (assert) {
 });
 
 
+QUnit.test("autofocus_without_form", function(assert) {
+    const title = "My not-form title";
+    const id = "not_form_id";
+    // callback function that creates a "form" without HTML form
+    // elements.  Trivial here, but could be e.g., the file upload
+    // from LinkAhead WebUI Core Components.
+    const init_not_form_field = () => {
+        const container = $(`<div class="row"/>`);
+        return container[0];
+    };
+    // This should always work
+    cb_without_autofocus = form_panel.create_show_form_callback(
+        id,
+        title,
+        undefined,
+        init_not_form_field,
+        false
+    );
+    const nav = document.createElement("nav");
+    document.body.appendChild(nav);
+    cb_without_autofocus();
+    assert.ok(document.querySelector(`#${id}`), "Callback was called without autofocus.");
+    $(`#${id}`).remove();
+
+    cb_with_autofocus = form_panel.create_show_form_callback(
+        id,
+        title,
+        undefined,
+        init_not_form_field,
+        true
+    );
+    cb_with_autofocus();
+    assert.ok(document.querySelector(`#${id}`), "Callback was called with autofocus, bt still okay.");
+});
-- 
GitLab


From 33a497da0069e36326444dbb33b128438650d42f Mon Sep 17 00:00:00 2001
From: Florian Spreckelsen <f.spreckelsen@indiscale.com>
Date: Tue, 23 Jul 2024 16:55:18 +0200
Subject: [PATCH 2/2] FIX: Ignore auto_focus for elements without form tags

---
 CHANGELOG.md              |  8 +++++++-
 src/core/js/form_panel.js | 25 +++++++++++++------------
 2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a6e07e42..52b29d79 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,7 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added ###
 
-- GRPC Entity Service can be enabled with `BUILD_MODULE_EXT_GRPC_ENTIY_SERVICE=ENABLED`. Defaults to `DISABLED`. More info on this module under `src/doc/extension/grpc-entity-service.rst`. <https://docs.indiscale.com/caosdb-webui/extension/grpc-entity-service.html>
+- GRPC Entity Service can be enabled with
+  `BUILD_MODULE_EXT_GRPC_ENTIY_SERVICE=ENABLED`. Defaults to
+  `DISABLED`. More info on this module under
+  `src/doc/extension/grpc-entity-service.rst`. <https://docs.indiscale.com/caosdb-webui/extension/grpc-entity-service.html>
 
 ### Changed ###
 
@@ -22,6 +25,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   different link to parent dir more visible.
 - [#255](https://gitlab.com/linkahead/linkahead-webui/-/issues/255) Remove
   disabled scroll bar under property names that would show on some browsers.
+- [#258](https://gitlab.com/linkahead/linkahead-webui/-/issues/258)
+  Ignore `auto_focus` when `create_show_form_callback` is called on an
+  element without HTML `form` elements.
 
 ### Security ###
 
diff --git a/src/core/js/form_panel.js b/src/core/js/form_panel.js
index 4eb2ddca..80f754b6 100644
--- a/src/core/js/form_panel.js
+++ b/src/core/js/form_panel.js
@@ -26,7 +26,7 @@
  * form_panel module for creating a panel below the navbar where forms can be
  * placed.
  */
-var form_panel = new function () {
+var form_panel = new function() {
     const logger = log.getLogger("form_panel");
     this.version = "0.1";
     this.dependencies = ["log", "caosdb_utils", "markdown", "bootstrap"];
@@ -38,7 +38,7 @@ var form_panel = new function () {
      * 1. Creates the form panel if it does not exist.
      * 2. Removes the welcome panel if present.
      */
-    this.get_form_panel = function (panel_id, title) {
+    this.get_form_panel = function(panel_id, title) {
         // remove welcome
         $(".caosdb-f-welcome-panel").remove();
         $(".caosdb-v-welcome-panel").remove();
@@ -60,7 +60,7 @@ var form_panel = new function () {
     /**
      * Remove the form panel from the DOM tree.
      */
-    this.destroy_form_panel = function (panel) {
+    this.destroy_form_panel = function(panel) {
         $(panel).remove();
     };
 
@@ -75,22 +75,22 @@ var form_panel = new function () {
      * The first input element will be focused unless you specify `false` as
      * fifths parameter.
      */
-    this.create_show_form_callback = function (
-        panel_id, title, form_config, form_creator=undefined, auto_focus=true
+    this.create_show_form_callback = function(
+        panel_id, title, form_config, form_creator = undefined, auto_focus = true
     ) {
         return (e) => {
             logger.trace("enter show_form_panel", e);
 
             const panel = $(form_panel.get_form_panel(panel_id, title));
             if (panel.find("form").length === 0) {
-                if (form_config != undefined && form_creator!=undefined){
+                if (form_config != undefined && form_creator != undefined) {
                     throw new Error("create_show_form_callback takes either a FormConfig or a function that creates the form");
                 }
 
                 var form;
-                if (form_config != undefined ){
+                if (form_config != undefined) {
                     form = form_elements.make_form(form_config);
-                } else if (form_creator != undefined ){
+                } else if (form_creator != undefined) {
                     form = form_creator();
                 } else {
                     throw new Error("create_show_form_callback takes a FormConfig or a function that creates the form");
@@ -104,17 +104,18 @@ var form_panel = new function () {
                 );
             }
             if (typeof auto_focus === "undefined" || !!auto_focus === true) {
-                if (panel.find("form")[0].length>0) {
+                if (panel.find("form").length > 0 && panel.find("form")[0].length > 0) {
                     panel.find("form")[0][0].focus();
+                } else {
+                    logger.debug("create_show_form_callback was called with auto_focus = true (default), but no form is given.");
                 }
             }
         }
     };
 
-    this.init = function () {
-    }
+    this.init = function() {}
 }
 
-$(document).ready(function () {
+$(document).ready(function() {
     caosdb_modules.register(form_panel);
 });
-- 
GitLab