Re: A proposal for Element constructors

Another solution to that "more than one tag per interface" problem is
to introduce subclasses of those interfaces for each tag.

Adam


On Tue, Oct 25, 2011 at 8:42 PM, Kentaro Hara <haraken@chromium.org> wrote:
> Hi folks,
> * Background *
> I have been working on making DOM objects look and feel more like ordinary
> JavaScript objects. I implemented Event constructors  [1], for example.
>
> * Proposal *
> Element.create() has proposed and been under discussion [2]. Besides
> Element.create(), I propose constructors for Elements, like "new
> HTMLButtonElement(...)", "new HTMLDivElement(...)" and "new
> HTMLVideoElement(...)". I think that both Element.create() *and* Element
> constructors are useful.
> For example,
>     var button = new HTMLButtonElement( {disabled: true},
>                                                                         [new
> TextNode("Click Me!!"),
>                                                                          new
> Image( {src: "http://example.com/xxx.png"} ) ] );
>     document.body.appendChild(button);
> is equivalent to the following HTML:
>     <button disabled>
>     Click Me!!
>     <img src = "http://example.com/xxx.png" />
>     </button>
> As shown in above, the constructor has two arguments. The first one is a
> dictionary of Element properties. The second one is an array of Nodes, which
> become child nodes of the Element.
>
> * Advantages of Element constructors *
> (a) Better errors when you misspell it
> Element.create("vdieo", {src: ...} ) ==> No error; HTMLUnknownElement is
> created
> new HTMLVdieoElement( {src: ...} ) ==> ReferenceError; Stack trace points
> you to the faulty line of code
> (b) Consistency with other constructable DOM objects
> e.g. new XMLHttpRequest(), new Image(), new Event(), new CustomEvent(), new
> MessageEvent(), ...
> (c) Enables to subtype DOM objects in the future
> We are planning to make DOM objects subtype-able, like this:
>     function MyButton(text) {
>         HTMLButtonElement.call(this);    /* (#) */
>         this.textContent = text;
>     }
>     MyButton.prototype = Object.create(HTMLButtonElement.prototype, {...});
>     var fancyButton = new MyButton("Click Me!!");
> In order to make the line (#) work, HTMLButtonElement must have a
> constructor.
>
> * Spec examples *
> interface [
>     NamedConstructor(optional HTMLButtonElementInit initDict, optional
> NodeArray children)
> ] HTMLButtonElement : HTMLElement {
>     attribute boolean disabled;
>     attribute DOMString value;
>     ... (omitted)
> }
> dictionary HTMLButtonElementInit : HTMLElementInit {
>     boolean disabled;
>     DOMString value;
>     ... (omitted)
> }
> interface [
>     NamedConstructor(optional HTMLElementInit initDict, optional NodeArray
> children)
> ] HTMLElement : Element {
>     attribute DOMString lang;
>     attribute DOMString className;
>     ... (omitted)
> }
> dictionary HTMLElementInit : ElementInit {
>     DOMString lang;
>     DOMString className;
>     ... (omitted)
> }
> interface Element : Node {
>     readonly attribute DOMString tagName;
>     ... (omitted)
> }
> dictionary ElementInit : NodeInit {
>     DOMString tagName;
>     ... (omitted)
> }
> interface Node {
>     readonly attribute unsigned short nodeType;
>     ... (omitted)
> }
> dictionary NodeInit {
>     unsigned short nodeType;
>     ... (omitted)
> }
>
> * Discussion
> (a) Element.create() *and* Element constructors?
> I think that both are useful for the reasons that dominicc pointed out in
> [3]. Element.create() is good when we have a tag name in hand, like
>     var tag = "button";
>     Element.create(tag, { }, ...);
> On the other hand, Element constructors have the advantages that I described
> above.
> (b) How to specify properties and attributes in the dictionary argument
> A property and an attribute are two different things [4]. A property is the
> thing that can be set by a setter like foo.value, and an attribute is the
> thing that can be set by foo.setAttribute(). A discussion has been conducted
> on how we can set up properties and attributes in the dictionary argument
> [2]. Proposed approaches in [2] are as follows:
> (b-1) Let a constructor have two dictionaries, one for properties and the
> other for attributes, e.g. new HTMLButtonElement( {disabled: true}, {class:
> "myButton", onclick: func}, ...)
> (b-2) Add a prefix character to attributes, e.g new HTMLButtonElement(
> {disabled: true, "@class": "myButton", "@onclick": func} )
> (b-3) Introduce a reserved key "attributes", e.g new HTMLButtonElement(
> {disabled: true, attributes: {class: "myButton", onclick: func} } )
> Another difficulty around attributes is how to naturally set a value of a
> boolean attribute in the dictionary when we have the value in hand. In case
> of a property, you just need to write like this:
>     var b = new HTMLButtonElement({disabled: value});
> However, in case of an attribute, we need to write like this:
>     var options = {};
>     if (value)
>         options.disabled = "";
>     var b = new HTMLButtonElement(options);
> Basically, I think that we should keep the succinctness of constructors and
> should not introduce a new syntax just for allowing people to set attributes
> in the constructor. Thus, I propose that we allow only properties in the
> dictionary, at least at the present moment. If we found in the future that
> people wish to set attributes in the constructor, we can discuss the feature
> again then.
> (c) How to specify child Elements in the constructor argument
> Possible approaches are as follows:
> (c-1) As variable arguments, e.g. new HTMLButtonElement( { ... }, child1,
> child2, child3, ...)
> (c-2) As an array, e.g. new HTMLButtonElement( { ... }, [child1, child2,
> child3] )
> (c-3) As variable arguments. We expand arguments of type array. e.g. new
> HTMLButtonElement( { ... }, child1, [child2, child3], child4, ...) is
> equivalent to new HTMLButtonElement({ ... }, child1, child2, child3, child4,
> ...)
> I guess that (c-3) is not good for the complicated rule. I think that both
> (c-1) and (c-2) are possible, but I prefer (c-1). I think that implicit
> array expansion is not necessary, since ES6 is introducing "..." operator
> for array expansion [6]. In other words, you can write like this:
>     var array = [child1, child2, child3, ......];
>     new HTMLButtonElement({ ...... }, ...array);
> (d) What should the owner document of the created Element be?
> I think that we can assume that the owner document is window.document, as
> existing constructors (new Image(), new Audio() and new Option()) is
> assuming. Some cases can expect an owner document other than
> window.document, but they are not so common. I believe that we should focus
> on making most of practical use cases simpler rather than supporting
> specialized cases that do not really need a convenience shortcut.
> (e) How to specify a namespace of attributes
> I propose that we do not support namespaced attributes like "xmlns:foo",
> since they are rare [5]. Again, we should focus on making most of practical
> use cases simpler.
> (f) How to create an unknown element that can be created by
> document.createElement("unknooooown")
> Fortunately, the HTML5 spec has HTMLUnknownElement. You can create an
> unknown element by new HTMLUnknownElement( {tagName: "unknooooown"}, ...)
> (g) How to handle HTMLElements that have more than one tags
> For example, both <ins> and <del> are tags of HTMLModificationElement. Then,
> how does the constructor look like? I think that we can easily handle this
> issue by distinguishing tags using a tagName property, e.g. new
> HTMLModificationElement( {tagName: "ins"}, ...) or new
> HTMLModificationElement( {tagName: "del"}, ...)
>
> [1] https://bugs.webkit.org/show_bug.cgi?id=67824
> [2] http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0537.html
> [3] http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0707.html
> [4] http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0666.html
> [5] http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0721.html
> [6] http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts (11.2.4
> Argument Lists)
>
>
> --
> Kentaro Hara, Tokyo, Japan (http://haraken.info)
>

Received on Wednesday, 26 October 2011 03:55:29 UTC