Skip navigation.

miscoded

the web is a hack

Posts tagged with "specs"

Google Maps vs. DOM2 specification 1-0

, , ,

Since users reported that seeing saved addresses and getting directions on Google Maps was broken in Opera I had to do some digging. Actually a lot of digging. Eventually, I ended up here:

xO.Tia=function(a){if(!a||a==window||!a.hasOwnProperty||xO.uSa(a))return xO.Type.NATIVE;if(xO.jTa(a))return xO.Type.PROTO;if(a.constructor===Function)return xO.Type.FUNCTION;if(a.constructor===Array)return xO.Type.ARRAY;if(a.constructor===Object)return xO.Type.OBJECT;return xO.Type.NATIVE};

..which in its unwrapped and scrambled glory is a method to figure out what sort of object "a" is. The bit we didn't handle like Maps expected was:
if(a.constructor===Object)return xO.Type.OBJECT;

If you pass a DOM node to this function that if clause is true and it will conclude that it is of type "Object". Further along there was some logic detecting that this node was an Object and thus not able to have event listeners.

So, no event listener is added and nothing at all happens when clicking the triangle to view your search history:


In Firefox, a node's constructor property points to the corresponding DOM2 HTML interface. To explain that in real English, the DOM 2 HTML specification says that for each element in HTML (BODY, A, DIV, P and so on) there should be a JavaScript object named window.HTML+name of element+Element (HTMLBodyElement, HTMLAnchorElement, HTMLDivElement, HTMLParagraphElement and so on).

What's the point of that? These are "prototypes" of the DOM. Through JavaScript's prototype inheritance feature you can add properties and methods to for example HTMLDivElement.prototype and all DIVs in your document will appear to have those properties and methods. For example
HTMLDivElement.prototype.getExternalLinks = function(){
    for(var list=[],links=this.getElementsByTagName('a'),l,i=0;l=links[i];i++)
        if((new RegExp( "https?:\/\/(?!"+location.hostname+")" )).test(l.getAttribute('href')))list.push(l);
    return list;
}

lets you call div.getExternalLinks() for any DIV in your DOM to list the anchors inside that DIV that point to a an external URL. Or maybe you want an isExternalLink() method on A nodes instead? No problem:
HTMLAnchorElement.prototype.isExternalLink = function(){
    return (new RegExp( "https?:\/\/(?!"+location.hostname+")" )).test(this.getAttribute('href'));
}

As you see, the DOM2 HTML standard gives you quite a lot of power to extend the DOM.

Back to our problem. When Google Maps in Firefox looks at div.constructor it points to the HTMLDivElement object.

In Opera, it points to window.Object.

The obvious question is: is Opera wrong?

The answer: No. We are perfectly standards-compliant. We follow ECMAScript 2.62 4.3.4 Constructor property spec, DOM2 Core, and DOM 2 HTML.

The problems is: none of these specifications really cover what the constructor property of a DOM node should return.

Opera and Google Maps compatibility is a victim of spec fragmentation. The DOM specifications over there are not sufficiently aware of the details in that other spec over there to cover the issue.

The funny thing is that the public-html mailing list has had loooong-winded discussions where a vocal group argued that the HTML5 spec was too comprehensive and should be split into multiple stand-alone specifications.

Looking beyond the "what I'm not interested in should not be in the spec" shoot-out, they have a point: the spec as-is might not be "reviewer-friendly" to someone who, for example, is only interested in discussing the semantics of the HTML language. ("Spec reviewers" are completely ignored in the HTML5 "priority of constituencies" design principle).

However, fragmenting the spec increases the risk of dropping another "constructor" underspecified on the floor. Google Maps basically found an omission in DOM2's ECMAScript bindings. Opera simply followed the spec and implemented the omission..

Let's do whatever it takes to make the next HTML spec comprehensive enough. To quote Jamie Zawinski: "your needs are big because the Internet is big". So fasten your seat belts, HTML5 will be huge, it'll be complex, it'll have the weird DOM bits and parser bits - and those bits are necessary to make it a really solid specification.

The holy wars of the humble alt

, , ,

Should the HTML5 specification require ALT attributes for all IMG tags? The raging debates on the public-html list seem endless. But let's see if we can get an overview..

  • Requiring ALT attributes hurts accessibility when tools or people insert empty or silly ALT attributes for significant images to pass validation.
  • Requiring ALT attributes helps accessibility when people educate themselves due to validation warnings and add useful ALT-contents, and when companies have to use ALT correctly due to legal threats.

Which effect is stronger and more valuable? This - in a nutshell - is what the ALT warriors should be discussing and researching. For example, there is some research here that indicates even low quality ALT text can be more helpful than none.

