From a0e4386c7a90efbbcd8c001a13aed22fc89a2279 Mon Sep 17 00:00:00 2001 From: sokumon Date: Thu, 25 Sep 2025 04:04:00 +0530 Subject: [PATCH] fix: let focus jump directly inside the first input of the first row --- .../public/js/frappe/form/controls/table.js | 28 ------------------- frappe/public/js/frappe/form/grid.js | 13 ++++++++- frappe/public/js/frappe/form/grid_row.js | 26 ++++++++++++++++- frappe/public/scss/common/grid.scss | 7 ++--- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/table.js b/frappe/public/js/frappe/form/controls/table.js index 62d31a3f7a..e056fe9e07 100644 --- a/frappe/public/js/frappe/form/controls/table.js +++ b/frappe/public/js/frappe/form/controls/table.js @@ -16,25 +16,6 @@ frappe.ui.form.ControlTable = class ControlTable extends frappe.ui.form.Control this.frm.grids[this.frm.grids.length] = this; } const me = this; - this.$wrapper.on("keydown", (e) => { - if (e.which == 9) { - if (e.shiftKey) { - let row_idx = me.set_current_row(e.target); - if (row_idx) { - this.grid.grid_rows[row_idx - 1].toggle_editable_row(true); - } - } else { - if (this.grid.grid_rows.length > 0) { - this.grid.grid_rows[this.grid.grid_rows.length - 1].toggle_editable_row( - true - ); - } else { - this.grid.add_new_row(null, null, true, null, true); - this.grid.grid_rows[0].toggle_editable_row(true); - } - } - } - }); this.$wrapper.on("paste", ":text", (e) => { const table_field = this.df.fieldname; const grid = this.grid; @@ -173,13 +154,4 @@ frappe.ui.form.ControlTable = class ControlTable extends frappe.ui.form.Control check_all_rows() { this.$wrapper.find(".grid-row-check")[0].click(); } - set_current_row(target) { - let current_row = null; - for (let i = 0; i < this.grid.grid_rows.length; i++) { - if (this.grid.grid_rows[i].wrapper.get(0).contains(target)) { - current_row = i + 1; - } - } - return current_row; - } }; diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js index 0b3c4623d0..959e720806 100644 --- a/frappe/public/js/frappe/form/grid.js +++ b/frappe/public/js/frappe/form/grid.js @@ -70,7 +70,7 @@ export default class Grid {

-
+
@@ -939,6 +939,7 @@ export default class Grid { } setTimeout(() => { + this.grid_rows[idx].toggle_editable_row(true); this.grid_rows[idx].row .find('input[type="Text"],textarea,select') .filter(":visible:first") @@ -1276,4 +1277,14 @@ export default class Grid { this.debounced_refresh(); } + + get_current_row(target) { + let current_row = null; + for (let i = 0; i < this.grid_rows.length; i++) { + if (this.grid_rows[i].wrapper.get(0).contains(target)) { + current_row = i; + } + } + return current_row; + } } diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index 10b18171e7..dcfae333a7 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -1101,7 +1101,17 @@ export default class GridRow { this.columns[df.fieldname] = $col; this.columns_list.push($col); - + if (ci == 0 && !this.header_row) { + $col.attr("tabIndex", 0); + $col.on("focus", function () { + if (me.grid.grid_rows.length == 0) { + me.grid.add_new_row(); + } + me.grid.grid_rows[me.grid.grid_rows.length - 1].toggle_editable_row(true); + me.grid.set_focus_on_row(); + $col.attr("tabIndex", ""); + }); + } return $col; } @@ -1199,6 +1209,8 @@ export default class GridRow { // flag list input if (this.columns_list && this.columns_list.slice(-1)[0] === column) { field.$input.attr("data-last-input", 1); + } else if (this.columns_list && this.columns_list.slice(0)[0] === column) { + field.$input.attr("data-first-input", 1); } } @@ -1288,6 +1300,18 @@ export default class GridRow { return false; } } + } else if (e.which === TAB && e.shiftKey) { + var first_column = me.wrapper + .find("input:enabled:not([type='checkbox'])") + .first() + .get(0); + var is_first_column = + $(this).attr("data-first-input") || first_column === this; + if (is_first_column) { + let ri = me.grid.get_current_row(e.target); + if (ri == 0) return; + me.grid.grid_rows[ri - 1].toggle_editable_row(true); + } } }); } diff --git a/frappe/public/scss/common/grid.scss b/frappe/public/scss/common/grid.scss index 817d337789..63a07df18e 100644 --- a/frappe/public/scss/common/grid.scss +++ b/frappe/public/scss/common/grid.scss @@ -8,9 +8,6 @@ color: var(--text-color); min-height: 150px; background-color: var(--subtle-accent); - &:focus-visible { - @include grid-focus(); - } } .form-grid.error { @@ -165,7 +162,9 @@ display: flex; vertical-align: middle; } - +.grid-static-col:focus-visible { + @include grid-focus(); +} .grid-static-col, .row-index { // height: 38px;