Closed Bug 127903 Opened 22 years ago Closed 13 years ago

<a> link tags intercept events meant for form submit buttons

Categories

(Core :: DOM: UI Events & Focus Handling, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla2.0b9

People

(Reporter: gav, Assigned: bzbarsky)

References

(Blocks 3 open bugs)

Details

Attachments

(5 files)

From Bugzilla Helper:
User-Agent: Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.8+) Gecko/20020226
BuildID:    2002022603

[spun off from the evangelism bug 115530 : the site was "fixed", but there may
be an actual bug in mozilla, too]

If a submit button is enclosed in an <a> tag, e.g.:

<form action="http://www.mozilla.org">
<a href="http://www.mozillazine.org">
<input type="submit" value="Click here; should take you to mozilla, not
mozillazine">
</a>
</form>

The submit button never receives the event.  Testcase to follow.

Reproducible: Always
Steps to Reproduce:
1. load testcase
2. click button

Actual Results:  Goes to mozillazine

Expected Results:  should go to www.mozilla.org

[I'm paraphrasing comments from bzbarsky in the original bug 115530.  cc'ing
Boris so he can correct me if I've got the wrong end of the stick]
Attached file bzbarsky's testcase
This happens on Linux too.
OS: Windows 98 → All
Hardware: PC → All
Depends on bug #124990 ??
Depends on: 124990
QA Contact: madhur → rakeshmishra
I'm hitting this on a few evangelism bugs, annoying :)
*** Bug 171601 has been marked as a duplicate of this bug. ***
*** Bug 58879 has been marked as a duplicate of this bug. ***
*** Bug 180038 has been marked as a duplicate of this bug. ***
QA Contact: rakeshmishra → trix
*** Bug 183983 has been marked as a duplicate of this bug. ***
Depends on: 185758
*** Bug 187902 has been marked as a duplicate of this bug. ***
Blocks: 188234
*** Bug 191902 has been marked as a duplicate of this bug. ***
Depends on: 197754
Blocks: 201418
No longer blocks: 201418
*** Bug 201418 has been marked as a duplicate of this bug. ***
Since bug 201418 got marked as a dupe of this bug, I recommend changing the
summary to reflect both bugs, as this bug now deals with <a> tags intercepting
events meant for inner <a>'s as as well as inner form controls. Recommend
summary is:
  <a> tags intercept events meant for inner elements

See bug 201408 for details for how this affects inner <a>'s in XHTML 1.
Blocks: 213306
*** Bug 213306 has been marked as a duplicate of this bug. ***
More thorough testcase.

Note that Opera and Safari have the same behavior as us, IE and Netscape 4.x differ.
.
Assignee: joki → saari
QA Contact: trix → ian
Blocks: 229925
Blocks: 197754
No longer depends on: 197754
*** Bug 233770 has been marked as a duplicate of this bug. ***
(In reply to comment #14)
> More thorough testcase.
> 
> Note that Opera and Safari have the same behavior as us, IE and Netscape 4.x
differ.

Opera 7.23 and Konqueror 3.1 (on redhat 9) both now work on Boris' testcase,
i.e. they take me to mozilla.org and NOT to mozillazine.org as does lynx
2.8.5dev.7 (on redhat 9) which shows mozillazine.org as a hidden link
Blocks: 110817
Attached file mkaply's testcase
That's not a testcase for this bug, Michael.  Our behavior there is correct,
since events bubble.
(In reply to comment #19)
> That's not a testcase for this bug, Michael.  Our behavior there is correct,
> since events bubble.

But since there is a different behavior in IE and 4.x, shouldn't quirks mode be
preventing the bubbling for form elements?
Only if this is breaking a significant number of sites.  quirks is about compat
when it matters, not compat in all cases.
Note to self:

The way to do this, per conversation with bryner, is to trigger the default
action during the bubbling stage in the system event group, before passing the
event up to the parent.
Blocks: 272900
Blocks: 218093
Attached patch Partial attemptSplinter Review
This doesn't work yet.	Form controls don't cancel events when they trigger
form submission, and the hack for <area> has to be left in because <area>s may
not be descendants of the <a>.

Further, status bar showing of links is broken with this patch; I'm not sure
why, and I don't really have time for the foreseeable future to deal with the
mess that is nsHTMLInputElement::HandleDOMEvent and
nsGenericHTMLElement::HandleDOMEventForAnchors
*** Bug 288327 has been marked as a duplicate of this bug. ***
Blocks: 62151
*** Bug 294379 has been marked as a duplicate of this bug. ***
Blocks: 297558
Blocks: 325652
Blocks: 329434
Blocks: 266958
(In reply to comment #23)
>the hack for <area> has to be left in because <area>s may not be descendants of the <a>.
Um... how is that relevant? Any click on an area should at some point run
nsHTMLAreaElement::HandleDOMEvent, I mean PostHandleEvent, which thus marking
the event as having been handled so that other link handlers ignore it, no?
I'm not sure what I meant by that comment, but what happens if you have:

  <a href="something"><img usemap="#map"></a>
  <map name="map">
    <area href="something else">
  </map>

And click the imagemap?  What events are fired and to what DOM nodes?
If memory serves me right, it targets the area element and bubbles up.
This really annoys people trying to save mapped images because the
context menu code has no idea which image was actually right-clicked on.
Ah, then comment 23 is confused.  ;)
Assignee: saari → events
What needs to be guarded against is links that are a parent of the <area>, not the <img>. So

  <img usemap="#map">
  <a href="something">
    <map name="map">
      <area href="something else">
    </map>
  </a>

Remove that check, and you'll currently go to _something_. The first testcase in bug 331959 has a check for this.
No longer blocks: 197754
Depends on: 331959
No longer blocks: 297558
So why, as a matter of course, do we not preventDefault() whenever we've carried out (or would carry out, barring errors) a default action? I've been looking at the code for a while and I haven't yet seen a good reason. Is it simply because people haven't been sure, so it's just become the norm not to?

Boris, I don't agree with comment 19. Sure events bubble, but that doesn't mean we should perform multiple default actions the root-most of which takes precedence (and may cancel out all the others). I really think we should perform one default action, and one default action only for each event. (At least if we don't, exceptions should be well reasoned and documented.) I also think the default action that should take precedence is the *leaf*-most one. I don't think it's useful or desirable to have clicks on those form elements activate their ancestor link. If there's text nested in the link along with the textbox the text should be a link, sure. But IMHO the textbox should stand above it.

I guess I may be in the minority. Opera disagrees with me, and IE seems confused (mouseover shows the link, but it doesn't act on it when the form controls are clicked).

Thoughts? Flames? :)
> whenever we've carried out (or would carry out, barring errors) a default
> action? 

What sort of default action?  For example, hovering a link has as "default action" changing the pointer.  Should that prevent other default actions (eg changing the status bar)?

That's a kinda silly example because the pointer is not changed off a DOM event.  But there are other cases like this too...

Maybe we _can_ get away with preventing default in all these cases; testing would need to happen to tell.

As far as comment 19 goes, you may well be right.... But that does raise compat questions too.  :(
(In reply to comment #32)
> What sort of default action?  For example, hovering a link has as "default
> action" changing the pointer.  Should that prevent other default actions (eg
> changing the status bar)?

What I mean is that when one PostHandleEvent performs actions for an element as a result of an event, none of the remaining PostHandleEvent calls on the element's ancestors should do anything. I'd argue that the PostHandleEvent call on the link should be triggering both the pointer change and the status bar change. To me, collectively all the actions (plural) carried out for a single element as a result of a particular event are its "default action" (singular) for that event.

I can't think of or see a situation where we want multiple elements in the event chain to perform default actions as a result of a single event as it bubbles up. That certainly doesn't mean there aren't any. I'm hoping if there are that other people will point them out.

> Maybe we _can_ get away with preventing default in all these cases; testing
> would need to happen to tell.

Not without "fixing" mkaply's testcase. I think that's what we should do, but as you say it does raise the compatibility question. I don't think too many people should be relying on those links being activated though since IE doesn't trigger them like we do.
All the default actions should trigger, IMHO.
Ian, that's clearly not a desirable result when anchors are nested inside each other or buttons nested inside anchors.  And possibly not if anchors are nested inside buttons (not sure about that).
I don't see any other sane solution.

The UA might not know about all the default actions (e.g. bindings might add new default actions). The default actions might not be mutually exclusive (e.g. two nested links targetting different iframes). If we don't do this we end up having to make all kind of hacky UI fixups, e.g. disabling the default action of a mouse hovering over a link when we think we'll disable the default action of that link should it be clicked.

Firing all the default actions is what is likely to be required by DOM3 Events, based on what I understood from talking to Safari devs.

All the cases you list are non-compliant markup in the first place. What IE does is completely inconsistent and hacky.
So essentially you think it's not acceptable for part of a default action to be to call preventDefault() on the event?
Okay, I'm a bit torn on this one. There are clearly merits and issues with either stance. I'm not going to work on this any further right now, but here's a patch for <button> to make sure it doesn't trigger ancestor links. It works by preventDefaulting all events that pass through the button that would trigger a link. This works for all buttons, but it would be fairly easy to get working just for submit buttons by wrapping the nsEventStatus_eConsumeNoDefault bits in an |if (mType == NS_FORM_BUTTON_SUBMIT)|.
> All the cases you list are non-compliant markup in the first place.

Please explain to me why the following snippets of XHTML are non-compliant:

  <a href="..."><input type="submit"/></a>
  <a href="..."><button/></a>
  <a href="...."><img usemap="#whatever"/></a>

I agree that per the DTD <button> may not contain <a> or other buttons or inputs and <a> may not contain <a>.  Nevertheless, it is possible to produce DOMs in which it does, both via our parser and via the DOM.  And pages depend on particular behavior of such DOMs.

> What IE does is completely inconsistent and hacky.

And pages depend on at least part of its behavior...
If someone can put forward an implementable, detailed proposal for what we should do that is compatible with IE, that we can put in a spec, then ok. So far all I've seen is proposals to have undocumented heuristics.

I agree that in HTML4 the three cases you give are indeed compliant, though of course the spec doesn't define how they should work. They won't be compliant in HTML5, but HTML5 _will_ say what should happen. I'd love for that to be compliant with IE and good UI at the same time. At the moment, the only sane proposal I've seen is that if an event collects more than one default action, then it must trigger all those default actions.
IE's behavior for the "button inside anchor" case is very straightforward.  The default action of a button (even an <input type="button">) is to call preventDefault on the event.

Same thing for <area>, as evidenced by the numerous web sites that use it.

So we could define the spec as you wish, and then we're still left deciding which default actions should call preventDefault (which is a perfectly legal thing to do per the spec, as far as I can tell).  And we'll have to have _some_ of our default actions doing so to avoid breaking web sites.
*** Bug 334323 has been marked as a duplicate of this bug. ***
Summary: <a> tags intercept events meant for form submit buttons → <a> link tags intercept events meant for form submit buttons
This is enough of a web compat issue that we should really fix it...
Flags: blocking1.9?
I could be convinced that this should be a blocker if someone feels strongly about it. Would be great if we got this specced and fixed either way.

Smaug, I believe you have had this in mind for some time?
Assignee: events → Olli.Pettay
Flags: blocking1.9? → blocking1.9-
Whiteboard: [wanted-1.9]
Given these two sections:
   http://www.whatwg.org/specs/web-apps/current-work/#interactive2
   http://www.whatwg.org/specs/web-apps/current-work/#image
...I think this is actually relatively well defined now. Maybe. Please let me know if I forgot anything.
So that's basically separating out the idea of activation behavior from the idea of default action, right?
When should we dispatch "submit" or "reset" (which I couldn't find in
WHATWG specs)? When handling DOMActivate in <input type="submit">?
So the events would be click->DOMActivate->submit,
or in some cases keypress->click->DOMActivate->submit

And similar question about change event.
(With change there is also the backwards compatibility issue: 
http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/content/html/content/src/nsHTMLInputElement.cpp&rev=1.455&mark=1493-1499#1481 )
Found where the change event handling is defined
http://www.whatwg.org/specs/web-forms/current-work/#the-click
(It is too difficult to find anything in the whatwg specs, since
those are so huge, IMO)
bz: Basically, yeah. The default action for DOMActivate becomes a generic one that just looks at all the affected elements and picks the right one to "run".

smaug: The forms aren't well defined by the WHATWG specs yet, but yes, sending the 'submit' or 'reset' event would be the activation behaviour. 'change' is harder because it isn't triggered by activation.

(I don't think making many smaller specs would make it any easier, by the way.)
Not sure if this is really needed for 1.9. The behavior isn't still defined anywhere, as far as I see.
This breaks websites, though.  That's why we'd like to fix it, whether things are officially defined or not.  That said, note that this is wanted, not blocker.
Hmm, so the default action for click would be to dispatch DOMActivate, but that would lead to several DOMActivate events if "interactive" elements are nested. 
(though, there is a comment: "Most interactive elements have content models that disallow nesting interactive elements.")
Hixie, or anyone, any suggestions what to do here?

Could we take jwatt's patch if support for <input type="button/submit/reset"> is added?
And btw, What should happen when the markup is
<a href="www.helsinki.fi"><input type="text"></a> (bug 59292)? 
If they are nested the first element in reverse tree order that has activation behavior is activated. This is defined at:

  http://www.whatwg.org/specs/web-apps/current-work/#interactive1

I believe Mozilla currently activates the last element to which the event bubbles through.
(In reply to comment #53)
> If they are nested the first element in reverse tree order that has activation
> behavior is activated.

Yes, activation behavior is defined, but activation behavior happens
after DOMActivate dispatch. If the default action is to
dispatch DOMActivate and all default actions should be fired, there
are possibly several DOMActivate events.

Say you have:

  <a><input type=submit></a>

and you click on the <input> only a single DOMActive event will be dispatched. It will trigger the activation behavior of the submit button and not that of the link surrounding it. I'm not in what scenario multiple events would be dispatched.
> only a single DOMActive event will be dispatched.

Why?  Both nodes in question have firing a DOMActivate event as default action, so there should be two DOMActivate events, targeted at the two nodes.  Since they bubble, the <a> will see both.
(In reply to comment #56)
>Both nodes in question have firing a DOMActivate event as default action
PMFJI and I haven't even looked at the code but I don't suppose by any chance that the nodes that fire DOMActivate events on a click consume the click?
(In reply to comment #55)
> I'm not in what scenario multiple events would be
> dispatched.
> 

"The default action of this click event ... must be to fire a further
DOMActivate event at the same element"
So where does that say that only one DOMActivate event is dispatched.
I understand that is probably how it should be, but html5 isn't 
as clear as it should be, IMO.

Hmm, also, I assume html5 tries to say that DOMActivate is dispatched
to some "interactive" element, even if click is dispatched to some 
other element. <a>hello,<span> click me</span>!</a>.


I would expect DOMActivate to basically dispatch as the default action of a click event. (Which seems to be what HTML5 says.) I'm not sure how it suggests that multiple events are to be dispatched.

Boris, why? There's only a single event target here which would get the event dispatched.
click event isn't necessarily dispatched to "interactive" element
(<a>hello,<span> click me</span>!</a>).
So how does "interactive" element know whether or not to dispatch DOMActivate?
As I said, just dispatch DOMActivate as default action of the click event (regardlress of "interactive"). Then for the first element in reverse tree order with activation behavior you trigger that behavior.
As the first default action, yes, but what about other default actions
which come later in the reverse tree order?
They are not the first, so they are not to be triggered.
According to what? :)
According to the HTML 5 draft which is based on reverse engineering Internet Explorer. It states when activation behavior is to be triggered. It doesn't say it should be triggered for the scenario you brought up.
Flags: wanted1.9+
Whiteboard: [wanted-1.9]
During test for Bug 384364(double HTTP GET by Fx 3 & Fx trunk), I met funny phenomena.

(A) Submit button in Link, placed in Form. onSubmit issues alert(). 
> <form action="http:URL-1" onSubmit="alert();"><a href="http:URL-2"><input type="submit"></a></form>
(test result with Fx trunk)
  1. alert() by onSubmit. Keep dialog open.
  2. URL-2 in <a href> is loaded
  3. OK to alert dialog => URL-1 in <form action> is loaded
     => Problem of Bug 127903 don't occur
  NSPR log says:
     1. Single HTTP GET to www.mozilla.org
     2. 200 response
        => Problem of Bug 362539 don't occur
     3. Single HTTP GET to www.mozillazine.org
     4. 200 response
Note: If onSubmit="alert();" is removed, double HTTP GET occurs on URL-2 in <a href>, and URL-1 in <form action> is not loaded. In this case, HTTP GET to URL-1 in <form action> is seen before HTTP GET request to URL-2 in <a href>.
See Bug 384364 Comment #5, attached test case, and attached NSPR log, please.
 
(B) If onClick handler of outer DIV returns false, action of Link / Submit
    was not executed. IE7 executed action of inner element.
><div onClick="return false;">
> <form action="http:URL-1"><a href="http:URL-2"><input type="submit"></a></form>
></div>
See test case attached to Bug 384364 by Bug 384364 Comment #5.
(attachment 331891 [details])

Bothe (A) and (B) are by design?
I updated test case for Bug 384364. (attachment id=332071)
This page contains test cases with <form><a><input type=submit></a></form>.

In following case, both action="mailto:" and href="http: URI" were executed with Fx 3.0.1 and Fx trunk.
> <form action="mailto:"><a href="http URI"><input type="submit"></a></form>
With Fx 2.0.0.14, action="mailto:" was not executed.
So original problem of "<a> link tags intercept events meant for form submit buttons" itself is already WORKSFORME.

When next case, funny phenomenon was observed, because of Bug 384364.
> <form action="http: of different URL, already in cache"><a href="#top"><input type="submit"></a></form>
 (1) Shift to "#top"
 (2) URI in action is loaded(may not be displayed. use Back button)
 (3) "#top" is still displayed
 (4) When back button is pressed :
     "#top" -> URI in action -> "#top" -> page position where clicked 
When the different URI is not in cache, HTTP GET is issued and it takes a while.
So rendering of the URI is executed after above (3), then URI in "form action" was the last displayed page.

Current behavior seems to be:
 (1) When <form><a href><input type=submit></a></form>, kick "action" of form
 (2) Kick "href"
 (3) Kick "href" again (Bug 384364)

Even after fix of Bug 384364, there is at least one problem.
When following HTML, what should be loaded?
> <form action="http: URL-A"><a href="http: URL-B"><input type="submit"></a></form>
If only one of two, which? If both, what order? First come, first served?
How about POST case?
NSPR log is obtained by following option, with DebugView on MS Win-XP SP3, with
Fx trunk.
> SET NSPR_LOG_MODULES=nsHttp:5,DOMLeak:5,DocumentLeak:5,nsDocShellLeak:5
> SET NSPR_LOG_FILE=WinDebug

Case-3B:
> <form action="http://URI-A"><a href="http://URI-B"><input type="submit"></a></form>
URI-A and URI-B are already held in cache, so no log for HTTP GET.
QA Contact: ian → events
Fixed in bug 331959 (and the patch there includes tests for this bug).
Assignee: Olli.Pettay → bzbarsky
Status: NEW → RESOLVED
Closed: 13 years ago
Flags: in-testsuite+
Resolution: --- → FIXED
Target Milestone: --- → mozilla2.0b9
No longer depends on: 331959
Depends on: 331959
Component: Event Handling → User events and focus handling
You need to log in before you can comment on or make changes to this bug.