virtualstate / navigation

Native JavaScript navigation [web api] implementation
MIT License
77 stars 5 forks source link

interceptEvents doesnt catch shadowDom links events #14

Closed ar2r13 closed 11 months ago

ar2r13 commented 1 year ago

Prerequisites

Version (i.e. v2.x.x)

1.0.1-alpha.192

Node.js version (i.e. 18.x, or N/A)

No response

Operating system

None

Operating system version (i.e. 20.04, 11.3, 10, or N/A)

No response

Description

interceptEvents doesnt catch shadowDom links events.

function interceptWindowClicks() checks only parents of event target. I guess it would be better to check is event path contains any a[href]

Steps to Reproduce


import('@virtualstate/navigation').then(({ applyPolyfill }) => applyPolyfill({
    interceptEvents: true
}))

### Expected Behavior

_No response_
fabiancook commented 1 year ago

Thanks I will look into this specific case!

Do you have a static html page that can trigger the issue? If you can make a PR, starting from

https://github.com/virtualstate/navigation/blob/17132f9caabf98ee76fad459841e9c649346921b/example/index.html#L1-L84

This page should be loading and then using the polyfill in a static way. The polyfill files thats referenced were are built files that I am just pushing to git... but you can update them too by building the project again.

I was using npx http-server -p 3000 ./example to serve the standalone example files for debugging. I should really add this as a script now too.

I will then be able to load this up in playwright and trigger the behaviour, and make a test around it like this, and will also be able to load it up directly in a browser and see how the behaviour works. Cheers!

(Sorry for the late reply I have been on holiday for the last month so haven't seen any github notifications!)

fabiancook commented 11 months ago

With the changes from #17, this should be good to go from here. I tested this in safari, I'll add some playwright tests to match though in the near future.


Some non important but informational bits....

In the image below the target of the originalEvent is <link-element>, an element with a shadow dom:

class LinkElement extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: "open" });
    shadow.innerHTML = '<a href="/">Link within Shadow DOM</a>';
  }
}

window.customElements.define('link-element', LinkElement)

image

Using composedPath()

image

If we inspect targets we can see the inner anchor element being accessible.

function getComposedPathTarget(event) {
    if (!event.composedPath) {
        return event.target;
    }
    const targets = event.composedPath();
    return targets[0] ?? event.target;
}

image

This only accounts for shadow DOMs using open mode.