delite/register

register is a utility module for defining custom elements.

Usage

You declare a new widget that is based off a DOM object that either is HTMLElement or implements HTMLElement, and also extends delite/CustomElement directly or indirectly. Typically you will extend delite/Widget or a subclass of delite/Widget rather than extending delite/CustomElement directly.

To register the most basic of widgets, you would do the following:

require(["delite/register", "delite/Widget"], function (register, Widget) {
    var MyWidget = register("my-widget", [HTMLElement, Widget], {
        foo: "bar"
    });
});

You can instantiate the widget programatically:

var mywidget1 = new MyWidget();

or using the custom tag in your HTML:

<my-widget></my-widget>

You can think of register as a combination of a class declaration system (internally it uses dcl, and document.registerElement from the new custom elements proposed standards.

Note that the register module has a createElement() method, and new MyWidget() calls that method.

register() takes three arguments:

Extensions

As mentioned above, the first extension must be a class/constructor function that has HTMLElement in its prototype chain. This will serve as the base element for the custom element that is part of your widget. HTMLElement has an interface that is roughly equivalent to the <div> tag and is the ancestor of all the HTML* DOM Elements. If your widget doesn't need any special features offered by other tags, HTMLElement is likely your best base for your widget.

If your widget through is designed to be an "extension" of another HTML element, like for example a <button>, then you should consider utilising a different base for your widget. This will ensure your widget will "behave" like that other root HTML element. For example, to create something that extends a <button>, you would do something like this:

require(["delite/register", "delite/Widget"], function (register, Widget) {
    var MyButton = register("my-widget", [HTMLButtonElement, Widget], {
        foo: "bar"
    });
});

And if you then wanted to instantiate this widget in HTML, you would use the following in markup:

<button is="my-button"></button>

You can also extend other widgets, but not base classes like delite/Widget that don't have HTMLElement in their prototype chain. If you are subclassing another widget, you should just use that as the base instead of one of the HTML* elements. For example, to create your own subclass of deliteful/Button:

require(["delite/register", "deliteful/Button"], function (register, Button) {
    var MyButtonSubClass = register("my-button-subclass", Button, {
        foo: "bar"
    });
});

And instantiate programatically:

var mybutton1 = new MyButtonSubClass();

or declaratively via HTML using the is attribute:

<button is="my-button-subclass"></button>

Because deliteful/Button has HTMLButtonElement as its base, it means that any subclasses need to utilise that root tag when instantiating via element creation. This means you should know if the widget you are descending from builds on top of a base other than HTMLElement.

Lifecycle

First of all, note that no constructor methods are called when a widget is created. Rather, createdCallback() and enterViewCallback() are called. Generally though, you will extend delite/Widget which provides more specific lifecycle methods.

Rendering a widget

Unlike Dijit, by the time createdCallback() is called (and in delite/Widget subclasses: render()), the widget's root node already exists. Either it's the original root node from the markup (ex: <button is="d-button">) or it was created via the internal register.createElement() call.

You cannot change the root node, although you can set attributes on it and setup event listeners. In addition, you will often create sub-nodes underneath the root node.

Also note that the root node is this. So putting those concepts together, a trivial render() method in a delite/Widget subclass would be:

render: function(){
    this.className = "d-button";
}

OOP

As mentioned earlier, register() is built on dcl, and it also exposes some methods from dcl for calling subclass methods. For example:

open: register.after(function(){
    // first the superclass open() call will run, then this code
})

Standards

register() tries to conform to the proposed custom elements standard. Internally, it will call document.registerElement() on platforms that support it.