Challenge: analyse how browsers enter US Airlines’ membership website

We recently investigated a bug report about this US Airways login form. Pressing enter to log in fails – but only in Opera. The question is why? Read on if you want to try to analyse the problem.. …

Colleague KΓ₯re dig through the layers of form validation scripts and came up with this demo of the problem in all its complexity:

<form method="post" action="#" onsubmit="javascript:return original_onsubmit();">
	<input type="text" value="Press Enter">
</form>
<script type="text/javascript">
function original_onsubmit()
	{
	if((typeof(window.event) != "undefined") && (window.event != null))
		{
		window.event.returnValue = true;
		}
	return true;
	}

var f = document.forms[0];
var userName = document.getElementsByTagName('input')[0];
userName.focus();

if(document.addEventListener)
	{
	f.addEventListener('submit',foobar,false);
	userName.addEventListener('keypress',loginkeypress,false);
	}
else if(document.attachEvent)
	{
	f.attachEvent('submit',foobar);
	userName.attachEvent("onkeypress",loginkeypress);
	}

function loginkeypress(e)
	{
	e = e?e:window.event;
	if(e != null && e.keyCode == 13)
		{
		if(e.preventDefault)
			{
			e.preventDefault();
			}
		else if(window.event)
			{
			e.returnValue = false;
			}
		document.location = 'javascript:submitform()';
		return false;
		}
	}

function foobar()
	{
	alert('FAIL');
	}

function submitform()
	{
	if(f.onsubmit() != false)
		{
		f.submit();
		}
	}
</script>

Among the main four browser engines, Opera's is the only one to call foobar(). Can you tell why, and propose a fix?

If you need to see the code running, it's here:
CORE-32417.htm

Discussion open in the comments. I have an analysis and a list of 5 different ways we might fix it, which I'll post later – for now it will be interesting to see your proposals πŸ™‚

Advertisements

