Set the status bar before actually handling the DOM event. That way if theevent is canceled, we'll still show the right status bar text. Bug 40838,patch by Florian Quèze <f.qu@queze.net, r=smaug, sr=bzbarsky

This commit is contained in:
bzbarsky@mit.edu 2007-04-23 00:31:21 -07:00
parent 7e52b169fd
commit bcfbc64387
11 changed files with 162 additions and 38 deletions

View File

@ -49,6 +49,7 @@ class nsIContent;
class nsIDocument;
class nsIDOMEvent;
class nsPresContext;
class nsEventChainVisitor;
class nsEventChainPreVisitor;
class nsEventChainPostVisitor;
class nsIEventListenerManager;

View File

@ -3794,6 +3794,74 @@ nsGenericElement::CreateSlots()
return new nsDOMSlots(mFlagsOrSlots);
}
PRBool
nsGenericElement::CheckHandleEventForLinksPrecondition(nsEventChainVisitor& aVisitor,
nsIURI** aURI) const
{
if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
!NS_IS_TRUSTED_EVENT(aVisitor.mEvent) ||
!aVisitor.mPresContext) {
return PR_FALSE;
}
// Make sure we actually are a link
return IsLink(aURI);
}
nsresult
nsGenericElement::PreHandleEventForLinks(nsEventChainPreVisitor& aVisitor)
{
// Optimisation: return early if this event doesn't interest us.
// IMPORTANT: this switch and the switch below it must be kept in sync!
switch (aVisitor.mEvent->message) {
case NS_MOUSE_ENTER_SYNTH:
case NS_FOCUS_CONTENT:
case NS_MOUSE_EXIT_SYNTH:
case NS_BLUR_CONTENT:
break;
default:
return NS_OK;
}
// Make sure we meet the preconditions before continuing
nsCOMPtr<nsIURI> absURI;
if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
return NS_OK;
}
nsresult rv = NS_OK;
// We do the status bar updates in PreHandleEvent so that the status bar gets
// updated even if the event is consumed before we have a chance to set it.
switch (aVisitor.mEvent->message) {
// Set the status bar the same for focus and mouseover
case NS_MOUSE_ENTER_SYNTH:
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
// FALL THROUGH
case NS_FOCUS_CONTENT:
{
nsAutoString target;
GetLinkTarget(target);
rv = TriggerLink(aVisitor.mPresContext, absURI, target, PR_FALSE, PR_TRUE);
}
break;
case NS_MOUSE_EXIT_SYNTH:
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
// FALL THROUGH
case NS_BLUR_CONTENT:
rv = LeaveLink(aVisitor.mPresContext);
break;
default:
// switch not in sync with the optimization switch earlier in this function
NS_NOTREACHED("switch statements not in sync");
return NS_ERROR_UNEXPECTED;
}
return rv;
}
nsresult
nsGenericElement::PostHandleEventForLinks(nsEventChainPostVisitor& aVisitor)
{
@ -3804,24 +3872,14 @@ nsGenericElement::PostHandleEventForLinks(nsEventChainPostVisitor& aVisitor)
case NS_MOUSE_CLICK:
case NS_UI_ACTIVATE:
case NS_KEY_PRESS:
case NS_MOUSE_ENTER_SYNTH:
case NS_FOCUS_CONTENT:
case NS_MOUSE_EXIT_SYNTH:
case NS_BLUR_CONTENT:
break;
default:
return NS_OK;
}
if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
!NS_IS_TRUSTED_EVENT(aVisitor.mEvent) ||
!aVisitor.mPresContext) {
return NS_OK;
}
// Make sure we actually are a link before continuing
// Make sure we meet the preconditions before continuing
nsCOMPtr<nsIURI> absURI;
if (!IsLink(getter_AddRefs(absURI))) {
if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
return NS_OK;
}
@ -3908,27 +3966,6 @@ nsGenericElement::PostHandleEventForLinks(nsEventChainPostVisitor& aVisitor)
}
break;
// Set the status bar the same for focus and mouseover
case NS_MOUSE_ENTER_SYNTH:
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
// FALL THROUGH
case NS_FOCUS_CONTENT:
{
nsAutoString target;
GetLinkTarget(target);
rv = TriggerLink(aVisitor.mPresContext, absURI, target, PR_FALSE, PR_TRUE);
}
break;
case NS_MOUSE_EXIT_SYNTH:
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
rv = LeaveLink(aVisitor.mPresContext);
break;
case NS_BLUR_CONTENT:
rv = LeaveLink(aVisitor.mPresContext);
break;
default:
// switch not in sync with the optimization switch earlier in this function
NS_NOTREACHED("switch statements not in sync");

View File

