diff --git a/extensions/xforms/nsXFormsControlStub.cpp b/extensions/xforms/nsXFormsControlStub.cpp index 6b06f42ed881..8bf716e465eb 100644 --- a/extensions/xforms/nsXFormsControlStub.cpp +++ b/extensions/xforms/nsXFormsControlStub.cpp @@ -49,6 +49,9 @@ #include "nsIXTFXMLVisualWrapper.h" #include "nsIDocument.h" #include "nsXFormsModelElement.h" +#include "nsPIDOMWindow.h" +#include "nsIFocusController.h" +#include "nsIScriptGlobalObject.h" /** This class is used to generate xforms-hint and xforms-help events.*/ class nsXFormsHintHelpListener : public nsIDOMEventListener { @@ -332,6 +335,71 @@ nsXFormsControlStubBase::HandleDefault(nsIDOMEvent *aEvent, if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Focus].name)) { TryFocus(aHandled); + } else if (type.Equals(NS_LITERAL_STRING("keypress"))) { + nsCOMPtr keyEvent = do_QueryInterface(aEvent); + if (keyEvent) { + PRUint32 keycode; + keyEvent->GetKeyCode(&keycode); + if (keycode == nsIDOMKeyEvent::DOM_VK_TAB) { + PRBool extraKey = PR_FALSE; + + keyEvent->GetAltKey(&extraKey); + if (extraKey) { + return NS_OK; + } + + keyEvent->GetCtrlKey(&extraKey); + if (extraKey) { + return NS_OK; + } + + keyEvent->GetMetaKey(&extraKey); + if (extraKey) { + return NS_OK; + } + + keyEvent->GetShiftKey(&extraKey); + mPreventLoop = PR_TRUE; + if (extraKey) { + nsXFormsUtils::DispatchEvent(mElement, eEvent_Previous); + } else { + nsXFormsUtils::DispatchEvent(mElement, eEvent_Next); + } + } + } + } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Next].name) || + type.EqualsASCII(sXFormsEventsEntries[eEvent_Previous].name)) { + + // only continue this processing if xforms-next or xforms-previous were + // dispatched by the form and not as part of the 'tab' and 'shift+tab' + // processing + if (mPreventLoop) { + mPreventLoop = PR_FALSE; + return NS_OK; + } + + nsCOMPtr domDoc; + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); + + nsCOMPtr doc = do_QueryInterface(domDoc); + // element isn't in a document, yet? Odd, indeed. Well, if not in + // document, these two events have no meaning. + NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); + nsCOMPtr win = + do_QueryInterface(doc->GetScriptGlobalObject()); + + + // An inelegant way to retrieve this to be sure, but we are + // guaranteed that the focus controller outlives us, so it + // is safe to hold on to it (since we can't die until it has + // died). + nsIFocusController *focusController = win->GetRootFocusController(); + if (focusController && + type.EqualsASCII(sXFormsEventsEntries[eEvent_Next].name)) { + focusController->MoveFocus(PR_TRUE, nsnull); + } else { + focusController->MoveFocus(PR_FALSE, nsnull); + } } } diff --git a/extensions/xforms/nsXFormsControlStub.h b/extensions/xforms/nsXFormsControlStub.h index 1e89c00862a1..3c3b66ebce1b 100644 --- a/extensions/xforms/nsXFormsControlStub.h +++ b/extensions/xforms/nsXFormsControlStub.h @@ -143,7 +143,8 @@ public: nsIXTFElement::NOTIFY_HANDLE_DEFAULT), kElementFlags(nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR), mHasParent(PR_FALSE), - mBindAttrsCount(0) + mBindAttrsCount(0), + mPreventLoop(PR_FALSE) {}; protected: @@ -165,6 +166,11 @@ protected: /** State that tells whether control has a parent or not */ PRBool mHasParent; + /** State to prevent infinite loop when generating and handling xforms-next + * and xforms-previous events + */ + PRBool mPreventLoop; + /** * Array of repeat-elements of which the control uses repeat-index. */