Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add urlAttribute helper that uses baseURI (used for href, src etc.) #154

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

danburzo
Copy link

Fixes #153 by adding an urlAttribute helper to use in IDL properties that need to reflect HTML attributes representing an URL, such as HTMLAnchorElement.href, HTMLImageElement.src, etc.

@@ -14,8 +14,8 @@ class HTMLAnchorElement extends HTMLElement {
}

/* c8 ignore start */ // copy paste from img.src, already covered
get href() { return encodeURI(stringAttribute.get(this, 'href')); }
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getter/setter for href used to encode/decode the URI, and this change breaks some tests. Should this technique be adopted inside urlAttribute?

Browser behavior is below:

let a = document.createElement('a');
a.href = 'https://google.com/?q=asd&lol=<2>';
a.href
// "https://google.com/?q=asd&lol=%3C2%3E"
a.getAttribute('href')
// "https://google.com/?q=asd&lol=<2>"

Should we also store the raw value in the attribute, and encode it on the getter?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if tests break it means we'll break working code out there ... this change shouldn't require a major though, should it?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P.S. yes, we might want to encodeURI on the URL returned href, if URL returned href is not encoded already

Copy link
Owner

@WebReflection WebReflection Aug 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... which it does ...

new URL('/?q=asd&lol=<2>', 'https://google.com/').href
// "https://google.com/?q=asd&lol=%3C2%3E" 

so we want this behavior, I would drop the encoding but I am not sure we should drop the decoding ... the encoding is provided by the URL on current attribute which is the raw value, the decoding in assignment looks like still necessary to preserve the raw value ... this should not break anything, just remove the encodeURI in the getter.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to read a bit more to understand how to align with the HTML spec (if possible). The immediate fix for the breaking test is:

return new URL(attr, element.baseURI ?? undefined).href;

(baseURI is null in the absence of an explicit location or <base> element, and that's an invalid base URL.)

But the problem is the getter returns either the encoded or unencoded value depending on the validity of baseURI, and I wonder if that's the case in browsers as well.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation of baseURI is aware of <base> right now, but if speed is a concern this needs to be cached or otherwise optimized, so that might complicate things:

  get baseURI() {
    const ownerDocument = this.nodeType === DOCUMENT_NODE ?
                            this : this.ownerDocument;
    if (ownerDocument) {
      const base = ownerDocument.querySelector('base');
      if (base)
        return base.getAttribute('href');

      const {location} = ownerDocument.defaultView;
      if (location)
        return location.href;
    }

    return null;
  }

Let me know if you think this feature is worth it in relation with your goals / use-cases for linkedom. This has been an interesting rabbit hole regardless!

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uhm ... I see ... then return null should be return 'about:blank' ... right? I don't think this would break much code out there but it is, technically, a breaking change, due returning non falsy value when no case is met ... bummer!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't see a big problem with return 'about:blank'; although it's technically a breaking change, as is I guess changing the behavior of URL-like element attributes. What I'm more concerned is how to get rid of the inefficient querySelector each time you request href on a link, and still update the value when you mutate the DOM.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cached version of this module doesn't care about repeated qS/qSA operation if the DOM didn't mutate in the meanwhile, so if that's a concern, just use the cached version instead?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is linkedom/cached import, instead of the regular one https://github.com/WebReflection/linkedom#are-childnodes-and-children-always-computed

@danburzo danburzo marked this pull request as ready for review August 18, 2022 09:09
@@ -66,7 +66,7 @@ export class Node extends EventTarget {
const ownerDocument = this.nodeType === DOCUMENT_NODE ?
this : this.ownerDocument;
if (ownerDocument) {
const base = ownerDocument.querySelector('base');
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<base> elements without a href attribute should be skipped here. The algorithm is a bit more complicated (allowing for relative href), but maybe that can be addressed more thoroughly in a future PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

baseURI should be factored into HTMLAnchorElement.href
2 participants