@ -1005,9 +1005,29 @@ protected:
void GetContentsAsText(nsAString& aText);
/**
* Unified function to carry out event default actions for links of all types
* Functions to carry out event default actions for links of all types
* (HTML links, XLinks, SVG "XLinks", etc.)
*/
/**
* Check that we meet the conditions to handle a link event
* and that we are actually on a link.
*
* @param aVisitor event visitor
* @param aURI the uri of the link, set only if the return value is PR_TRUE [OUT]
* @return PR_TRUE if we can handle the link event, PR_FALSE otherwise
*/
PRBool CheckHandleEventForLinksPrecondition(nsEventChainVisitor& aVisitor,
nsIURI** aURI) const;
/**
* Handle status bar updates before they can be cancelled.
*/
nsresult PreHandleEventForLinks(nsEventChainPreVisitor& aVisitor);
/**
* Handle default actions for link event if the event isn't consumed yet.
*/
nsresult PostHandleEventForLinks(nsEventChainPostVisitor& aVisitor);
/**

View File

@ -1255,8 +1255,8 @@ IsArea(nsIContent *aContent)
aContent->IsNodeOfType(nsINode::eHTML));
}
nsresult
nsGenericHTMLElement::PostHandleEventForAnchors(nsEventChainPostVisitor& aVisitor)
PRBool
nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(nsEventChainVisitor& aVisitor)
{
NS_PRECONDITION(nsCOMPtr<nsILink>(do_QueryInterface(this)),
"should be called only when |this| implements |nsILink|");
@ -1265,7 +1265,7 @@ nsGenericHTMLElement::PostHandleEventForAnchors(nsEventChainPostVisitor& aVisito
// We need a pres context to do link stuff. Some events (e.g. mutation
// events) don't have one.
// XXX: ideally, shouldn't we be able to do what we need without one?
return NS_OK;
return PR_FALSE;
}
//Need to check if we hit an imagemap area and if so see if we're handling
@ -1275,7 +1275,26 @@ nsGenericHTMLElement::PostHandleEventForAnchors(nsEventChainPostVisitor& aVisito
aVisitor.mPresContext->EventStateManager()->
GetEventTargetContent(aVisitor.mEvent, getter_AddRefs(target));
if (target && IsArea(target) && !IsArea(this)) {
return !target || !IsArea(target) || IsArea(this);
}
nsresult
nsGenericHTMLElement::PreHandleEventForAnchors(nsEventChainPreVisitor& aVisitor)
{
nsresult rv = nsGenericElement::PreHandleEvent(aVisitor);
NS_ENSURE_SUCCESS(rv, rv);
if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
return NS_OK;
}
return PreHandleEventForLinks(aVisitor);
}
nsresult
nsGenericHTMLElement::PostHandleEventForAnchors(nsEventChainPostVisitor& aVisitor)
{
if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
return NS_OK;
}

View File

@ -202,6 +202,12 @@ public:
virtual void PerformAccesskey(PRBool aKeyCausesActivation,
PRBool aIsTrustedEvent);
/**
* Check if an event for an anchor can be handled
* @return PR_TRUE if the event can be handled, PR_FALSE otherwise
*/
PRBool CheckHandleEventForAnchorsPreconditions(nsEventChainVisitor& aVisitor);
nsresult PreHandleEventForAnchors(nsEventChainPreVisitor& aVisitor);
nsresult PostHandleEventForAnchors(nsEventChainPostVisitor& aVisitor);
PRBool IsHTMLLink(nsIURI** aURI) const;

View File

@ -111,6 +111,7 @@ public:
virtual void SetFocus(nsPresContext* aPresContext);
virtual PRBool IsFocusable(PRBool *aTabIndex = nsnull);
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
virtual PRBool IsLink(nsIURI** aURI) const;
virtual void GetLinkTarget(nsAString& aTarget);
@ -275,6 +276,12 @@ nsHTMLAnchorElement::IsFocusable(PRInt32 *aTabIndex)
return PR_TRUE;
}
nsresult
nsHTMLAnchorElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{
return PreHandleEventForAnchors(aVisitor);
}
nsresult
nsHTMLAnchorElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
{

View File

@ -87,6 +87,7 @@ public:
NS_IMETHOD LinkAdded() { return NS_OK; }
NS_IMETHOD LinkRemoved() { return NS_OK; }
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
virtual PRBool IsLink(nsIURI** aURI) const;
virtual void GetLinkTarget(nsAString& aTarget);
@ -170,6 +171,12 @@ nsHTMLAreaElement::SetTarget(const nsAString& aValue)
return SetAttr(kNameSpaceID_None, nsGkAtoms::target, aValue, PR_TRUE);
}
nsresult
nsHTMLAreaElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{
return PreHandleEventForAnchors(aVisitor);
}
nsresult
nsHTMLAreaElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
{

View File

@ -107,6 +107,7 @@ public:
virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
PRBool aNotify);
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
virtual PRBool IsLink(nsIURI** aURI) const;
virtual void GetLinkTarget(nsAString& aTarget);
@ -325,6 +326,12 @@ nsHTMLLinkElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
return rv;
}
nsresult
nsHTMLLinkElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{
return PreHandleEventForAnchors(aVisitor);
}
nsresult
nsHTMLLinkElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
{

View File

@ -69,6 +69,7 @@ public:
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGAElementBase::)
// nsINode interface methods
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
@ -168,6 +169,15 @@ nsSVGAElement::GetHref(nsIDOMSVGAnimatedString * *aHref)
//----------------------------------------------------------------------
// nsINode methods
nsresult
nsSVGAElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{
nsresult rv = nsGenericElement::PreHandleEvent(aVisitor);
NS_ENSURE_SUCCESS(rv, rv);
return PreHandleEventForLinks(aVisitor);
}
nsresult
nsSVGAElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
{

View File

@ -113,6 +113,15 @@ DocShellToPresContext(nsIDocShell *aShell, nsPresContext **aPresContext)
return ds->GetPresContext(aPresContext);
}
nsresult
nsXMLElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{
nsresult rv = nsGenericElement::PreHandleEvent(aVisitor);
NS_ENSURE_SUCCESS(rv, rv);
return PreHandleEventForLinks(aVisitor);
}
nsresult
nsXMLElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
{

View File

@ -60,6 +60,7 @@ public:
NS_FORWARD_NSIDOMELEMENT(nsGenericElement::)
// nsINode interface methods
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;