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

document.querySelector() doesn't return specific class #184

Open
regseb opened this issue Nov 13, 2022 · 7 comments
Open

document.querySelector() doesn't return specific class #184

regseb opened this issue Nov 13, 2022 · 7 comments

Comments

@regseb
Copy link

regseb commented Nov 13, 2022

Hi,

For some elements, the document.querySelector() method doesn't return the specific class, but a HTMLElement. For example with the <meta> element whose object returned isn't an HTMLMetaElement.

import * as linkedom from 'linkedom';

const { document } = linkedom.parseHTML(`
  <html>
    <head>
      <meta name="foo" content="bar">
    </head>
    <body>
      <button>Baz/<button>
      <span>Qux/span>
      <a>Quux</a>
    </body>
  </html>
`);


console.log(document.querySelector("meta") instanceof linkedom.HTMLMetaElement); // false
console.log(document.querySelector("button") instanceof linkedom.HTMLButtonElement); // true
console.log(document.querySelector("span") instanceof linkedom.HTMLSpanElement); // false
console.log(document.querySelector("a") instanceof linkedom.HTMLAnchorElement); // true

Maybe the problem happens only on the class that doesn't call registerHTMLClass().

@WebReflection
Copy link
Owner

meta is not registered as special tag IIRC and I have no plan to register all elements as special tags ... after reading all other issues you are having, I might suggest you are better off with JSDOM if you expect everything in the HTML standard to be implemented in here. This maybe will save you time for future issues: it's not a goal of this project to have the whole HTML standard working ... it actually tries to care the minimal amount of time to render SSR, not to replace JSDOM or a real browser and the read path is not super interesting in here as you always have regular workaround via getAttribute or other primitives.

@regseb
Copy link
Author

regseb commented Nov 13, 2022

I'm porting my Chrome extension to Manifest V3 which requires the use of a service worker. But in the service worker, the DOMParser object isn't available. So I want to use LinkeDOM as polyfill with the worker version 👍. I only need to parse HTML and find values with querySelector().

I find a bug on the dataset (uhyphen#1). And my other problems are the lack of properties: HTMLScriptElement.text #182, HTMLMetaElement.content #183, HTMLBlockquoteElement.cite, HTMLVideoElement.poster and HTMLEmbedElement.type. I created only two issues because then I thought that it was not the purpose of this project to have all properties.

I have a workaround:

import * as linkedom from "./lib/linkedom.js";

if (!("DOMParser" in globalThis)) {
    globalThis.DOMParser = linkedom.DOMParser;

    Object.defineProperty(linkedom.HTMLScriptElement.prototype, "text", {
        get() {
            return this.textContent;
        },
    });
}

But for content, I can't use HTMLMetaElement because querySelector() returns a HTMLElement. I can add the property in HTMLElement prototype, but it adds the property on all HTML elements.

Object.defineProperty(linkedom.HTMLElement.prototype, "content", {
    get() {
        return this.getAttribute("content") ?? "";
    },
});

@WebReflection
Copy link
Owner

it's a web extension though, you can do whatever you want and nothing else should be affected? to have classes exposed and elements upgraded (it's like builtin extends in LinkeDOM even for native classes) you need to register the class to the parser, then you cna polyfill by your own.

these attributes are for today, every other for tomorrow ... you can likely overcome all of them through getAttribute after knowing what you are selecting, or use textContent instead of text for scripts ... not sure why you can't workaround these cases but heck, web extensions envs don't affect other sandboxes, do whatever you like there?

@WebReflection
Copy link
Owner

P.S. a way to export <option> is here, similarly to how you'd need to export all other special tags in your case, meta included, plus attributes https://github.com/WebReflection/linkedom/blob/155dfb9de84c672a0b2f4476d14f68d4b9a5054e/esm/html/option-element.js

@regseb
Copy link
Author

regseb commented Nov 13, 2022

I'm not blocked by all the issues I have opened. I can modify my code to use getAttribute() or override the classes provided by LinkeDOM.

By fixing directly in LinkeDOM, if other users have the same problems as me: they will benefit from the fixes.

I understand that you don't want to add an infinite of properties. You can close the issues I opened if you want.

@WebReflection
Copy link
Owner

WebReflection commented Nov 13, 2022

the option one had a very valid use case because in SSR you want to write option.value = 'thing' and see that reflected, as much as selected, if true ... others look just like read-only accessors or not too interesting as SSR use cases when you can just use setAttribute or getAttribute so if a use-case is pretty common and compelling, happy to put it in there, if I have to accept every single weird accessor, we can say goodbye to performance in various ultra-common scenarios, reason these requests have been filed only today, after 1+ year this project has been adopted already by many. I don't see your requests as really necessary for daily usage, a bit too specialized, imho ... but maybe I am wrong?

@WebReflection
Copy link
Owner

P.S. if nothing, it's very possible I should think about a way to export pluggable in features/accessors/classes to recognize when querySelector is used so that patching these on demand is possible

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

No branches or pull requests

2 participants