35 thoughts on “Challenge: analyse how browsers enter US Airlines’ membership website

  1. I'm guessing the window.event.returnValue = true; causes foobar to run, but I don't know why it wouldn't do the same in IE – something to do with attachEvent behaving differently than addEventListener?

  2. I guess it has to do with the order in which the event listeners are added and then executed by the browser. My guess is opera runs through the events in the order they were added (so first foobar, then loginkeypress) and the other guys do it in some other way (following the DOM structure? reverse order?)PS: if I am right do I get a new t-shirt? my old opera shirt (from the christmas special 2008) got a hole recently 😦

  3. Originally posted by lucideer:

    I'm guessing the window.event.returnValue = true; causes foobar to run

    You're on to something :)Originally posted by serious:

    if I am right do I get a new t-shirt?

    Good idea, I'll see whether I can arrange something for the first person to post a complete explanation πŸ˜‰

  4. The f.onsubmit() call (in submitform) seems to trigger the submit event of the form (and thus calls foobar) which it probably shouldn't.When the user presses enter the submitform method gets called, this calls the onsubmit method of the form, which probably should only be the callback using the onsubmit HTML attribute, but in Opera this seems to trigger the submit event, and thus also calls foobar.Edit:But this doesn't explain why commenting out the window.event.returnValue line makes it work, nor why f.onsubmit gives an anonymous function which only contains "return original_onsubmit();"

  5. Eh…don't know enough about JS, but the first thing I'd say is that their line order is awful. So I think I've grasped window.event, and also original_onsubmit. I really despise the way foobar is getting called. Though perhaps it's more miraculous that this works in the other browsers.If a dirty hack like commenting out window.event.returnvalue works, then great! Otherwise, move foobar to the bottom and alter its call. I hope this makes sense, like I said JS is only something I've dickered with.

  6. funny thing is when you add alert(window.event) before "if" it will appear two times and will return :[object KeyEvent] and [object MouseEvent] and i don't know whyfunction original_onsubmit() { alert(window.event); if((typeof(window.event) != "undefined") && (window.event != null)) { window.event.returnValue = true; } return true; }In firefox line window.event.returnValue = true; isnt executed in my opinion troublemaker is:if((typeof(window.event) != "undefined") && (window.event != null))P.S.Which tool do you use to debug js? Is there any official website or forum to support dragonfly? While there is no good (or popular)developer tools for opera there always will be problem like this one.

  7. Anonymous writes:"Which tool do you use to debug js? Is there any official website or forum to support dragonfly? While there is no good (or popular)developer tools for opera there always will be problem like this one."||this is the question I ask to myself again and again each time article here is posted (they are great! keep them comming!) and at the same time NOTHING is happening with dragonfly.||easiest way of debugging opera is using firebug.. and then porting this to opera.||unfortunatelly, most developers will stop at 'using firebug' and never ever run opera again.

  8. Anonymous writes:there is a forum (you can find a link on the my.opera.com/dragonfly – right column, bottom). but this forum is dead/dying and there is no activity worth mentioning. as for the progress.. dragonfly is 'being worked on' for 3 years now? and it still is a POS that cant properly debug JS, cant profile JS (how many times given methods are run), cant profile network and rendering.. using it to fix problems like this one is a no-go. it requires 10x times more effort than using firebug and forgetting about opera. and given that 10x effort costs 10x more time and that costs 10x money.. well.. then no wonder why companies do not pay for fixing bugs in opera.

  9. Anonim # 15. September 2010dragonfly is everyday better(i use it time to time since 2009) but if there is no forum about it.. no support.. how do dragonfly developer could possibly know what is wrong witch it.. and there are some bugs.

  10. Anonymous writes:yes, pretty everybody knows about bitbucket, and pretty everybody can read the commit list – 8 changes (most irrelevant) in last week. this means this project is of no importance to opera currently. http://bitbucket.org/scope/dragonfly-stp-1/changesets – 2 programmers, both obviously doing this as a part time job, and doing mostly nothing important. ||oh and the twitter.. had hard time finding anything relevant to dragonfly at all in that babble.

  11. Opera is evaluating

    document.location = 'javascript:submitform()';

    synchronously while it should not. It should schedule a new thread when the current ends. If that line is replaced with

    setTimeout(submitform,1);

    Then the tc behaves the same in Opera and the other browsers.party pooper :p

  12. Sir… YOU ARE AWESOME πŸ˜€ Could you tell how did you do debugging please?P.S. That is unfair.. i was thinking that js is issue not a opera engine

  13. Well if it evaluates differently it's due to an engine difference. Whether the behavior is proper is another matter. So Opera's failing in this case because it's too fast? The script doesn't set an explicit timing chain, so Opera just played loose and missed the turnoff?

  14. Good efforts all (though the Dragonfly comments are somewhat off-topic – general comments about Dragonfly can be posted on the Opera Dragonfly blog.)We're close to nailing it – who is first to explain why calling submitform() immediately causes the foobar function to run? πŸ™‚ And if JoΓ£o or others explain how they did their debugging I'm sure we can all learn something from each other.

  15. Originally posted by lucideer:

    If you want to see progress, you can download and try out the snapshots.

    That's not going to get you much in the way of progress on most days. Dragonfly is bound by core functionality. So scope updates are coupled with core updates and are few and far between.

  16. Originally posted by fearphage:

    That's not going to get you much in the way of progress on most days. Dragonfly is bound by core functionality. So scope updates are coupled with core updates and are few and far between.

    True enough, but I'm using the latest bitbucket snapshot now and it's at least a minor improvement over the served one (though that could be due to bugs, I'm not sure).Originally posted by hallvors:

    why calling submitform() immediately causes the foobar function to run

    Opera is the only one that calls @onsubmit twice – once on f.onsubmit() (where foobar is not run as far as I can see) and again on f.submit() (this time foobar runs). Other browsers don't run @onsubmit when f.submit() is called, which makes sense because the submit event is preventable, but f.onsubmit() evaluates the attribute directly. But this still doesn't explain why IE doesn't run the submit event – it seems to be setting window.event.returnValue to true just as Opera is…Which is where I'm still getting stuck. I think I know why Opera does, just not why IE doesn't.

  17. Originally posted by lucideer:

    But this still doesn't explain why IE doesn't run the submit event

    As far as i know, there is no "submit" event in IE. There is "onsubmit" though, so

    f.attachEvent('submit',foobar);

    probably does nothing in IE

  18. Originally posted by Methodius:

    probably does nothing in IE

    Well spotted indeed – this may be a bug in the demo, not sure if the site makes this mistake πŸ˜‰

  19. Anonymous writes:OK, so the above test may be deleted. Hoping quotes get through.<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><html><head> <title>US Airways login demo</title></head><body> <form method="post" action="#" onsubmit="return test();"> <input type="text" value="Press Enter"> </form> <input type="checkbox" id="preventdefault" checked="checked"/> Call e.preventDefault();<br/> <input type="checkbox" id="returnvalue" checked="checked"/> Set e.returnValue to true<br/> <script type="text/javascript"> function test() { // seems to act the same as the foorbar failure, // but can be shown now because the onsubmit-call has been deleted. alert("ADDED FAILURE MODE"); return true; } var f = document.forms[0]; var userName = document.getElementsByTagName('input')[0]; userName.focus(); f.addEventListener('submit',foobar,false); userName.addEventListener('keypress',loginkeypress,false); function loginkeypress(e) { if (document.getElementById("preventdefault").checked === true) { e.preventDefault(); } document.location = 'javascript:submitform()'; //return false; } function foobar() { alert('FAIL'); } function submitform() { if (document.getElementById("returnvalue").checked === true) { window.event.returnValue = true; } f.submit(); } </script></body></html>

  20. Anonymous writes:For those of you interested, a more reduced test-case solely for Opera.It contains two nice checkboxes for you to check out, and an extra failure warning to enjoy. Call e.preventDefault(); Set e.returnValue to true

  21. Reinaut writes:Analysis of code effect for Opera only:The form.submit() call is a red herring. Comment it out and try it!Also the document location changes can be replaced with a direct (synchronous) call.I believe the default action of the enter-key gets through. The e.preventDefault() normally prevents the default action from happening, but Opera (by supporting the IE-model) has also implemented event.returnValue. It seems the latter of the two wins.In effect, if an event's default action is prevented by calling e.preventDefault, it can be reactivated by setting its returnValue to true.Nice examples are (activates default action):window.event.returnValue = true;e.preventDefault();window.event.returnValue = window.event.returnValue;or even better:window.event.returnValue = window.event.returnValue;This last one deactivates an event due to undefined being the default value, but only taking effect after assignment.

  22. Anonymous writes:if you arent logged in – you cannot|| if opera indeed is ignoring preventDefault in certain scenarios, this one bug (immediate core fix please!!) can be responsible for a LOT of mess around the web. || im still waiting for a story of how you guys did debug this scenario. used firebug?

  23. Congrats to Reinhaut, the first person to describe the last piece of the puzzle: the weird interaction between preventDefault() and event.returnValue being set to true. I'll write up my analysis in a new blog post shortly πŸ˜‰

  24. Originally posted by Reinaut:

    For me, the tools used are 'source' and 'apply changes'. That's it.

    +1This is a reduced testcase, so an advanced debugging tool wasn't really necessary – it's fairly simple to see even by just looking at the code what's happening – the trick is how that's handled differently in different browsers, for which a little bit of code-editing here and there works wonders.

  25. Apply Changes is the best feature. You can put your face and name into a screenshot of the New York Times. πŸ˜‰ Or do just about anything, anywhere else. I use screenshots from Source view when emailing sites about broken features.

  26. Originally posted by smqzbq:

    or what myopera bug

    Reinaut doesn't have a myopera account – that's how commenters names appear when they don't have an account. He's posted twice.

  27. Sorry for my repeated questions but i don't see any comment submitted by "Reinaut". The first appearance of "Reinaut" is here :Anonim # 17. September 2010, 03:46Reinaut writes: Analysis of code effe…..I suppose i don't see one comment? or what myopera bug ??

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s