Файли
openidea/src/platform/doubleClick.test.ts
T
l0ng-ai 329ad2c644 fix(ui): treat every second click of a burst as a double-click
WebKit fires `dblclick` only for the second click of a burst. A quick
double-click right after another arrives as `click` with `detail` 3 and 4 and
no `dblclick`, so the second double-click on a folder in the Project view (and
on any tree row, tab or list item handled by `onDoubleClick`) did nothing.

A window-level shim now dispatches a `dblclick` on the click's target for every
later even click of a burst (detail 4, 6, ...), after the page's own click
handlers. Existing `onDoubleClick` handlers and their `stopPropagation` apply
unchanged; an engine that fires its own `dblclick` for that click gets it
dropped as a duplicate.

The Project view test now delivers bursts the way WebKit does (`dblclick` only
at detail 2) and checks both expand modes over 2–6 click bursts.

Refs #724
2026-11-03 22:34:29 +08:00

65 рядки
2.0 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { fireEvent } from "@testing-library/react";
import { installRepeatedDoubleClick } from "./doubleClick";
describe("installRepeatedDoubleClick", () => {
let uninstall: () => void;
let el: HTMLElement;
let dbl: ReturnType<typeof vi.fn<(detail: number, target: EventTarget | null) => void>>;
beforeEach(() => {
uninstall = installRepeatedDoubleClick();
el = document.createElement("div");
document.body.append(el);
dbl = vi.fn();
el.addEventListener("dblclick", (e) => dbl((e as MouseEvent).detail, e.target));
});
afterEach(() => {
uninstall();
el.remove();
});
/** A burst as WebKit delivers it: `dblclick` only after the second click. */
const burst = (clicks: number) => {
for (let detail = 1; detail <= clicks; detail++) {
fireEvent.click(el, { detail });
if (detail === 2) fireEvent.doubleClick(el, { detail });
}
};
it("turns each later even click of a burst into one double-click on its target", () => {
burst(6);
expect(dbl.mock.calls).toEqual([
[2, el],
[4, el],
[6, el],
]);
});
it("leaves odd clicks, other buttons and the first double-click alone", () => {
burst(3);
fireEvent.click(el, { detail: 4, button: 1 });
expect(dbl.mock.calls).toEqual([[2, el]]);
});
it("drops the engine's own double-click when it also fires one", () => {
fireEvent.click(el, { detail: 4 });
fireEvent.doubleClick(el, { detail: 4 });
expect(dbl).toHaveBeenCalledTimes(1);
});
it("keeps the click handlers ahead of the double-click", () => {
const order: string[] = [];
el.addEventListener("click", () => order.push("click"));
el.addEventListener("dblclick", () => order.push("dblclick"));
fireEvent.click(el, { detail: 4 });
expect(order).toEqual(["click", "dblclick"]);
});
it("does nothing once uninstalled", () => {
uninstall();
fireEvent.click(el, { detail: 4 });
expect(dbl).not.toHaveBeenCalled();
});
});