WICG / webcomponents

Web Components specifications
Other
4.38k stars 371 forks source link

Permit retrieval of registered classes from window.customElements #445

Closed JanMiksovsky closed 8 years ago

JanMiksovsky commented 8 years ago

Following up on issue #431, I'd like to propose that window.customElements allow a dev to retrieve information about the custom elements which have been registered. It sounds like @domenic was supportive of this idea, so as a strawman, I propose adding the following:

This, at least would meet the needs I've encountered, chiefly being able to: 1) easily verify that a particular custom element has in fact been registered, 2) conditionally define an element if it hasn't already been registered. E.g.:

if (!window.customElements.get('my-element')) {
  window.customElements.define('my-element', MyElement);
}
domenic commented 8 years ago

A couple questions:

  1. What is the use case for iteration?
  2. Is it a problem that get(name) returns only the constructor, and not any of the other relevant information? Most interestingly, I imagine, whether or not it's a type extension and if so of what.
annevk commented 8 years ago

It should probably also return the callbacks stored by the user agent... Or at least we should have the option to do that if we think it's useful at some point.

domenic commented 8 years ago

Maybe .get() just gets the constructor, and .getDefinition() gets an object representing the definition?

Anyway, who's interested in implementing this if I spec it? @rniwa @kojiishi ... trying to Will Chen's GitHub handle...

rniwa commented 8 years ago

I don't want to support customElements[@@iterator] but providing a mechanism to get the definition seems fine to me.

JanMiksovsky commented 8 years ago

To answer @domenic's question: I think the iterator would be generally useful for tools/extensions that want to list the elements which have been registered. But I don't have a pressing need for it right now. If the iterator is hard, it's by no means required for v1.

rianby64 commented 8 years ago

Let's consider an example for the iterator:

// somewhere else were defined MyElement1, MyElement2... and so on
window.customElements.define('my-element1', MyElement1);
window.customElements.define('my-element2', MyElement2);

// then, let's play with Iterator...
var alreadyDefined = window.customElements; // 
for (var customElement of alreadyDefined) {
  console.dir(customElement);   // should I see here MyElement1, MyElement2?
}

What about if somewhere else we've imported a custom element that registers some new custom elements?

<link rel="import" href="myExamples.html"> <!-- here we define more custom elements? -->

Remember that all imports don't have context.

What are the pros and cons if have a table with all registered custom elements? If it's needed I'd like to check this table from a clear place... for example

var defined = window.customElements.definitions;
for (var customElement in defined) {
   console.dir(customElement);
}

And if check if an element already was registered.

if (!window.customElements.definitions.getItem('my-element1')) { 
  // ...
}

The above is following the convention given for Attributes.

annevk commented 8 years ago

I don't think we can consider HTML imports as a use case given that nobody but Chrome wants to implement it.

rianby64 commented 8 years ago

@annevk Let's not consider HTML imports, but let's consider what @JanMiksovsky proposed: window.customElements[@@iterator]() What about if manipulate the defined custom elements via window.customElements.definitions? I think that the existing structure for Element.attributes fits good to window.customElements.definitions. Here we've the possibility to define functions like hasDefinition(), getDefinition() and so on. I hope that has sense.

rianby64 commented 8 years ago

@annevk Thanks a lot. By the way. I found that the example about how to import html via link looks simple. But also I see that HTML import draft offers different ways to import html. I'll read the manuals and take your advice in count.

domenic commented 8 years ago

I don't see any reason to create anything as complex as Element.prototype.attributes when nobody so far has stated a use case. (Although @JanMiksovsky gave a "tools/extensions" use case, that's probably better served by extensions APIs, not web platform APIs.)

rianby64 commented 8 years ago

@domenic I see you noticed that Element.prototype.attributes is a complex thing. Let me write some ideas.

A CustomElementsRegistry's list of defined local names is the list containing all of the local names of the custom element definitions in the registry.

  1. As mentioned at "2.4 The CustomElementsRegistry interface" the window.customElements is a list.
  2. As mentioned at "3.1 HTML+: The Window object" I see that window.customElements is an instance of "2.4 The CustomElementsRegistry interface".

Then,

  1. Is it necessary to expose the list from the registry?
  2. If expose it, should be used the root element window.customElements?

I think that to expose the list of defined custom elements should be used an extra attribute... something like

window.customElements.definitions
// or
window.customElements.elements
// or something similar

But... The same name window.customElements states that we're working with custom elements. So. We've an object window.customElements that 1) defines new custom elements 2) behaves like a list

domenic commented 8 years ago

I am supremely uninterested in the API shape. What I am interested in is use cases. It's probably not worth your time bikeshedding the former.

rianby64 commented 8 years ago

Ok. The use cases will drive us to this conversation at some point.

jarek-foksa commented 8 years ago

In case every standard element gets its own constructor as discussed in https://github.com/whatwg/html/issues/896, wouldn't it make more sense to have a registry that includes both standard and custom elements? Sample use cases:

const SUPPORTS_PICTURE = document.elements.has("picture");
const SUPPORTS_SMIL = document.elements.has("animate");
const SUPPORTS_MATHML = document.elements.has("math");
const SUPPORTS_MESH_GRADIENTS = document.elements.has("mesh");
domenic commented 8 years ago

@jarek-foksa can you explain what the use case for that is? If it's about figuring out support, you can do that just as easily by testing for 'HTMLPictureElement' in window etc.

jarek-foksa commented 8 years ago

@domenic This looks rather inconsistent to me:

if (window.HTMLPictureElement) {
  let picture = document.createElement("picture");
}

I would prefer to have a choice of either constructor-based or name-based APIs that I could use consistently:

// Name-based approach
if (document.elements.has("picture")) {
  let picture = document.elements.create("picture");
}

// Constructor-based approach
if (window.HTMLPictureElement) {
  let picture = new HTMLPictureElement();
}
domenic commented 8 years ago

I don't see any need to introduce an entire new registry API surface just to fix some aesthetic inconsistency.

rianby64 commented 8 years ago

I think that @domenic desires to see a very short way to check if a custom element was defined or not. What about if

var check = document.querySelector('my-custom-element');
if (check) {
  console.log('my-custom-element already defined');
}
annevk commented 8 years ago

Is this needed for v1?

rniwa commented 8 years ago

It seems like this is a v2 feature although it has a very high benefit-to-cost ratio so I'd consider adding this earlier than other v2 features.

domenic commented 8 years ago

Untagging needs-consensus as it seems like this has consensus at least in its basic form. I'll spec .get(name) soon.

rianby64 commented 8 years ago

Please, let's summary. I'd like to understand the thread :smile: .get(name) means window.get(name) or document.get(name)?

The current documentation states:

window.define('name', ClassName)

So,

window.get('name') should return ClassName. Right?

Should you consider to name that function in a more specific way? I see that window has already some getters

window.getComputedStyle;
window.getSelection;
window.getMatchedCSSRules;

Does have sense to name the function to getDefinition ? It's just an opinion... If getDefinition is too long then get sounds good too. Thanks!

domenic commented 8 years ago

It's window.customElements, not document or window.

There's no getDefinition for now, just get.

rianby64 commented 8 years ago

Ah :smile: excelente! So, window.customElements.get('name') returns ClassName. Understood. Thanks a lot.

domenic commented 8 years ago

This is included in https://github.com/whatwg/html/pull/1012.

annevk commented 8 years ago

\o/