There is an incredible amount of time being spent on largely irrelevant arguments - from both sides. For example

  • Mass uploading images (e.g. Flickr) means people don't have time to write ALT texts, so Flickr can't require users to do so.

    This is just a matter of how conscientious the user is. Flickr should have an optional "description for blind people" box, users who did not fill in details would cause Flickr to output invalid HTML without ALT. So non-conscientious users create invalid HTML - to me, that sounds like a fact of life, not a spec bug.

  • Future software may be able to analyse images automatically and provide alternative text if ALT is omitted.

    Yeah, I'll believe in this intelligent software when I see it - and in particular I find it hard to believe that such hyper-intelligent software can't be configured to generate ALT-text for ALL images regardless of supplied ALT.

  • Requiring ALT means blind users can not upload images they don't know the contents of.

    Um, and uploading images you don't know the contents of is a major use case? I sort of can't see the motivation of the user for doing that.


Then there is a lot of hot air and big egos or at least claims that other people have big egos, claims that whoever disagrees with you is arrogant and doesn't listen etc.. I admit that the quality of discussion on the public-html W3C list disappoints me.

The current spec text seems pretty good. I think that in the interest of getting rid of invisible meta data and user-targeted text in hidden attributes it might also say that ALT can be omitted if aria-describedby points to some element in the page.

Now please move on to the next topic..

extending the web is hard

, , ,

The Prototype library defines a .replace() method on any element that replaces the contents of that element. The WebForms 2 spec defines a .replace attribute on INPUT type=submit that can be set to replace="values" to make a form submit not replace the entire document but simply update the form contents. You can't give two different things the same name. So if you use Prototype and call someInput.replace() your script will stop with an error in Opera because we support WebForms2 and "replace" is a property and not a method.

The wonderful flexibility of ECMAScript / JavaScript lets script authors define nearly anything and everything just about anywhere in the environment. That's why extending JavaScript is getting so complicated - anything we add to specifications and in browsers risks conflicting with something that an author already added somewhere. ES4 plans to come to the rescue with namespaces but until we get there we'll keep stumbling into problems when we try to improve the web. HTML5, you're overdue and welcome - but proceed with caution..

Suggestions for Chris Wilson

, ,

How would Chris Wilson feel if people stopped writing him open letters?

I'm nowhere near Brendan's league but here's another "Dear Chris", this time on the proposed <meta http-equiv="X-UA-Compatible" content="IE=8" /> versioning for HTML5.

First: I know you're stuck between a rock and a hard place, between thousands of web developers shouting and swearing at you for not implementing the standards better and millions of web sites that might break if you do. Moreover, knowing first-hand the problems Opera ran into when implementing WebForms 2 I don't doubt for a moment that your compatibility concerns are real.

The proposed META tag sort of shifts maintenance and backwards compatibility concerns from website authors to browser developers, which can be a good thing. However, there are problems with such wholesale version targetting:

  • Browsers will have to support an unmanageable and confusing mess of different rendering modes (and the PocketIE team will hate you for the bloat).
  • Because the META tag affects every part of the page, progressively enhancing such pages with new CSS features will be harder.


The way the web currently works is partial versioning: using JavaScript object detection, conditional comments (IE-only), CSS hacks or special keywords to "opt in to" specific layout or scripting properties. Can we build on and extend that? Enhance feature detection rather than opt-in hard-coded rendering mode?

Some examples of what that might look like..

-moz-box-sizing equivalents for opting in to specific interpretations of given CSS properties
if( 'borderRadius' in element.currentStyle )
@supports-multiple-backgrounds{ div.mosaic{ bacground: URL(bg1.png) top left no-repeat; bacground: URL(bg2.png) bottom right no-repeat } }

I'd like markup or CSS to express "if you support css3-column-layout, fetch that stylesheet, else use this XSL transformation to build a TABLE".. So, feature-based versioning built right into the standard itself instead of added as a META hack and an afterthought. Please consider making the opt-in mechanisms feature-based rather than rendering-engine-version-based!

How can you do it? Well, the IE team may have forgotten what it takes to play catch-up with a different UA implementation (you had some experience back in the NS4 days though) but Opera QA can remind you :wink:. You could apply the same skills to align the new standard and the new rendering engine with the web:

The web and the spec would benefit enourmously if your team sat down to do the detailed analysis work - hunting through the sites that break, figuring out the main problems, suggesting ways the still-in-progress HTML5 standard could change to make real compatibility possible. It's slow but you can make a public comittment and draw huge grassroot support from web developers. I bet you would get help doing evangelism and outreach for sites that serve you "error correcting" CSS you can't possibly work with in standars mode. You can release IE8 beta versions but delay the final until site compatibility problems are resolved..

We at Opera doing this right now, spending hours analysing IE quirks to figure out how to be compatible with the specs, the web, and the IEs. It's slow. It takes manhours and manyears. But it's what it takes to do it right..

Software is 100% detail. Quality is 100% attention to detail. And the detail called X-UA-Compatible should be replaced with something better. Thanks for your attention.

alignment of megaliths

, , , ...

The main point of the standards is of course to align the megaliths rendering and scripting engines of standards-compliant browsers. I've already discussed some of the problems arising when specs and implementations clash, and the dilemmas we face when we have the choice between being strictly standards-compliant and breaking some major website or breaking the spec, aligning with the other browsers, and making the site(s) work.

Never an easy decision to make!

