Skip navigation.

miscoded

the web is a hack

Posts tagged with "javascript"

liveclipboard

, , , ...


liveclipboard is an interesting idea from Ray Ozzie. He's also blogged the process and brainstorming behind it. This is great..

Unfortunately it doesn't work in Opera.

The reason appears to be a bug in FireFox regarding how it evaluates XPath expressions. The document.evaluate spec states that the context node must belong to the same document as the method is called on. (The style is somewhat convoluted, I'm not 100% sure I've understood the phrase If the XPathEvaluator was obtained by casting the Document correctly but I can't think of any other reading that makes sense).

So, if you call document.evaluate( expression, someOtherDocument ...), Opera follows the spec to the t and throws an exception while FireFox doesn't. The liveclipboard script relies on this FireFox bug.

The fix is simple: import the nodes to the current document before XPathing them. For example:

hCardXmlNode = domParser.parseFromString(hCardXmlString, 'application/xml');


should be

hCardXmlNode = document.importNode(domParser.parseFromString(hCardXmlString, 'application/xml').firstChild, true);


One of these cases where testing in multiple browsers will highlight your assumptions about web standards.

my booking form is a secret

, , , ...

thomsonfly.com contains a hidden booking form. They don't seem to like bookings.

The reason? The booking form is within a table that is styled to be hidden:

<table class="fullwidth" id="hometable" style="clear: both; visibility:hidden;">


Another part of the code is hidden from non-IE browsers with conditional comments:

<!--[if IE ]>
<div id="loadMessage" style="position: absolute; z-index: 2; top:180px; background: url(/img/elements/anim_please_wait.gif) no-repeat center; width: 100%; text-align: center; height: 17px;" ></div>
<![endif]-->


..and there is some scripting that will remove the "loading" screen and show the search form if UA is IE. Naturally since the "loading" message is hidden with conditional comments, this:

(document.getElementById("loadMessage")).style.display = "none";


fails and stops the script before the table is un-hidden. Also obviously, they don't expect any booking visitors with JavaScript disabled, since then the form would simply never appear.

"Thomsonfly - the low fares airline that goes further to confuse you."

old bug, new patch

, ,

Sadly, ZDNet has not yet fixed the very stupid, little issue I pointed out to them nearly two years ago - so now I'm about to give them a small dosis of medicine in the form of a browser.js patch saying

if( location.href.indexOf('zdnet.com.com')>-1 ){
// Bug 146580, redirects video requests to missing files if it sees "Opera"
navigator.userAgent=navigator.userAgent.replace(/Opera/, 'MSIE 6.0');
}


Short and sweet, and doesn't even ruin Opera's position in their server stats :-)

JSTidy

, ,

Tarquin's clever idea is fast becoming one of my favourite tools against the very popular all-on-one-line libraries, not to mention the sort of scrambled code Google is blessing us with:

http://www.howtocreate.co.uk/tutorials/jsexamples/JSTidy.html

Thanks :smile:

Dell goes for the quirks

, , , ...

This page should have a Flash in it. Now Opera, where is it?

Well, here's a pretty little function from Dell, meant to return an element with a specific name:

function ParseDivObjects( targetName )
{
var objs = document.getElementsByName( targetName );

//-- Workaround for "inconsistent" W3C ruleset in IE as DIV's aren't mapped with name properties
if( objs.length == 0 )
{
var targets = document.getElementsByTagName( "DIV" );
var tmpObj;

objs = new Array();

for( var targetidx = 0; targetidx < targets.length; targetidx++ )
{
tmpObj = targets[targetidx];
if( tmpObj.name == targetName )
{
objs.push( tmpObj );
}
}
}
return objs;
}


Let's start: document.getElementsByName is not supposed to be used for elements that are not supposed to have a "name" attribute. So, for example you can use getElementsByName with INPUT elements but not with DIV. Except that Mozilla apparently disagrees with that interpretation of the specification and thinks IE's behaviour is "a quirk". Really?

Anyway, Dell has a workaround for IE: they go through all DIVs in the page and check tmpObj.name, which means Opera is out of luck again. Since DIVs are not meant to have a "name" attribute we don't create any .name property for it. Using getAttribute here would make it work.

So Dell crams two different quirks into one function, and Opera fails because it supports neither. Time to violate the DOM spec a little more.. :frown:

GMail's while(1) demystified

, , , ...

For a long time I've been wondering why GMail tends to add
while(1);
to the top of their scripts when they send for example contact lists or E-mail texts embedded in JavaScript. Typically these scripts are requested with XMLHttpRequest and the first line is removed before the rest of the script is sent to eval(). If they didn't remove the while(1) it would of course create a never-ending loop, hang the page and perhaps even the browser. So why do they add it in the first place?

Today the penny dropped: it's a subtle security feature. If I on my evil home page added a script and set the source to a suitable GMail URL I might manage to make GMail send ME your contact list. However, if I manage I won't actually get to the data, I will simply hang your browser in the while loop.

