- From: Joseph Orbegoso Pea <notifications@github.com>
- Date: Fri, 19 Aug 2016 20:30:01 -0700
- To: w3c/webcomponents <webcomponents@noreply.github.com>
- Message-ID: <w3c/webcomponents/issues/549@github.com>
Due to the renaming of some class methods (attached/detached to connected/disconnected) and removal of createdCallback in favor of constructors (which is a good thing!), I find myself writing my WebComponent base class (class-factory mixin) as follows.
My question is, should I be doing what I'm doing, or do you recommend something else? Note that the attached/detachedCallback methods simply call the connected/disconnectedCallback methods, and also note what I've done with `createdCallback` and the `constructor` due to the differences between v0 and v1. Subclasses of my WebComponent base class still use `createdCallback` rather than a constructor in order to be backwards compatible.
The code is as follows, with parts removed for brevity in order to show just the parts dealing with the v0/v1 APIs directly and how backwards compatibility is maintained:
```js
// Very very stupid hack needed for Safari in order for us to be able to extend
// the HTMLElement class. See:
// https://github.com/google/traceur-compiler/issues/1709
if (typeof window.HTMLElement != 'function') {
const _HTMLElement = function HTMLElement(){}
_HTMLElement.prototype = window.HTMLElement.prototype
window.HTMLElement = _HTMLElement
}
// XXX: Maybe we can improve by clearing items after X amount of time?
const classCache = new Map
function hasHTMLElementPrototype(constructor) {
if (!constructor) return false
if (constructor === HTMLElement) return true
else return hasHTMLElementPrototype(constructor.prototype)
}
/**
* Creates a WebComponent base class dynamically, depending on which
* HTMLElement class you want it to extend from. Extend from WebComponent when
* making a new Custom Element class.
*
* @example
* const WebComponent = WebComponentMixin(HTMLButtonElement)
* class AwesomeButton extends WebComponent { ... }
*
* @param {Function} elementClass The class that the generated WebComponent
* base class will extend from.
*/
export default
function WebComponentMixin(elementClass) {
if (!elementClass) elementClass = HTMLElement
if (!hasHTMLElementPrototype(elementClass)) {
throw new TypeError(
'The argument to WebComponentMixin must be a constructor that extends from or is HTMLElement.'
)
}
// if a base class that extends the given `elementClass` has already been
// created, return it.
if (classCache.has(elementClass))
return classCache.get(elementClass)
// otherwise, create it.
class WebComponent extends elementClass {
// constructor() is used in v1 Custom Elements instead of
// createdCallback() as in v0.
constructor() {
super()
// If the following is true, then we know the user should be using
// `document.registerElement()` to define an element from this class.
// `document.registerElement()` creates a new constructor, so if the
// constructor here is being called then that means the user is not
// instantiating a DOM HTMLElement as expected because it is required
// that the constructor returned from `document.registerElement` be used
// instead (this is a flaw of Custom Elements v0 which is fixed in v1
// where class constructors can be used directly).
if (document.registerElement && !customElements.define) {
// TODO: link to docs.
throw new Error(`
You cannot instantiate this class directly without first registering it
with \`document.registerElement(...)\`. See an example at http://....
`)
}
// Throw an error if no Custom Elements API exists.
if (!document.registerElement && !customElements.define) {
// TODO: link to docs.
throw new Error(`
Your browser does not support the Custom Elements API. You'll
need to install a polyfill. See how at http://....
`)
}
// otherwise the V1 API exists, so call the createdCallback, which
// is what Custom Elements v0 would call by default. Subclasses of
// WebComponent should put instantiation logic in createdCallback
// instead of in a custom constructor if backwards compatibility is
// to be maintained.
this.createdCallback()
}
createdCallback() {
// code removed for brevity...
}
connectedCallback() {
// code removed for brevity...
}
attachedCallback() { this.connectedCallback() } // back-compat
disconnectedCallback() {
// code removed for brevity...
}
detachedCallback() { this.disconnectedCallback() } // back-compat
}
classCache.set(elementClass, WebComponent)
return WebComponent
}
```
Any thoughts?
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/549
Received on Saturday, 20 August 2016 03:30:30 UTC