I can now confirm a few points where Opera 9.5 is going to deviate somewhat from the specs or from our earlier implementations in order to be better aligned with other browsers. If you are a webmaster or JavaScript author please check that the changes will not cause problems for you!

We'll do the following:

  • Capturing event listeners will fire on target. This behaviour will be kept until Firefox fixes their bug. Opera's new implementation is not expected to cause problems since most sites using the addEventListener API will have been tested against Firefox. A possible exception is widget code which may expect Opera's old behaviour.
  • Implementation of capturing load event handlers changed: load events from within the document will now only be captured when the capturing event listener is attached to the document. In other words, earlier you could do
    window.addEventListener('load', func, true)
    and expect func to be called for all "load" events inside the document. From 9.5 you will have to do
    document.addEventListener('load', func, true)
    to get this capturing behaviour. (Please do not copy that code unless you know what the "true" part of it means!) This will probably become the official specification. Again, this will probably only break code specifically written for Opera such as widgets, and the change is known to fix large number of websites that use event capture by mistake.
  • We've changed the relationship between body.clientHeight and documentElement.clientHeight in standards mode. The value of body.clientHeight is now viewport height, documentElement.clientHeight is document height. This is AFAIK what Firefox does too. This change can break your website if you use browser detection before reading clientHeight from body or documentElement.


I believe Firefox will support adding capturing load events to document. There you go, alignment of megaliths!

(Like the post title? Found it on Wikipedia :smile:.)

re-invented wheels

, ,


The HTML input element already defines a type attribute so it was a matter of adding new values, and my experiments looked at doing so for number and date. This worked fine on most browsers, but the Opera browsers handling of the type and required attributes made it necessary to support datatype and needed as alternatives.


(source)
Well, that's the sort of problem you get when re-inventing wheels: you have to figure out how to fit them in next to the wheels already in place. Meet the JavaScript car mechanic:
  // partial work around Opera's WF2 implementation for type
  // same technique doesn't work for required attribute :-(

Doesn't work for "required"? Seems like the JavaScript mechanic left his "removeAttribute" tool at home.

  if (nativewf2)
  {
    fields = document.getElementsByTagName("input");

    for (i = 0; i < fields.length; ++i)
    {
      field = fields[i];
      type = field.getAttribute("type");

      if (type == "number" || type == "date")
      {
        field.setAttribute("datatype", type);
        field.setAttribute("type", "text");


Look at those final setAttribute statements: since Opera's WF2 wheels apparently aren't good enough they are dismounted and the fancy JavaScript-required-XForms-Lite-wheels fitted instead. Why can't the mechanic simply say "OK, this car already has wheels so I don't need to do any work here"?

Are the differences between XForms Lite "date" and WF2 "date" so severe?

Why would one "required" be better than the other (besides from "required" being invented there while "required" isn't, that is..)?

When specs and implementations clash

, , , ...

One of the points of having open, independently developed standards from the W3C is of course to achieve compatibility.

However, standards are not always clear and consistent, and browsers do not always get things right.

When facing a choice between being compatible with other browsers and websites OR the standard, we may have a third way: fixing the standard to align it with the common implementations and the content. That's the only way one can have the cake and eat it, be standards-compatible and compatible with the Web as it is. Is it feasible? Or even a good idea? Standards are supposed to be set-in-stone after all, to keep implementors happy so that we don't spend hours and money doing it this way only to find a rewritten standard tells us to follow that way instead..

Three real-life examples of cases where we do break or are about to break the standard:

1) getAttribute on non-existing attributes
Standard mandated returning an empty string. Other browsers returned null. Sites running into problems due to Opera's correct standards support included Yahoo mail.

We reached a general consensus that returning null is a better idea, so we have changed Opera and asked the relevant W3C group to consider changing the text in an errata or the next version.

2) Throwing WRONG_DOCUMENT_ERR on cross-document node usage
If a node created in one document is appended to another document, the standard clearly states that a WRONG_DOCUMENT_ERR should be thrown. Firefox doesn't, and sites taking the Firefox behaviour for granted and breaking in Opera included Blogger.com's rich text editor.

Opera will start to call adoptNode implicitly. I'm not sure what way the standard will go - nobody seems to intend to push for a change here. According to their bug report, Mozilla intends to fix it (which is great!) and as soon as they do and websites fix their coding errors, we can revert to spec-compatible mode. Meanwhile, we are not going to live with sites being broken in Opera due to Firefox's bugs.

3) addEventListener and firing capturing events on target
Setting a capturing "click" event listener on, say, an IMG tag has no effect, because the standard clearly says that event listeners should not fire on target. Again, Firefox gets the implementation wrong and sites where this has caused trouble include live.com (according to the Safari team, I have not seen this myself but their analysis is probably right).

Sure, we should fix the standard here and go for it - I don't see any specific benefit to not firing the event listener though I'm all ears if anyone knows why the spec is written like that. We haven't changed this yet but I guess we will follow Safari.

The lesson? To standards bodies: please care about existing implementations, experience and content when developing the standards. Specs that are seriously incompatible with prior implementations or web content cause implementation headaches, incompatibilities and suffering users.