дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
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
Цей коміт міститься в:
1 джерело
eefe166cf7
коміт
329ad2c644
4 files changed
+151
-23
No files matched your search
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* WebKit (the macOS webview) 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, tab or row did nothing. This turns
|
||||
* every later even click of a burst into a `dblclick` on the same target, so React
|
||||
* `onDoubleClick` handlers (and their `stopPropagation`) see each double-click. An engine
|
||||
* that does fire its own `dblclick` for that click gets it suppressed as a duplicate.
|
||||
*/
|
||||
const synthetic = new WeakSet<Event>();
|
||||
|
||||
export function installRepeatedDoubleClick(win: Window = window): () => void {
|
||||
let last: { target: EventTarget; detail: number } | null = null;
|
||||
|
||||
// Bubble phase on the window: after the page's own click handlers, like the engine's dblclick.
|
||||
const onClick = (e: MouseEvent) => {
|
||||
last = null;
|
||||
if (e.button !== 0 || e.detail < 4 || e.detail % 2 !== 0 || !e.target) return;
|
||||
const dbl = new MouseEvent("dblclick", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
composed: true,
|
||||
view: e.view,
|
||||
detail: e.detail,
|
||||
screenX: e.screenX,
|
||||
screenY: e.screenY,
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
button: e.button,
|
||||
buttons: e.buttons,
|
||||
ctrlKey: e.ctrlKey,
|
||||
shiftKey: e.shiftKey,
|
||||
altKey: e.altKey,
|
||||
metaKey: e.metaKey,
|
||||
});
|
||||
synthetic.add(dbl);
|
||||
last = { target: e.target, detail: e.detail };
|
||||
e.target.dispatchEvent(dbl);
|
||||
};
|
||||
|
||||
const onDoubleClick = (e: MouseEvent) => {
|
||||
if (synthetic.has(e) || !last) return;
|
||||
const duplicate = e.detail === last.detail && e.target === last.target;
|
||||
last = null;
|
||||
if (!duplicate) return;
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
win.addEventListener("click", onClick);
|
||||
win.addEventListener("dblclick", onDoubleClick, true);
|
||||
return () => {
|
||||
win.removeEventListener("click", onClick);
|
||||
win.removeEventListener("dblclick", onDoubleClick, true);
|
||||
};
|
||||
}
|
||||
Reference in new issue
Заблокувати користувача