Any navigation triggered within a shadow tree will cause a regular navigation (i.e. a full reload) instead of going through Ember’s router if the source (e.g. a HTML a
element) is located in a shadow tree.
Discourse almost has this covered in these files:
app/assets/javascripts/discourse/initializers/click-interceptor.js.es6
app/assets/javascripts/discourse/lib/intercept-click.js.es6
In order to fix this in Discourse, we would need to replace jQuery’s event listener as it only listens for clicks on anchor elements. The events from inside the shadow DOM; however, will have the shadow host as a target. This can’t even be an anchor element; hence, this event listener never catches these clicks. The following code would need to listen on anchor elements and any shadow host elements. In general, this would mean listening on all elements, but only proceed with a) anchor elements or b) elements that are a shadow host. For the latter, one can walk their composed path as shown in my workaround below.
$("#main").on("click.discourse", "a", interceptClick);
I understand if that’s something you don’t even want to fix right now as Discourse doesn’t use shadow DOM. I’m putting this here for documentation and users who want to use shadow DOM inside Discourse.
Plugin workaround
I have small workaround active in my plugin. I listen for all click
events on the shadow host …
import DiscourseURL from 'discourse/lib/url';
// …
shadowHost.addEventListener('click', interceptClick);
… and check if in their composed path, there is an anchor element.
function interceptClick(event) {
for (const target of event.composedPath()) {
if (target.tagName === 'A' && target.href !== '') {
event.preventDefault();
DiscourseURL.routeTo(target.href);
return;
}
}
}
This is pretty similar to what Discourse does in the files mentioned above.
(If you don’t consider this a bug, I change the category to dev.)