fix external link blocking for nested elems in link

if a link contains nested elements like `<a href="http://somewhere"><strong>goto</strong></a>`
then the link is trigger by the `<strong />` element which has no `href` attribute.
We were thus releasing the event in this case, resulting in legitimate external links
not blocked.

We are now looking for the closest `<a />` parent (might be self) to retrieve the `href`
attribute and capture if necessary.
This commit is contained in:
renaud gaudin 2020-04-01 17:50:54 +00:00
parent 507002d34e
commit bce0e8c37c
1 changed files with 18 additions and 6 deletions

View File

@ -1,21 +1,22 @@
var block_path = "/catch/external";
// called only on external links
function capture_event(e) { e.target.setAttribute("href", encodeURI(block_path + "?source=" + e.target.href)); }
function capture_event(e, target) { target.setAttribute("href", encodeURI(block_path + "?source=" + target.href)); }
// called on all link clicks. filters external and call capture_event
function on_click_event(e) {
if ("target" in e && "href" in e.target) {
var href = e.target.href;
var target = findParent("a", e.target);
if (target !== null && "href" in target) {
var href = target.href;
if (window.location.pathname.indexOf(block_path) == 0) // already in catch page
return;
if (href.indexOf(window.location.origin) == 0)
return;
if (href.substr(0, 2) == "//")
return capture_event(e);
return capture_event(e, target);
if (href.substr(0, 5) == "http:")
return capture_event(e);
return capture_event(e, target);
if (href.substr(0, 6) == "https:")
return capture_event(e);
return capture_event(e, target);
return;
}
}
@ -23,6 +24,17 @@ function on_click_event(e) {
// script entrypoint (called on document ready)
function run() { live('a', 'click', on_click_event); }
// find first parent with tagname
function findParent(tagname, el) {
while (el) {
if ((el.nodeName || el.tagName).toLowerCase() === tagname.toLowerCase()) {
return el;
}
el = el.parentNode;
}
return null;
}
// matches polyfill
this.Element && function(ElementPrototype) {
ElementPrototype.matches = ElementPrototype.matches ||