diff --git a/rust/perspective-viewer/src/rust/components/form/code_editor.rs b/rust/perspective-viewer/src/rust/components/form/code_editor.rs index a6629e128c..bf8547b02a 100644 --- a/rust/perspective-viewer/src/rust/components/form/code_editor.rs +++ b/rust/perspective-viewer/src/rust/components/form/code_editor.rs @@ -75,6 +75,28 @@ fn on_keydown(event: KeyboardEvent, deps: &(UseStateSetter, Callback<()>)) event.prevent_default(); deps.1.emit(()) } + + // handle the tab key press + if event.key() == "Tab" { + event.prevent_default(); + + let caret_pos = elem.selection_start().unwrap().unwrap_or_default() as usize; + + let mut initial_text = elem.value(); + + initial_text.insert(caret_pos, '\t'); + + elem.set_value(&initial_text); + + let input_event = web_sys::InputEvent::new("input").unwrap(); + let _ = elem.dispatch_event(&input_event).unwrap(); + + // place caret after inserted tab + let new_caret_pos = (caret_pos + 1) as u32; + let _ = elem.set_selection_range(new_caret_pos, new_caret_pos); + + elem.focus().unwrap(); + } } /// Scrolling callback diff --git a/rust/perspective-viewer/test/js/column_settings/attributes_tab.spec.ts b/rust/perspective-viewer/test/js/column_settings/attributes_tab.spec.ts index 214cdcc707..17cc914a4f 100644 --- a/rust/perspective-viewer/test/js/column_settings/attributes_tab.spec.ts +++ b/rust/perspective-viewer/test/js/column_settings/attributes_tab.spec.ts @@ -95,6 +95,39 @@ test.describe("Attributes Tab", () => { view.columnSettingsSidebar.attributesTab.saveBtn ).toBeDisabled(); }); + test("Tab Button Click enters 4 spaces.", async ({ page }) => { + let view = new PageView(page); + await view.restore({ + expressions: { expr: "12345" }, + columns: ["expr", "Row ID"], + settings: true, + }); + let expr = await view.settingsPanel.activeColumns.getColumnByName( + "expr" + ); + await expr.editBtn.click(); + await view.columnSettingsSidebar.openTab("Attributes"); + + let sidebar = view.columnSettingsSidebar; + let attributesTab = sidebar.attributesTab; + + let textarea = attributesTab.expressionEditor.textarea; + + await textarea.type("foo", { delay: 100 }); + expect(await textarea.evaluate((input) => input!.value)).toStrictEqual( + "foo12345" + ); + + await textarea.type("\t", { delay: 100 }); + const expected = await textarea.evaluate((input) => input!.value); + + expect(expected).toContain("\t"); + + const caretPosition = await textarea.evaluate( + (input) => input!.selectionStart + ); + expect(caretPosition).toBe(4); // length of foo + length of '\t' = 4; + }); test("Reset button", async ({ page }) => { let view = new PageView(page); await view.restore({ diff --git a/tools/perspective-test/results.tar.gz b/tools/perspective-test/results.tar.gz index 3ea71c1185..08599ddace 100644 Binary files a/tools/perspective-test/results.tar.gz and b/tools/perspective-test/results.tar.gz differ