Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import $ from "jquery";
import { describe, expect, it, vi } from "vitest";

import { setupAnswerEventHandlers } from "./RelationMap.js";

vi.mock("../../../services/utils.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../../services/utils.js")>();
return {
...actual,
default: {
...actual.default,
filterAttributeName: vi.fn((val: string) => val)
}
};
});

describe("RelationMap - $answer event synchronization", () => {

it("dispatches input event with bubbles:true when Enter is pressed", () => {
const $answer = $("<input type='text' />");
const dispatchSpy = vi.spyOn($answer[0], "dispatchEvent");

setupAnswerEventHandlers($answer);
$answer.trigger($.Event("keydown", { key: "Enter" }));

expect(dispatchSpy).toHaveBeenCalledWith(
expect.objectContaining({ type: "input", bubbles: true })
);
});

it("dispatches input event with bubbles:true when input loses focus (blur)", () => {
const $answer = $("<input type='text' />");
const dispatchSpy = vi.spyOn($answer[0], "dispatchEvent");

setupAnswerEventHandlers($answer);
$answer.trigger("blur");

expect(dispatchSpy).toHaveBeenCalledWith(
expect.objectContaining({ type: "input", bubbles: true })
);
});

it("does not dispatch input event for non-Enter keys", () => {
const $answer = $("<input type='text' />");
const dispatchSpy = vi.spyOn($answer[0], "dispatchEvent");

setupAnswerEventHandlers($answer);
$answer.trigger($.Event("keydown", { key: "a" }));
$answer.trigger($.Event("keydown", { key: "Tab" }));
$answer.trigger($.Event("keydown", { key: "Escape" }));

const inputEvents = dispatchSpy.mock.calls
.map(([e]) => e as Event)
.filter((e) => e.type === "input" && e.bubbles === true);
expect(inputEvents).toHaveLength(0);
});

it("input event bubbles up to parent element", () => {
const $answer = $("<input type='text' />");
const parent = document.createElement("div");
parent.appendChild($answer[0]);

const parentListener = vi.fn();
parent.addEventListener("input", parentListener);

setupAnswerEventHandlers($answer);
$answer.trigger($.Event("keydown", { key: "Enter" }));

expect(parentListener).toHaveBeenCalledOnce();
expect(parentListener.mock.calls[0][0]).toMatchObject({ type: "input", bubbles: true });
});

});
14 changes: 14 additions & 0 deletions apps/client/src/widgets/type_widgets/relation_map/RelationMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,18 @@ function useNoteDragging({ containerRef, mapApiRef }: {
return dragProps;
}

export function setupAnswerEventHandlers($answer: JQuery<HTMLElement>) {
$answer.on("keydown", (e) => {
if (e.key === "Enter") {
$answer[0].dispatchEvent(new Event("input", { bubbles: true }));
}
});

$answer.on("blur", () => {
$answer[0].dispatchEvent(new Event("input", { bubbles: true }));
});
}
Comment on lines +407 to +417
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The separate keydown and blur event handlers can be combined into a single, more concise handler by leveraging jQuery's ability to listen for multiple events at once. This makes the code more compact and idiomatic.

export function setupAnswerEventHandlers($answer: JQuery<HTMLElement>) {
    $answer.on("keydown blur", (e) => {
        if (e.type === "blur" || e.key === "Enter") {
            $answer[0].dispatchEvent(new Event("input", { bubbles: true }));
        }
    });
}


function useRelationCreation({ mapApiRef, jsPlumbApiRef }: { mapApiRef: RefObject<RelationMapApi>, jsPlumbApiRef: RefObject<jsPlumbInstance> }) {
const connectionCallback = useCallback(async (info: OnConnectionBindInfo, originalEvent: Event) => {
const connection = info.connection;
Expand All @@ -422,6 +434,8 @@ function useRelationCreation({ mapApiRef, jsPlumbApiRef }: { mapApiRef: RefObjec
return;
}

setupAnswerEventHandlers($answer);

$answer.on("keyup", () => {
// invalid characters are simply ignored (from user perspective they are not even entered)
const attrName = utils.filterAttributeName($answer.val() as string);
Expand Down
Loading