Fix for bug 138957 - Submission triggering element must submit nam/value pair

if the submission is performed from onlcick and the handler retunrs true.
Introduced submission deferal to wait for the handler's return value.
r= jkeiser sr=jst
This commit is contained in:
alexsavulov%netscape.com 2002-11-30 00:01:21 +00:00
Родитель 2cd27f702a
Коммит 5cc1ae7c24
4 изменённых файлов: 557 добавлений и 319 удалений

Просмотреть файл

@ -155,6 +155,29 @@ public:
* @param aEnum the enumeration [OUT]
*/
NS_IMETHOD GetControlEnumerator(nsISimpleEnumerator** aEnum) = 0;
/**
* Flag the form to know that a button or image triggered scripted form
* submission. In that case the form will defer the submission until the
* script handler returns and the return value is known.
*/
NS_IMETHOD OnSubmitClickBegin() = 0;
NS_IMETHOD OnSubmitClickEnd() = 0;
/**
* Flush a possible pending submission. If there was a scripted submission
* triggered by a button or image, the submission was defered. This method
* forces the pending submission to be submitted. (happens when the handler
* returns false or there is an action/target change in the script)
*/
NS_IMETHOD FlushPendingSubmission() = 0;
/**
* Forget a possible pending submission. Same as above but this time we
* get rid of the pending submission cause the handler returned true
* so we will rebuild the submission with the name/value of the triggering
* element
*/
NS_IMETHOD ForgetPendingSubmission() = 0;
};
#endif /* nsIForm_h___ */

Просмотреть файл