Clever. But I wonder how much security it actually adds..?

Google maps and event transparency

, , , ...

If you use Google Maps with Opera 9 betas you have probably noticed that the top left navigation does virtually nothing. Only the slider works at the moment.

Technically, they use an empty element that is styled to cover the graphic to catch mouse events and call the navigation actions. (Don't ask me why it is coded like that, and why for example the graphic isn't the background of the DIV so that this problem doesn't arise).

This not working in Opera is caused by our experimental support for event transparency.

At first sight I thought I had missed something in IE's implementation that would make Google Maps work. However, none of my tests could identify the missing piece of that puzzle - and it turns out what they actually do is to set a background colour on the empty element and then make it invisible again by setting an opacity filter!

Now, there is no natural link between event transparency and opacity. If a UA implements the former but not the latter, our Google Mappers would have to look for another workaround. It is pure luck that Opera happens to add support for both at the same time, so Google will fix this by using the IE workaround for Opera too.

This issue shows how important it is to standardise a way to say an event should fire on invisible elements. I think addEventListener should be extended with a fourth argument that controls this.

As an aside, to avoid browser sniffing you can use this code to detect support for CSS3 opacity in UAs that support the DOM standard's getComputedStyle:

var el=document.createElement('div');
el.style.opacity='.5';
var opacitySupported=(getComputedStyle( el, 'opacity').opacity)?true:false;

key events

, , , ...

Of course most JavaScript authors use key events in rather simple ways. It may be news to you that

  1. key events are not standardised
  2. there are serious incompatibilities between browsers
  3. localization of many key events is impossible
  4. big, important sites mess things up


Hm, that sounds like a summary of JavaScript in general. :frown:

One thing at a time.. Is it non-standard to use key events? Yes. Well, the stuff that is in general use isn't standardised. The W3C DOM 3 Events working group note says nothing about popular bits like onkeypress, event.keyCode and event.which, instead it standardises stuff like textInput, keyIdentifier and keyLocation. This isn't implemented anywhere as far as I know.

Regarding browser incompatibilities, IE does not send keypress events for function keys while Opera and FireFox do, in FireFox event.keyCode is always 0 in keypress events and most authors do dodgy hacks to read event.which instead, Opera does its own thing for punctuation character keyCodes for no particular reason. Also Opera does not let you cancel Backspace presses, while FireFox doesn't allow cancelling Delete.

On localization, keys move around when you change from, say a US keyboard to a Norwegian one. Any letters that require a Shift modifier in one layout but not in the other can not be reliably detected in onkeydown/onkeyup handlers. This means keys like < > . : ; , + - / \ - you can not tell the user to press them and detect them in a keydown or keyup handler, because the keyCode value will be different on a different keyboard.

More on l10n: If you use an Input Method Editor (IME) the input will bypass key events entirely in Opera, send keydown+keyup in IE and keydown+keypress in FireFox. With an IME event, keyCode for keydown events is always 229 no matter what letter you press in both UAs while IE gets the keyCode right on keyup. (Tested with MS Japanese IME 8.1).

Also, be aware that some locales use [AltGr] to type characters, and from JavaScript this will set event.ctrlKey so if you detect the S key and the [Ctrl] key for your editor's "save" command you're wrong and all Poles will hate you unless they use a browser that hacks around that issue. This is a problem on important, major sites.

I've made a small table just to get a better overview of the popular event object properties. The simplest conclusion is that this isn't as tidy as it should be..

So, how should we turn this mess into a standard that is compatible with existing content?

  • event order is keydown, keypress, keyup
  • event.keyCode, event.which and event.charCode - the former two are commonly used with pseudo-browser-sniffing, so we can't just remove either. I haven't noticed event.charCode used anywhere but it is nevertheless a nice idea to be clearer about the key ID/character code distinction. It would be nice if event.charCode could be used in keydown/keyup handlers to detect the localized character value, getting around the problem with different keyboard locales.
  • function keys should not send onkeypress or input events
  • I'm undecided on whether the UA or the site should work around the AltGr-sets-Ctrl issue
  • setting keyCode/charCode in a keypress must change the keys that get input. UA must do this in a way that does not allow websites to control for example paste actions.
  • cancelling a keydown event must prevents keypress and default action for all keys (but not keyup)
  • cancelling a keypress event prevents input and default action
  • the keypress/input event must be able to handle IME input. The IME won't necessarily send one character at a time so we should have an event.data property giving the full text
  • I don't think it's useful to send key events while the IME is handling the input. Do you really want to know that the user pressed a key with the keyCode 65 when they aren't typing an A at all? It would make more sense to me to send a keypress/input event when the user accepts the IME suggestion.


That's enough keys for the moment. Now I'm going to shortcut back to enter home.
No, not the keys. I meant I'll escape. Break. Shift my location.

Darn, I don't get away from thinking of keys now. Must be F8.