- From: Adam Barth <w3c@adambarth.com>
- Date: Tue, 25 Oct 2011 20:54:29 -0700
- To: Kentaro Hara <haraken@chromium.org>
- Cc: public-webapps@w3.org, Dominic Cooney <dominicc@chromium.org>
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