mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
fix(browser): stop a cancelled drag from leaving every browser tab unclickable (#26986)
The webview registry made every webview click-through on dragstart and only restored it on dragend or drop. A dragstart that something cancels (for example pressing and moving an agent logo in the tab strip, which the tab drag sensor cancels) never starts a drag, so neither event fires and every existing browser tab ignores clicks until a later full drag or a reload. A live native drag delivers no pointer events to the page, so any pointerdown or pointermove now ends the native-drag passthrough. Renderer pointer drags hold their own passthrough tokens and are unaffected.
This commit is contained in:
@@ -76,7 +76,13 @@ describe('webview registry drag listeners', () => {
|
||||
|
||||
registerPersistentWebview('page-1', createWebview())
|
||||
|
||||
expect(addedListeners.map((entry) => entry.type)).toEqual(['dragstart', 'dragend', 'drop'])
|
||||
expect(addedListeners.map((entry) => entry.type)).toEqual([
|
||||
'dragstart',
|
||||
'dragend',
|
||||
'drop',
|
||||
'pointerdown',
|
||||
'pointermove'
|
||||
])
|
||||
})
|
||||
|
||||
it('removes drag listeners after the last webview is destroyed', async () => {
|
||||
@@ -86,7 +92,7 @@ describe('webview registry drag listeners', () => {
|
||||
registerPersistentWebview('page-1', createWebview())
|
||||
registerPersistentWebview('page-2', createWebview())
|
||||
|
||||
expect(addedListeners).toHaveLength(3)
|
||||
expect(addedListeners).toHaveLength(5)
|
||||
|
||||
destroyPersistentWebview('page-1')
|
||||
|
||||
@@ -94,7 +100,13 @@ describe('webview registry drag listeners', () => {
|
||||
|
||||
destroyPersistentWebview('page-2')
|
||||
|
||||
expect(removedListeners.map((entry) => entry.type)).toEqual(['dragstart', 'dragend', 'drop'])
|
||||
expect(removedListeners.map((entry) => entry.type)).toEqual([
|
||||
'dragstart',
|
||||
'dragend',
|
||||
'drop',
|
||||
'pointerdown',
|
||||
'pointermove'
|
||||
])
|
||||
expect(unregisterGuestMock).toHaveBeenCalledWith({ browserPageId: 'page-1' })
|
||||
expect(unregisterGuestMock).toHaveBeenCalledWith({ browserPageId: 'page-2' })
|
||||
})
|
||||
@@ -124,13 +136,35 @@ describe('webview registry drag listeners', () => {
|
||||
expect(secondWebview.style.pointerEvents).toBe('auto')
|
||||
})
|
||||
|
||||
it('releases native drag passthrough when a cancelled dragstart never starts a drag', async () => {
|
||||
const { registerPersistentWebview } = await import('./webview-registry')
|
||||
const webview = createWebview()
|
||||
webview.style.pointerEvents = 'auto'
|
||||
registerPersistentWebview('page-1', webview)
|
||||
const listener = (type: string): ((event: Event) => void) => {
|
||||
const found = addedListeners.find((entry) => entry.type === type)?.listener
|
||||
if (typeof found !== 'function') {
|
||||
throw new Error(`${type} listener missing`)
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
for (const pointerType of ['pointermove', 'pointerdown']) {
|
||||
listener('dragstart')(new Event('dragstart'))
|
||||
expect(webview.style.pointerEvents).toBe('none')
|
||||
// No dragend or drop follows a cancelled dragstart; the next pointer event proves no drag is live.
|
||||
listener(pointerType)(new Event(pointerType))
|
||||
expect(webview.style.pointerEvents).toBe('auto')
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps one listener set across repeated registrations', async () => {
|
||||
const { registerPersistentWebview } = await import('./webview-registry')
|
||||
|
||||
registerPersistentWebview('page-1', createWebview())
|
||||
registerPersistentWebview('page-2', createWebview())
|
||||
|
||||
expect(addedListeners).toHaveLength(3)
|
||||
expect(addedListeners).toHaveLength(5)
|
||||
})
|
||||
|
||||
it('profiles live webviews and registered browser guests for memory breadcrumbs', async () => {
|
||||
|
||||
@@ -44,6 +44,8 @@ type DragListenerRegistry = {
|
||||
dragstart: () => void
|
||||
dragend: () => void
|
||||
drop: () => void
|
||||
pointerdown: () => void
|
||||
pointermove: () => void
|
||||
}
|
||||
|
||||
function getListenerHost(): (Window & { [DRAG_LISTENER_KEY]?: DragListenerRegistry }) | null {
|
||||
@@ -62,6 +64,8 @@ function removeDragListeners(): void {
|
||||
window.removeEventListener('dragstart', existingListeners.dragstart, true)
|
||||
window.removeEventListener('dragend', existingListeners.dragend, true)
|
||||
window.removeEventListener('drop', existingListeners.drop, true)
|
||||
window.removeEventListener('pointerdown', existingListeners.pointerdown, true)
|
||||
window.removeEventListener('pointermove', existingListeners.pointermove, true)
|
||||
delete listenerHost[DRAG_LISTENER_KEY]
|
||||
dragListenersAttached = false
|
||||
nativeDragPassthroughRelease?.()
|
||||
@@ -81,13 +85,19 @@ function ensureDragListeners(): void {
|
||||
const dragstart = (): void => setWebviewsDragPassthrough(true)
|
||||
const dragend = (): void => setWebviewsDragPassthrough(false)
|
||||
const drop = (): void => setWebviewsDragPassthrough(false)
|
||||
// Why: a cancelled dragstart never starts a drag, so no dragend or drop follows and every webview
|
||||
// would stay click-through. A live native drag delivers no pointer events, so one proves it is over.
|
||||
const pointerdown = (): void => setWebviewsDragPassthrough(false)
|
||||
const pointermove = (): void => setWebviewsDragPassthrough(false)
|
||||
|
||||
window.addEventListener('dragstart', dragstart, true)
|
||||
window.addEventListener('dragend', dragend, true)
|
||||
window.addEventListener('drop', drop, true)
|
||||
window.addEventListener('pointerdown', pointerdown, true)
|
||||
window.addEventListener('pointermove', pointermove, true)
|
||||
// Why: only live webviews need drag passthrough listeners; removing them
|
||||
// when the registry empties keeps browserless sessions free of global hooks.
|
||||
listenerHost[DRAG_LISTENER_KEY] = { dragstart, dragend, drop }
|
||||
listenerHost[DRAG_LISTENER_KEY] = { dragstart, dragend, drop, pointerdown, pointermove }
|
||||
dragListenersAttached = true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user