@ -463,7 +463,20 @@ nsHTMLButtonElement::HandleDOMEvent(nsIPresContext* aPresContext,
return NS_OK;
}
}
PRBool bInSubmitClick = mType == NS_FORM_BUTTON_SUBMIT &&
!(aFlags & NS_EVENT_FLAG_CAPTURE) &&
!(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) &&
aEvent->message == NS_MOUSE_LEFT_CLICK &&
mForm;
if (bInSubmitClick) {
// tell the form that we are about to enter a click handler.
// that means that if there are scripted submissions, the
// latest one will be deferred until after the exit point of the handler.
mForm->OnSubmitClickBegin();
}
// Try script event handlers first
nsresult ret;
ret = nsGenericHTMLContainerFormElement::HandleDOMEvent(aPresContext,
@ -471,121 +484,154 @@ nsHTMLButtonElement::HandleDOMEvent(nsIPresContext* aPresContext,
aFlags,
aEventStatus);
if ((NS_OK == ret) && (nsEventStatus_eIgnore == *aEventStatus) &&
!(aFlags & NS_EVENT_FLAG_CAPTURE) && !(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT)) {
switch (aEvent->message) {
if (bInSubmitClick) {
// tell the form that we are about to exit a click handler
// so the form knows not to defer subsequent submissions
// the pending ones that were created during the handler
// will be flushed or forgoten.
mForm->OnSubmitClickEnd();
}
case NS_KEY_PRESS:
case NS_KEY_UP:
{
// For backwards compat, trigger buttons with space or enter
// (bug 25300)
nsKeyEvent * keyEvent = (nsKeyEvent *)aEvent;
if ((keyEvent->keyCode == NS_VK_RETURN && NS_KEY_PRESS == aEvent->message) ||
keyEvent->keyCode == NS_VK_SPACE && NS_KEY_UP == aEvent->message) {
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event;
event.eventStructType = NS_MOUSE_EVENT;
event.message = NS_MOUSE_LEFT_CLICK;
event.isShift = PR_FALSE;
event.isControl = PR_FALSE;
event.isAlt = PR_FALSE;
event.isMeta = PR_FALSE;
event.clickCount = 0;
event.widget = nsnull;
rv = HandleDOMEvent(aPresContext, &event, nsnull,
NS_EVENT_FLAG_INIT, &status);
}
}
break;// NS_KEY_PRESS
if (NS_SUCCEEDED(ret) &&
!(aFlags & NS_EVENT_FLAG_CAPTURE) && !(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT)) {
if (nsEventStatus_eIgnore == *aEventStatus) {
switch (aEvent->message) {
case NS_MOUSE_LEFT_CLICK:
{
if ((mType == NS_FORM_BUTTON_SUBMIT || mType == NS_FORM_BUTTON_RESET) &&
mForm) {
nsFormEvent event;
event.eventStructType = NS_FORM_EVENT;
event.message = (mType == NS_FORM_BUTTON_RESET)
? NS_FORM_RESET : NS_FORM_SUBMIT;
event.originator = this;
nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
// If |nsIPresShell::Destroy| has been called due to
// handling the event (base class HandleDOMEvent, above),
// the pres context will return a null pres shell. See
// bug 125624.
if (presShell) {
nsCOMPtr<nsIContent> form(do_QueryInterface(mForm));
presShell->HandleDOMEventWithTarget(form, &event, &status);
case NS_KEY_PRESS:
case NS_KEY_UP:
{
// For backwards compat, trigger buttons with space or enter
// (bug 25300)
nsKeyEvent * keyEvent = (nsKeyEvent *)aEvent;
if ((keyEvent->keyCode == NS_VK_RETURN && NS_KEY_PRESS == aEvent->message) ||
keyEvent->keyCode == NS_VK_SPACE && NS_KEY_UP == aEvent->message) {
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event;
event.eventStructType = NS_MOUSE_EVENT;
event.message = NS_MOUSE_LEFT_CLICK;
event.isShift = PR_FALSE;
event.isControl = PR_FALSE;
event.isAlt = PR_FALSE;
event.isMeta = PR_FALSE;
event.clickCount = 0;
event.widget = nsnull;
rv = HandleDOMEvent(aPresContext, &event, nsnull,
NS_EVENT_FLAG_INIT, &status);
}
}
}
break;// NS_MOUSE_LEFT_CLICK
break;// NS_KEY_PRESS
case NS_MOUSE_LEFT_BUTTON_DOWN:
{
nsIEventStateManager *stateManager;
if (NS_OK == aPresContext->GetEventStateManager(&stateManager)) {
stateManager->SetContentState(this, NS_EVENT_STATE_ACTIVE |
NS_EVENT_STATE_FOCUS);
NS_RELEASE(stateManager);
case NS_MOUSE_LEFT_CLICK:
{
if (mForm) {
if (mType == NS_FORM_BUTTON_SUBMIT) {
// tell the form to forget a possible pending submission.
// the reason is that the script returned true (the event was
// ignored) so if there is a stored submission, it will miss
// the name/value of the submitting element, thus we need
// to forget it and the form element will build a new one
mForm->ForgetPendingSubmission();
}
if (mType == NS_FORM_BUTTON_SUBMIT || mType == NS_FORM_BUTTON_RESET) {
nsFormEvent event;
event.eventStructType = NS_FORM_EVENT;
event.message = (mType == NS_FORM_BUTTON_RESET)
? NS_FORM_RESET : NS_FORM_SUBMIT;
event.originator = this;
nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
// If |nsIPresShell::Destroy| has been called due to
// handling the event (base class HandleDOMEvent, above),
// the pres context will return a null pres shell. See
// bug 125624.
if (presShell) {
nsCOMPtr<nsIContent> form(do_QueryInterface(mForm));
presShell->HandleDOMEventWithTarget(form, &event, &status);
}
}
}
}
*aEventStatus = nsEventStatus_eConsumeNoDefault;
}
break;
break;// NS_MOUSE_LEFT_CLICK
// cancel all of these events for buttons
case NS_MOUSE_MIDDLE_BUTTON_DOWN:
case NS_MOUSE_MIDDLE_BUTTON_UP:
case NS_MOUSE_MIDDLE_DOUBLECLICK:
case NS_MOUSE_RIGHT_DOUBLECLICK:
case NS_MOUSE_RIGHT_BUTTON_DOWN:
case NS_MOUSE_RIGHT_BUTTON_UP:
{
nsCOMPtr<nsIDOMNSEvent> nsevent;
case NS_MOUSE_LEFT_BUTTON_DOWN:
{
nsIEventStateManager *stateManager;
if (NS_OK == aPresContext->GetEventStateManager(&stateManager)) {
stateManager->SetContentState(this, NS_EVENT_STATE_ACTIVE |
NS_EVENT_STATE_FOCUS);
NS_RELEASE(stateManager);
}
*aEventStatus = nsEventStatus_eConsumeNoDefault;
}
break;
if (aDOMEvent) {
nsevent = do_QueryInterface(*aDOMEvent);
// cancel all of these events for buttons
case NS_MOUSE_MIDDLE_BUTTON_DOWN:
case NS_MOUSE_MIDDLE_BUTTON_UP:
case NS_MOUSE_MIDDLE_DOUBLECLICK:
case NS_MOUSE_RIGHT_DOUBLECLICK:
case NS_MOUSE_RIGHT_BUTTON_DOWN:
case NS_MOUSE_RIGHT_BUTTON_UP:
{
nsCOMPtr<nsIDOMNSEvent> nsevent;
if (aDOMEvent) {
nsevent = do_QueryInterface(*aDOMEvent);
}
if (nsevent) {
nsevent->PreventBubble();
} else {
ret = NS_ERROR_FAILURE;
}
}
if (nsevent) {
nsevent->PreventBubble();
} else {
ret = NS_ERROR_FAILURE;
break;
case NS_MOUSE_ENTER_SYNTH:
{
nsIEventStateManager *stateManager;
if (NS_OK == aPresContext->GetEventStateManager(&stateManager)) {
stateManager->SetContentState(this, NS_EVENT_STATE_HOVER);
NS_RELEASE(stateManager);
}
*aEventStatus = nsEventStatus_eConsumeNoDefault;
}
}
break;
break;
case NS_MOUSE_ENTER_SYNTH:
{
nsIEventStateManager *stateManager;
if (NS_OK == aPresContext->GetEventStateManager(&stateManager)) {
stateManager->SetContentState(this, NS_EVENT_STATE_HOVER);
NS_RELEASE(stateManager);
// XXX this doesn't seem to do anything yet
case NS_MOUSE_EXIT_SYNTH:
{
nsIEventStateManager *stateManager;
if (NS_OK == aPresContext->GetEventStateManager(&stateManager)) {
stateManager->SetContentState(nsnull, NS_EVENT_STATE_HOVER);
NS_RELEASE(stateManager);
}
*aEventStatus = nsEventStatus_eConsumeNoDefault;
}
*aEventStatus = nsEventStatus_eConsumeNoDefault;
}
break;
break;
// XXX this doesn't seem to do anything yet
case NS_MOUSE_EXIT_SYNTH:
{
nsIEventStateManager *stateManager;
if (NS_OK == aPresContext->GetEventStateManager(&stateManager)) {
stateManager->SetContentState(nsnull, NS_EVENT_STATE_HOVER);
NS_RELEASE(stateManager);
default:
break;
}
} else {
switch (aEvent->message) {
case NS_MOUSE_LEFT_CLICK:
if (mForm && mType == NS_FORM_BUTTON_SUBMIT) {
// tell the form to flush a possible pending submission.
// the reason is that the script returned false (the event was
// not ignored) so if there is a stored submission, it needs to
// be submitted immediatelly.
mForm->FlushPendingSubmission();
}
*aEventStatus = nsEventStatus_eConsumeNoDefault;
}
break;
break;// NS_MOUSE_LEFT_CLICK
} //switch
} //if
} //if
default:
break;
}
}
return ret;
}

Просмотреть файл

@ -120,6 +120,8 @@ public:
mGeneratingSubmit(PR_FALSE),
mGeneratingReset(PR_FALSE),
mIsSubmitting(PR_FALSE),
mInSubmitClick(PR_FALSE),
mPendingSubmission(nsnull),
mSubmittingRequest(nsnull) { }
@ -161,6 +163,10 @@ public:
nsISupports** aReturn);
NS_IMETHOD IndexOfControl(nsIFormControl* aControl, PRInt32* aIndex);
NS_IMETHOD GetControlEnumerator(nsISimpleEnumerator** aEnumerator);
NS_IMETHOD OnSubmitClickBegin();
NS_IMETHOD OnSubmitClickEnd();
NS_IMETHOD FlushPendingSubmission();
NS_IMETHOD ForgetPendingSubmission();
// nsIRadioGroupContainer
NS_IMETHOD SetCurrentRadioButton(const nsAString& aName,
@ -228,12 +234,32 @@ protected:
//
//
/**
* Actually perform the submit (called by DoSubmitOrReset)
* Attempt to submit (submission might be deferred)
* (called by DoSubmitOrReset)
*
* @param aPresContext the presentation context
* @param aEvent the DOM event that was passed to us for the submit
*/
nsresult DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent);
/**
* Prepare the submission object (called by DoSubmit)
*
* @param aPresContext the presentation context
* @param aFormSubmission the submission object
* @param aEvent the DOM event that was passed to us for the submit
*/
nsresult BuildSubmission(nsIPresContext* aPresContext,
nsCOMPtr<nsIFormSubmission>& aFormSubmission,
nsEvent* aEvent);
/**
* Perform the submission (called by DoSubmit and FlushPendingSubmission)
*
* @param aPresContext the presentation context
* @param aFormSubmission the submission object
*/
nsresult SubmitSubmission(nsIPresContext* aPresContext,
nsIFormSubmission* aFormSubmission);
/**
* Walk over the form elements and call SubmitNamesValues() on them to get
* their data pumped into the FormSubmitter.
@ -271,6 +297,11 @@ protected:
PRPackedBool mGeneratingReset;
/** Whether we are submitting currently */
PRPackedBool mIsSubmitting;
/** Whether the submission was triggered by an Image or Submit*/
PRPackedBool mInSubmitClick;
/** The pending submission object */
nsCOMPtr<nsIFormSubmission> mPendingSubmission;
/** The request currently being submitted */
nsCOMPtr<nsIRequest> mSubmittingRequest;
/** The web progress object we are currently listening to */
@ -522,6 +553,13 @@ nsHTMLFormElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, PRBool aNotify)
{
if (aName == nsHTMLAtoms::action || aName == nsHTMLAtoms::target) {
if (mPendingSubmission) {
// aha, there is a pending submission that means we're in
// the script and we need to flush it. let's tell it
// that the event was ignored to force the flush.
// the second argument is not playing a role at all.
FlushPendingSubmission();
}
ForgetCurrentSubmission();
}
return nsGenericHTMLContainerElement::SetAttr(aNameSpaceID, aName,
@ -790,7 +828,7 @@ nsHTMLFormElement::DoReset()
ForgetCurrentSubmission(); \
return rv; \
}
nsresult
nsHTMLFormElement::DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent)
{
@ -805,6 +843,44 @@ nsHTMLFormElement::DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent)
mIsSubmitting = PR_TRUE;
NS_ASSERTION(!mWebProgress && !mSubmittingRequest, "Web progress / submitting request should not exist here!");
nsCOMPtr<nsIFormSubmission> submission;
//
// prepare the submission object
//
BuildSubmission(aPresContext, submission, aEvent);
if(mInSubmitClick) {
// we are in the onclick event handler so we have to
// defer this submission. let's remember it and return
// without submitting
mPendingSubmission = submission;
// ensure reentrancy
mIsSubmitting = PR_FALSE;
return NS_OK;
}
//
// perform the submission
//
SubmitSubmission(aPresContext, submission);
return NS_OK;
}
nsresult
nsHTMLFormElement::BuildSubmission(nsIPresContext* aPresContext,
nsCOMPtr<nsIFormSubmission>& aFormSubmission,
nsEvent* aEvent)
{
if (mPendingSubmission) {
// aha, we have a pending submission that was not flushed
// (this happens when form.submit() is called twice for example)
// we have to delete it and build a new one since values
// might have changed inbetween (we emulate IE here, that's all)
mPendingSubmission = nsnull;
}
// Get the originating frame (failure is non-fatal)
nsIContent *originatingElement = nsnull;
if (aEvent) {
@ -813,20 +889,28 @@ nsHTMLFormElement::DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent)
}
}
nsresult rv;
//
// Get the submission object
//
nsCOMPtr<nsIFormSubmission> submission;
nsresult rv = GetSubmissionFromForm(this, aPresContext,
getter_AddRefs(submission));
rv = GetSubmissionFromForm(this, aPresContext, getter_AddRefs(aFormSubmission));
NS_ENSURE_SUBMIT_SUCCESS(rv);
//
// Dump the data into the submission object
//
rv = WalkFormElements(submission, originatingElement);
rv = WalkFormElements(aFormSubmission, originatingElement);
NS_ENSURE_SUBMIT_SUCCESS(rv);
return NS_OK;
}
nsresult
nsHTMLFormElement::SubmitSubmission(nsIPresContext* aPresContext,
nsIFormSubmission* aFormSubmission)
{
nsresult rv;
//
// Get the action and target
//
@ -870,9 +954,9 @@ nsHTMLFormElement::DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent)
// Submit
//
nsCOMPtr<nsIDocShell> docShell;
rv = submission->SubmitTo(actionURI, target, this, aPresContext,
getter_AddRefs(docShell),
getter_AddRefs(mSubmittingRequest));
rv = aFormSubmission->SubmitTo(actionURI, target, this, aPresContext,
getter_AddRefs(docShell),
getter_AddRefs(mSubmittingRequest));
NS_ENSURE_SUBMIT_SUCCESS(rv);
// Even if the submit succeeds, it's possible for there to be no docshell
@ -897,7 +981,6 @@ nsHTMLFormElement::DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent)
return rv;
}
nsresult
nsHTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL,
PRBool* aCancelSubmit)
@ -1224,6 +1307,46 @@ nsHTMLFormElement::ResolveName(const nsAString& aName,
return mControls->GetNamedObject(aName, aResult);
}
NS_IMETHODIMP
nsHTMLFormElement::OnSubmitClickBegin()
{
mInSubmitClick = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFormElement::OnSubmitClickEnd()
{
mInSubmitClick = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFormElement::FlushPendingSubmission()
{
if (!mPendingSubmission) {
return NS_OK;
}
//
// preform the submission with the stored pending submission
//
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
SubmitSubmission(presContext, mPendingSubmission);
// now delete the pending submission object
mPendingSubmission = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFormElement::ForgetPendingSubmission()
{
// just delete the pending submission
mPendingSubmission = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFormElement::GetEncoding(nsAString& aEncoding)

Просмотреть файл

@ -1400,6 +1400,16 @@ nsHTMLInputElement::HandleDOMEvent(nsIPresContext* aPresContext,
}
break;
case NS_FORM_INPUT_SUBMIT:
case NS_FORM_INPUT_IMAGE:
if(mForm) {
// tell the form that we are about to enter a click handler.
// that means that if there are scripted submissions, the
// latest one will be deferred until after the exit point of the handler.
mForm->OnSubmitClickBegin();
}
break;
default:
break;
} //switch
@ -1422,6 +1432,22 @@ nsHTMLInputElement::HandleDOMEvent(nsIPresContext* aPresContext,
aFlags,
aEventStatus);
if (!(aFlags & NS_EVENT_FLAG_CAPTURE) && !(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) &&
aEvent->message == NS_MOUSE_LEFT_CLICK) {
switch(type) {
case NS_FORM_INPUT_SUBMIT:
case NS_FORM_INPUT_IMAGE:
if(mForm) {
// tell the form that we are about to exit a click handler
// so the form knows not to defer subsequent submissions
// the pending ones that were created during the handler
// will be flushed or forgoten.
mForm->OnSubmitClickEnd();
}
break;
} //switch
}
// Reset the flag for other content besides this text field
aEvent->flags |= noContentDispatch ? NS_EVENT_FLAG_NO_CONTENT_DISPATCH : NS_EVENT_FLAG_NONE;
@ -1464,237 +1490,257 @@ nsHTMLInputElement::HandleDOMEvent(nsIPresContext* aPresContext,
// Bugscape 2369: type might have changed during event handler
GetType(&type);
if ((NS_OK == rv) && (nsEventStatus_eIgnore == *aEventStatus) &&
if (NS_SUCCEEDED(rv) &&
!(aFlags & NS_EVENT_FLAG_CAPTURE) &&
!(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT)) {
switch (aEvent->message) {
if (nsEventStatus_eIgnore == *aEventStatus) {
switch (aEvent->message) {
case NS_FOCUS_CONTENT:
{
if (formControlFrame) {
// If this is a file control, check to see if focus has bubbled
// up from it's child textfield or child button. If that's the case,
// don't focus this parent file control -- leave focus on the child.
if (type != NS_FORM_INPUT_FILE || !(aFlags & NS_EVENT_FLAG_BUBBLE)) {
SET_BOOLBIT(mBitField, BF_SKIP_FOCUS_EVENT, PR_TRUE);
formControlFrame->SetFocus(PR_TRUE, PR_TRUE);
SET_BOOLBIT(mBitField, BF_SKIP_FOCUS_EVENT, PR_FALSE);
case NS_FOCUS_CONTENT:
{
if (formControlFrame) {
// If this is a file control, check to see if focus has bubbled
// up from it's child textfield or child button. If that's the case,
// don't focus this parent file control -- leave focus on the child.
if (type != NS_FORM_INPUT_FILE || !(aFlags & NS_EVENT_FLAG_BUBBLE)) {
SET_BOOLBIT(mBitField, BF_SKIP_FOCUS_EVENT, PR_TRUE);
formControlFrame->SetFocus(PR_TRUE, PR_TRUE);
SET_BOOLBIT(mBitField, BF_SKIP_FOCUS_EVENT, PR_FALSE);
}
return NS_OK;
}
return NS_OK;
}
}
break; // NS_FOCUS_CONTENT
}
break; // NS_FOCUS_CONTENT
case NS_KEY_PRESS:
case NS_KEY_UP:
{
// For backwards compat, trigger checks/radios/buttons with
// space or enter (bug 25300)
nsKeyEvent * keyEvent = (nsKeyEvent *)aEvent;
case NS_KEY_PRESS:
case NS_KEY_UP:
{
// For backwards compat, trigger checks/radios/buttons with
// space or enter (bug 25300)
nsKeyEvent * keyEvent = (nsKeyEvent *)aEvent;
if ((aEvent->message == NS_KEY_PRESS &&
keyEvent->keyCode == NS_VK_RETURN) ||
(aEvent->message == NS_KEY_UP &&
keyEvent->keyCode == NS_VK_SPACE)) {
switch(type) {
case NS_FORM_INPUT_CHECKBOX:
case NS_FORM_INPUT_RADIO:
{
// Checkbox and Radio try to submit on Enter press
if (keyEvent->keyCode != NS_VK_SPACE) {
// Generate a submit event targeted at the form content
nsCOMPtr<nsIContent> form(do_QueryInterface(mForm));
if ((aEvent->message == NS_KEY_PRESS &&
keyEvent->keyCode == NS_VK_RETURN) ||
(aEvent->message == NS_KEY_UP &&
keyEvent->keyCode == NS_VK_SPACE)) {
switch(type) {
case NS_FORM_INPUT_CHECKBOX:
case NS_FORM_INPUT_RADIO:
{
// Checkbox and Radio try to submit on Enter press
if (keyEvent->keyCode != NS_VK_SPACE) {
// Generate a submit event targeted at the form content
nsCOMPtr<nsIContent> form(do_QueryInterface(mForm));
if (form) {
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
if (shell) {
nsCOMPtr<nsIContent> formControl = this; // kungFuDeathGrip
if (form) {
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
if (shell) {
nsCOMPtr<nsIContent> formControl = this; // kungFuDeathGrip
nsFormEvent event;
event.eventStructType = NS_FORM_EVENT;
event.message = NS_FORM_SUBMIT;
event.originator = formControl;
nsEventStatus status = nsEventStatus_eIgnore;
shell->HandleDOMEventWithTarget(form, &event, &status);
nsFormEvent event;
event.eventStructType = NS_FORM_EVENT;
event.message = NS_FORM_SUBMIT;
event.originator = formControl;
nsEventStatus status = nsEventStatus_eIgnore;
shell->HandleDOMEventWithTarget(form, &event, &status);
}
}
break; // If we are submitting, do not send click event
}
break; // If we are submitting, do not send click event
// else fall through and treat Space like click...
}
// else fall through and treat Space like click...
}
case NS_FORM_INPUT_BUTTON:
case NS_FORM_INPUT_RESET:
case NS_FORM_INPUT_SUBMIT:
case NS_FORM_INPUT_IMAGE: // Bug 34418
{
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event;
event.eventStructType = NS_MOUSE_EVENT;
event.message = NS_MOUSE_LEFT_CLICK;
event.isShift = PR_FALSE;
event.isControl = PR_FALSE;
event.isAlt = PR_FALSE;
event.isMeta = PR_FALSE;
event.clickCount = 0;
event.widget = nsnull;
rv = HandleDOMEvent(aPresContext, &event, nsnull,
NS_EVENT_FLAG_INIT, &status);
} // case
} // switch
}
/*
* If this is input type=text, and the user hit enter, fire onChange and
* submit the form (if we are in one)
*
* Bug 99920, bug 109463 and bug 147850:
* (a) if there is a submit control in the form, click the first submit
* control in the form.
* (b) if there is just one text control in the form, submit by sending
* a submit event directly to the form
* (c) if there is more than one text input and no submit buttons, do
* not submit, period.
*/
if (aEvent->message == NS_KEY_PRESS &&
(keyEvent->keyCode == NS_VK_RETURN ||
keyEvent->keyCode == NS_VK_ENTER) &&
(type == NS_FORM_INPUT_TEXT || type == NS_FORM_INPUT_PASSWORD)) {
if (mForm) {
nsIFrame* primaryFrame = GetPrimaryFrame(PR_FALSE);
if (primaryFrame) {
nsITextControlFrame* textFrame = nsnull;
CallQueryInterface(primaryFrame, &textFrame);
// Fire onChange (if necessary)
if (textFrame) {
textFrame->CheckFireOnChange();
}
}
// Find the first submit control in elements[]
// and also check how many text controls we have in the form
nsCOMPtr<nsIContent> submitControl;
PRInt32 numTextControlsFound = 0;
nsCOMPtr<nsISimpleEnumerator> formControls;
mForm->GetControlEnumerator(getter_AddRefs(formControls));
nsCOMPtr<nsISupports> currentControlSupports;
nsCOMPtr<nsIFormControl> currentControl;
PRBool hasMoreElements;
while (NS_SUCCEEDED(formControls->HasMoreElements(&hasMoreElements)) &&
hasMoreElements) {
formControls->GetNext(getter_AddRefs(currentControlSupports));
currentControl = do_QueryInterface(currentControlSupports);
if (currentControl) {
PRInt32 type;
currentControl->GetType(&type);
if (!submitControl &&
(type == NS_FORM_INPUT_SUBMIT ||
type == NS_FORM_BUTTON_SUBMIT ||
type == NS_FORM_INPUT_IMAGE)) {
submitControl = do_QueryInterface(currentControl);
// We know as soon as we find a submit control that it no
// longer matters how many text controls there are--we are
// going to fire the onClick handler.
break;
} else if (type == NS_FORM_INPUT_TEXT ||
type == NS_FORM_INPUT_PASSWORD) {
numTextControlsFound++;
}
}
}
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
if (shell) {
if (submitControl) {
// Fire the button's onclick handler and let the button handle
// submitting the form.
nsGUIEvent event;
case NS_FORM_INPUT_BUTTON:
case NS_FORM_INPUT_RESET:
case NS_FORM_INPUT_SUBMIT:
case NS_FORM_INPUT_IMAGE: // Bug 34418
{
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event;
event.eventStructType = NS_MOUSE_EVENT;
event.message = NS_MOUSE_LEFT_CLICK;
event.isShift = PR_FALSE;
event.isControl = PR_FALSE;
event.isAlt = PR_FALSE;
event.isMeta = PR_FALSE;
event.clickCount = 0;
event.widget = nsnull;
nsEventStatus status = nsEventStatus_eIgnore;
shell->HandleDOMEventWithTarget(submitControl, &event, &status);
} else if (numTextControlsFound == 1) {
// If there's only one text control, just submit the form
nsCOMPtr<nsIContent> form = do_QueryInterface(mForm);
nsFormEvent event;
event.eventStructType = NS_FORM_EVENT;
event.message = NS_FORM_SUBMIT;
event.originator = nsnull;
nsEventStatus status = nsEventStatus_eIgnore;
shell->HandleDOMEventWithTarget(form, &event, &status);
rv = HandleDOMEvent(aPresContext, &event, nsnull,
NS_EVENT_FLAG_INIT, &status);
} // case
} // switch
}
/*
* If this is input type=text, and the user hit enter, fire onChange and
* submit the form (if we are in one)
*
* Bug 99920, bug 109463 and bug 147850:
* (a) if there is a submit control in the form, click the first submit
* control in the form.
* (b) if there is just one text control in the form, submit by sending
* a submit event directly to the form
* (c) if there is more than one text input and no submit buttons, do
* not submit, period.
*/
if (aEvent->message == NS_KEY_PRESS &&
(keyEvent->keyCode == NS_VK_RETURN ||
keyEvent->keyCode == NS_VK_ENTER) &&
(type == NS_FORM_INPUT_TEXT || type == NS_FORM_INPUT_PASSWORD)) {
if (mForm) {
nsIFrame* primaryFrame = GetPrimaryFrame(PR_FALSE);
if (primaryFrame) {
nsITextControlFrame* textFrame = nsnull;
CallQueryInterface(primaryFrame, &textFrame);
// Fire onChange (if necessary)
if (textFrame) {
textFrame->CheckFireOnChange();
}
}
}
}
}
} break; // NS_KEY_PRESS || NS_KEY_UP
// Find the first submit control in elements[]
// and also check how many text controls we have in the form
nsCOMPtr<nsIContent> submitControl;
PRInt32 numTextControlsFound = 0;
// cancel all of these events for buttons
case NS_MOUSE_MIDDLE_BUTTON_DOWN:
case NS_MOUSE_MIDDLE_BUTTON_UP:
case NS_MOUSE_MIDDLE_DOUBLECLICK:
case NS_MOUSE_RIGHT_DOUBLECLICK:
case NS_MOUSE_RIGHT_BUTTON_DOWN:
case NS_MOUSE_RIGHT_BUTTON_UP:
{
if (type == NS_FORM_INPUT_BUTTON ||
type == NS_FORM_INPUT_RESET ||
type == NS_FORM_INPUT_SUBMIT ) {
nsCOMPtr<nsIDOMNSEvent> nsevent;
nsCOMPtr<nsISimpleEnumerator> formControls;
mForm->GetControlEnumerator(getter_AddRefs(formControls));
if (aDOMEvent) {
nsevent = do_QueryInterface(*aDOMEvent);
}
if (nsevent) {
nsevent->PreventBubble();
} else {
rv = NS_ERROR_FAILURE;
}
}
break;
}
case NS_MOUSE_LEFT_CLICK:
{
switch(type) {
case NS_FORM_INPUT_RESET:
case NS_FORM_INPUT_SUBMIT:
case NS_FORM_INPUT_IMAGE:
{
if (mForm) {
nsFormEvent event;
event.eventStructType = NS_FORM_EVENT;
event.message = (type == NS_FORM_INPUT_RESET) ? NS_FORM_RESET : NS_FORM_SUBMIT;
event.originator = this;
nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
// If |nsIPresShell::Destroy| has been called due to
// handling the event (base class HandleDOMEvent, above),
// the pres context will return a null pres shell. See
// bug 125624.
if (presShell) {
nsCOMPtr<nsIContent> form(do_QueryInterface(mForm));
presShell->HandleDOMEventWithTarget(form, &event, &status);
nsCOMPtr<nsISupports> currentControlSupports;
nsCOMPtr<nsIFormControl> currentControl;
PRBool hasMoreElements;
while (NS_SUCCEEDED(formControls->HasMoreElements(&hasMoreElements)) &&
hasMoreElements) {
formControls->GetNext(getter_AddRefs(currentControlSupports));
currentControl = do_QueryInterface(currentControlSupports);
if (currentControl) {
PRInt32 type;
currentControl->GetType(&type);
if (!submitControl &&
(type == NS_FORM_INPUT_SUBMIT ||
type == NS_FORM_BUTTON_SUBMIT ||
type == NS_FORM_INPUT_IMAGE)) {
submitControl = do_QueryInterface(currentControl);
// We know as soon as we find a submit control that it no
// longer matters how many text controls there are--we are
// going to fire the onClick handler.
break;
} else if (type == NS_FORM_INPUT_TEXT ||
type == NS_FORM_INPUT_PASSWORD) {
numTextControlsFound++;
}
}
}
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
if (shell) {
if (submitControl) {
// Fire the button's onclick handler and let the button handle
// submitting the form.
nsGUIEvent event;
event.eventStructType = NS_MOUSE_EVENT;
event.message = NS_MOUSE_LEFT_CLICK;
event.widget = nsnull;
nsEventStatus status = nsEventStatus_eIgnore;
shell->HandleDOMEventWithTarget(submitControl, &event, &status);
} else if (numTextControlsFound == 1) {
// If there's only one text control, just submit the form
nsCOMPtr<nsIContent> form = do_QueryInterface(mForm);
nsFormEvent event;
event.eventStructType = NS_FORM_EVENT;
event.message = NS_FORM_SUBMIT;
event.originator = nsnull;
nsEventStatus status = nsEventStatus_eIgnore;
shell->HandleDOMEventWithTarget(form, &event, &status);
}
}
}
break;
}
default:
break;
} //switch
} break;// NS_MOUSE_LEFT_BUTTON_DOWN
} //switch
} break; // NS_KEY_PRESS || NS_KEY_UP
// cancel all of these events for buttons
case NS_MOUSE_MIDDLE_BUTTON_DOWN:
case NS_MOUSE_MIDDLE_BUTTON_UP:
case NS_MOUSE_MIDDLE_DOUBLECLICK:
case NS_MOUSE_RIGHT_DOUBLECLICK:
case NS_MOUSE_RIGHT_BUTTON_DOWN:
case NS_MOUSE_RIGHT_BUTTON_UP:
{
if (type == NS_FORM_INPUT_BUTTON ||
type == NS_FORM_INPUT_RESET ||
type == NS_FORM_INPUT_SUBMIT ) {
nsCOMPtr<nsIDOMNSEvent> nsevent;
if (aDOMEvent) {
nsevent = do_QueryInterface(*aDOMEvent);
}
if (nsevent) {
nsevent->PreventBubble();
} else {
rv = NS_ERROR_FAILURE;
}
}
break;
}
case NS_MOUSE_LEFT_CLICK:
{
switch(type) {
case NS_FORM_INPUT_RESET:
case NS_FORM_INPUT_SUBMIT:
case NS_FORM_INPUT_IMAGE:
{
if (mForm) {
if (mType == NS_FORM_INPUT_SUBMIT ||
mType == NS_FORM_INPUT_IMAGE) {
// tell the form to forget a possible pending submission.
// the reason is that the script returned true (the event was
// ignored) so if there is a stored submission, it will miss
// the name/value of the submitting element, thus we need
// to forget it and the form element will build a new one
mForm->ForgetPendingSubmission();
}
nsFormEvent event;
event.eventStructType = NS_FORM_EVENT;
event.message = (type == NS_FORM_INPUT_RESET) ? NS_FORM_RESET : NS_FORM_SUBMIT;
event.originator = this;
nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
// If |nsIPresShell::Destroy| has been called due to
// handling the event (base class HandleDOMEvent, above),
// the pres context will return a null pres shell. See
// bug 125624.
if (presShell) {
nsCOMPtr<nsIContent> form(do_QueryInterface(mForm));
presShell->HandleDOMEventWithTarget(form, &event, &status);
}
}
}
break;
default:
break;
} //switch
} break;// NS_MOUSE_LEFT_CLICK
} //switch
} else {
if (aEvent->message == NS_MOUSE_LEFT_CLICK &&
(type == NS_FORM_INPUT_SUBMIT || type == NS_FORM_INPUT_IMAGE) && mForm) {
// tell the form to flush a possible pending submission.
// the reason is that the script returned false (the event was
// not ignored) so if there is a stored submission, it needs to
// be submitted immediatelly.
mForm->FlushPendingSubmission();
}
} //if
} // if
return rv;