[whatwg] [dom] attributes collection not fully defined?
Hi, In the definition of the Element.attributes collection here: http://dom.spec.whatwg.org/#dom-element-attributes It doesn't seem to describe the behaviour for setting direct properties of the attributes collection, and how they map to attributes. For example, setting an attribute will create a property with the same name as the attribute: div = document.createElement(div); div.setAttribute(foo, bar); alert(div.attributes.foo); // [Object Attr] Except for read-only properties like length, which will not be shadowed by attributes: div.setAttribute(length, 99); alert(div.attributes.length); // 2 So far so good. Things get weird, though: div.attributes.fruit = apple; alert(div.attributes.fruit); // apple div.setAttribute(fruit, orange); alert(div.attributes.fruit); // [object Attr] div.removeAttribute(fruit); alert(div.attributes.fruit); // apple (!!!) Firefox and Chrome seem to be inconsistent on this, but at least in some situations they will shadow the property with an attribute, then restore the original property when the attribute is removed. You can have more fun by using Object.defineProperty to make the property read-only or unconfigurable, which Firefox and Chrome will again treat inconsistently. The mind boggles. How are these pseudo-properties supposed to be implemented? What magic hook calls them to life? The reason I ask is that jQuery = 1.9 uses div.attributes in its feature detection code, and it's causing us problems. Best regards, Michael -- Prince: Print with CSS! http://www.princexml.com
Re: [whatwg] [dom] attributes collection not fully defined?
On 5/29/13 11:08 PM, Michael Day wrote: For example, setting an attribute will create a property with the same name as the attribute: div = document.createElement(div); div.setAttribute(foo, bar); alert(div.attributes.foo); // [Object Attr] The DOM spec as written right now does not support this. This is a clear bug in the spec in that it's not web-compatible. See https://www.w3.org/Bugs/Public/show_bug.cgi?id=21986 Except for read-only properties like length, which will not be shadowed by attributes: div.setAttribute(length, 99); alert(div.attributes.length); // 2 This is the normal behavior for WebIDL things with a named getter. div.attributes.fruit = apple; alert(div.attributes.fruit); // apple div.setAttribute(fruit, orange); alert(div.attributes.fruit); // [object Attr] div.removeAttribute(fruit); alert(div.attributes.fruit); // apple (!!!) Firefox and Chrome seem to be inconsistent on this, but at least in some situations they will shadow the property with an attribute, then restore the original property when the attribute is removed. That is also the normal behavior for WebIDL things with a named getter. The mind boggles. How are these pseudo-properties supposed to be implemented? What magic hook calls them to life? If Element.attributes were using a named getter, the behavior would be as defined in http://dev.w3.org/2006/webapi/WebIDL/#getownproperty and http://dev.w3.org/2006/webapi/WebIDL/#defineownproperty Which is a bit dense but the short of it is: 1) The interface defines some set of exposed names. 2) Exposed names which would shadow something on the proto chain are ignored at get time. 3) Setting a property name that is not currently exposed creates a property on the object. If the name later becomes exposed, it will shadow the value that was set. 4) Setting a property name that is currently exposed does a Reject (which means throw in strict mode, silently do nothing in non-strict mode). Unless there is a named setter, of course. You can see all of this behavior in all sorts of other objects (e.g. in named access on an HTMLCollection)... But again, the spec as currently written: readonly attribute Attr[] attributes; does not in fact define any named getter behavior and is simply wrong... -Boris
Re: [whatwg] [dom] attributes collection not fully defined?
Hi Boris, Thank you for the detailed explanation. Having the WebIDL named getter definition helps to simplify things. This part still seems inconsistent with current browsers: 4) Setting a property name that is currently exposed does a Reject (which means throw in strict mode, silently do nothing in non-strict mode). Unless there is a named setter, of course. If I set the property name which has already been used for an attribute, it still seems to store the value: div.setAttribute(fruit, orange); div.attributes.fruit = apple; div.removeAttribute(fruit); alert(div.attributes.fruit); // apple except for a very strange bug in Firefox only, where if I *read* the value before removing it, the attribute doesn't go away later: div.setAttribute(fruit, orange); div.attributes.fruit = apple; alert(div.attributes.fruit.value); // orange div.removeAttribute(fruit); alert(div.attributes.fruit); // [object Attr] ??? Just adding the extra alert in the middle changes the value after removing the attribute, so that the Attr object is still returned. Anyway, doing nothing or throwing if the user tries to write to a property which is currently exposed seems like a much better option. Best regards, Michael -- Prince: Print with CSS! http://www.princexml.com
Re: [whatwg] [dom] attributes collection not fully defined?
On 5/30/13 12:06 AM, Michael Day wrote: This part still seems inconsistent with current browsers: 4) Setting a property name that is currently exposed does a Reject (which means throw in strict mode, silently do nothing in non-strict mode). Unless there is a named setter, of course. Behavior here varies. From object to object and from browser to browser, depending on whatever bizarre implementation details the browsers happen to be using to implement the properties appear and disappear thing. In particular, not all browsers are using WebIDL bindings for all objects yet, not even close. except for a very strange bug in Firefox only, where if I *read* the value before removing it, the attribute doesn't go away later: Yep, that's a result of how this object is currently implemented in release Firefox (not as a WebIDL object). It's a WebIDL object in Firefox nightly and Aurora builds if you want to test the behavior there. It looks like I slightly misread what the spec says about the setting case. Looks like for objects that do not have [OverrideBuiltins] setting will create/set a new own property that causes the property name to be hidden. So this testcase: div.setAttribute(fruit, orange); div.attributes.fruit = apple; alert(div.attributes.fruit); // apple div.removeAttribute(fruit); alert(div.attributes.fruit); // apple alerts apple in current trunk Firefox both times, for example. -Boris
Re: [whatwg] [dom] attributes collection not fully defined?
On Wed, May 29, 2013 at 8:34 PM, Boris Zbarsky bzbar...@mit.edu wrote: div.attributes.fruit = apple; alert(div.attributes.fruit); // apple div.setAttribute(fruit, orange); alert(div.attributes.fruit); // [object Attr] div.removeAttribute(fruit); alert(div.attributes.fruit); // apple (!!!) Firefox and Chrome seem to be inconsistent on this, but at least in some situations they will shadow the property with an attribute, then restore the original property when the attribute is removed. That is also the normal behavior for WebIDL things with a named getter. And this is why we should make named getter/setters a thing of the past. New specs are still being written which use these WebIDL features and almost all of them end up with confusing behavior like this. / Jonas
Re: [whatwg] [dom] attributes collection not fully defined?
And this is why we should make named getter/setters a thing of the past. New specs are still being written which use these WebIDL features and almost all of them end up with confusing behavior like this. +1 +1 +1 +1e100 :) Michael -- Prince: Print with CSS! http://www.princexml.com