From 26a2d9444e9f8bb495e410113e7dfec11ce0c67e Mon Sep 17 00:00:00 2001 From: "hyatt%netscape.com" Date: Wed, 11 Apr 2001 03:05:42 +0000 Subject: [PATCH] Adding support for advancing and rewinding the focus using the command dispatcher. r=saari, sr=jst --- content/xul/content/src/nsXULElement.cpp | 4 +- .../document/src/nsXULCommandDispatcher.cpp | 27 ++++ dom/public/base/nsIFocusController.h | 2 + dom/public/idl/xul/XULCommandDispatcher.idl | 4 + .../idl/xul/nsIDOMXULCommandDispatcher.idl | 4 + dom/public/nsDOMPropEnums.h | 3 + dom/public/nsDOMPropNames.h | 3 + dom/public/xul/nsIDOMXULCommandDispatcher.h | 12 ++ dom/src/base/nsFocusController.cpp | 51 ++++++++ dom/src/base/nsFocusController.h | 2 + dom/src/xul/nsJSXULCommandDispatcher.cpp | 120 ++++++++++++++++++ 11 files changed, 231 insertions(+), 1 deletion(-) diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index 1dfac084f89a..f33bde096ff1 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -1859,7 +1859,9 @@ nsXULElement::AddScriptEventListener(nsIAtom* aName, const nsAReadableString& aV if (NS_FAILED(rv)) return rv; } - if (NodeInfo()->Equals(nsXULAtoms::window)) { + nsCOMPtr root(getter_AddRefs(mDocument->GetRootContent())); + nsCOMPtr content(do_QueryInterface(NS_STATIC_CAST(nsIStyledContent*, this))); + if ((!root || root == content) && !NodeInfo()->Equals(nsXULAtoms::overlay)) { nsCOMPtr receiver = do_QueryInterface(global); if (! receiver) return NS_ERROR_UNEXPECTED; diff --git a/content/xul/document/src/nsXULCommandDispatcher.cpp b/content/xul/document/src/nsXULCommandDispatcher.cpp index a0d61e1c1d1b..277c88b02ea5 100644 --- a/content/xul/document/src/nsXULCommandDispatcher.cpp +++ b/content/xul/document/src/nsXULCommandDispatcher.cpp @@ -168,6 +168,33 @@ nsXULCommandDispatcher::SetFocusedWindow(nsIDOMWindowInternal* aWindow) return NS_ERROR_FAILURE; } +NS_IMETHODIMP +nsXULCommandDispatcher::AdvanceFocus() +{ + EnsureFocusController(); + if (mFocusController) + return mFocusController->MoveFocus(PR_TRUE, nsnull); + return NS_OK; +} + +NS_IMETHODIMP +nsXULCommandDispatcher::RewindFocus() +{ + EnsureFocusController(); + if (mFocusController) + return mFocusController->MoveFocus(PR_FALSE, nsnull); + return NS_OK; +} + +NS_IMETHODIMP +nsXULCommandDispatcher::AdvanceFocusIntoSubtree(nsIDOMElement* aElt) +{ + EnsureFocusController(); + if (mFocusController) + return mFocusController->MoveFocus(PR_TRUE, aElt); + return NS_OK; +} + NS_IMETHODIMP nsXULCommandDispatcher::AddCommandUpdater(nsIDOMElement* aElement, const nsAReadableString& aEvents, diff --git a/dom/public/base/nsIFocusController.h b/dom/public/base/nsIFocusController.h index 6803eeaf86a4..d52a9a0e016e 100644 --- a/dom/public/base/nsIFocusController.h +++ b/dom/public/base/nsIFocusController.h @@ -55,6 +55,8 @@ public: NS_IMETHOD GetControllerForCommand(const nsAReadableString& aCommand, nsIController** aResult)=0; NS_IMETHOD GetControllers(nsIControllers** aResult)=0; + + NS_IMETHOD MoveFocus(PRBool aForward, nsIDOMElement* aElt)=0; }; #endif // nsIFocusController_h__ diff --git a/dom/public/idl/xul/XULCommandDispatcher.idl b/dom/public/idl/xul/XULCommandDispatcher.idl index fac7a61e2b15..a46b8c9f6e03 100644 --- a/dom/public/idl/xul/XULCommandDispatcher.idl +++ b/dom/public/idl/xul/XULCommandDispatcher.idl @@ -13,4 +13,8 @@ interface XULCommandDispatcher { xpidl nsIController getControllerForCommand(in DOMString command); xpidl nsIControllers getControllers(); + + void advanceFocus(); + void rewindFocus(); + void advanceFocusIntoSubtree(in Element elt); }; diff --git a/dom/public/idl/xul/nsIDOMXULCommandDispatcher.idl b/dom/public/idl/xul/nsIDOMXULCommandDispatcher.idl index a442b524a417..a7291803f418 100644 --- a/dom/public/idl/xul/nsIDOMXULCommandDispatcher.idl +++ b/dom/public/idl/xul/nsIDOMXULCommandDispatcher.idl @@ -42,4 +42,8 @@ interface nsIDOMXULCommandDispatcher : nsISupports nsIController getControllerForCommand(in DOMString command); nsIControllers getControllers(); + + void advanceFocus(); + void rewindFocus(); + void advanceFocusIntoSubtree(in nsIDOMElement elt); }; diff --git a/dom/public/nsDOMPropEnums.h b/dom/public/nsDOMPropEnums.h index 108c7b5f0277..2d50dd39d074 100644 --- a/dom/public/nsDOMPropEnums.h +++ b/dom/public/nsDOMPropEnums.h @@ -1035,11 +1035,14 @@ enum nsDOMProp { NS_DOM_PROP_XMLHTTPREQUEST_OPEN, NS_DOM_PROP_XULCOMMANDDISPATCHER_ACTIVE, NS_DOM_PROP_XULCOMMANDDISPATCHER_ADDCOMMANDUPDATER, + NS_DOM_PROP_XULCOMMANDDISPATCHER_ADVANCEFOCUS, + NS_DOM_PROP_XULCOMMANDDISPATCHER_ADVANCEFOCUSINTOSUBTREE, NS_DOM_PROP_XULCOMMANDDISPATCHER_FOCUSEDELEMENT, NS_DOM_PROP_XULCOMMANDDISPATCHER_FOCUSEDWINDOW, NS_DOM_PROP_XULCOMMANDDISPATCHER_GETCONTROLLERFORCOMMAND, NS_DOM_PROP_XULCOMMANDDISPATCHER_GETCONTROLLERS, NS_DOM_PROP_XULCOMMANDDISPATCHER_REMOVECOMMANDUPDATER, + NS_DOM_PROP_XULCOMMANDDISPATCHER_REWINDFOCUS, NS_DOM_PROP_XULCOMMANDDISPATCHER_SUPPRESSFOCUS, NS_DOM_PROP_XULCOMMANDDISPATCHER_SUPPRESSFOCUSSCROLL, NS_DOM_PROP_XULCOMMANDDISPATCHER_UPDATECOMMANDS, diff --git a/dom/public/nsDOMPropNames.h b/dom/public/nsDOMPropNames.h index c36e3ff6c0d6..e619e1f57a1b 100644 --- a/dom/public/nsDOMPropNames.h +++ b/dom/public/nsDOMPropNames.h @@ -1033,11 +1033,14 @@ "xmlhttprequest.open", \ "xulcommanddispatcher.active", \ "xulcommanddispatcher.addcommandupdater", \ + "xulcommanddispatcher.advancefocus", \ + "xulcommanddispatcher.advancefocusintosubtree", \ "xulcommanddispatcher.focusedelement", \ "xulcommanddispatcher.focusedwindow", \ "xulcommanddispatcher.getcontrollerforcommand", \ "xulcommanddispatcher.getcontrollers", \ "xulcommanddispatcher.removecommandupdater", \ + "xulcommanddispatcher.rewindfocus", \ "xulcommanddispatcher.suppressfocus", \ "xulcommanddispatcher.suppressfocusscroll", \ "xulcommanddispatcher.updatecommands", \ diff --git a/dom/public/xul/nsIDOMXULCommandDispatcher.h b/dom/public/xul/nsIDOMXULCommandDispatcher.h index da396ca926e8..95c8f06386de 100644 --- a/dom/public/xul/nsIDOMXULCommandDispatcher.h +++ b/dom/public/xul/nsIDOMXULCommandDispatcher.h @@ -56,6 +56,12 @@ public: NS_IMETHOD GetControllerForCommand(const nsAReadableString& aCommand, nsIController** aReturn)=0; NS_IMETHOD GetControllers(nsIControllers** aReturn)=0; + + NS_IMETHOD AdvanceFocus()=0; + + NS_IMETHOD RewindFocus()=0; + + NS_IMETHOD AdvanceFocusIntoSubtree(nsIDOMElement* aElt)=0; }; @@ -69,6 +75,9 @@ public: NS_IMETHOD UpdateCommands(const nsAReadableString& aEventName); \ NS_IMETHOD GetControllerForCommand(const nsAReadableString& aCommand, nsIController** aReturn); \ NS_IMETHOD GetControllers(nsIControllers** aReturn); \ + NS_IMETHOD AdvanceFocus(); \ + NS_IMETHOD RewindFocus(); \ + NS_IMETHOD AdvanceFocusIntoSubtree(nsIDOMElement* aElt); \ @@ -82,6 +91,9 @@ public: NS_IMETHOD UpdateCommands(const nsAReadableString& aEventName) { return _to UpdateCommands(aEventName); } \ NS_IMETHOD GetControllerForCommand(const nsAReadableString& aCommand, nsIController** aReturn) { return _to GetControllerForCommand(aCommand, aReturn); } \ NS_IMETHOD GetControllers(nsIControllers** aReturn) { return _to GetControllers(aReturn); } \ + NS_IMETHOD AdvanceFocus() { return _to AdvanceFocus(); } \ + NS_IMETHOD RewindFocus() { return _to RewindFocus(); } \ + NS_IMETHOD AdvanceFocusIntoSubtree(nsIDOMElement* aElt) { return _to AdvanceFocusIntoSubtree(aElt); } \ extern "C" NS_DOM nsresult NS_InitXULCommandDispatcherClass(nsIScriptContext *aContext, void **aPrototype); diff --git a/dom/src/base/nsFocusController.cpp b/dom/src/base/nsFocusController.cpp index 562475737deb..293a15eb310d 100644 --- a/dom/src/base/nsFocusController.cpp +++ b/dom/src/base/nsFocusController.cpp @@ -37,6 +37,7 @@ #include "nsFocusController.h" #include "prlog.h" #include "nsIDOMEventTarget.h" +#include "nsIEventStateManager.h" #ifdef INCLUDE_XUL #include "nsIDOMXULDocument.h" @@ -165,6 +166,56 @@ nsFocusController::GetControllers(nsIControllers** aResult) return NS_OK; } +NS_IMETHODIMP +nsFocusController::MoveFocus(PRBool aForward, nsIDOMElement* aElt) +{ + // Obtain the doc that we'll be shifting focus inside. + nsCOMPtr doc; + nsCOMPtr content; + if (aElt) { + content = do_QueryInterface(aElt); + content->GetDocument(*getter_AddRefs(doc)); + } + else { + if (mCurrentElement) { + content = do_QueryInterface(mCurrentElement); + content->GetDocument(*getter_AddRefs(doc)); + content = nsnull; + } + else if (mCurrentWindow) { + nsCOMPtr domDoc; + mCurrentWindow->GetDocument(getter_AddRefs(domDoc)); + doc = do_QueryInterface(domDoc); + } + } + + if (!doc) + // No way to obtain an event state manager. Give up. + return NS_OK; + + + // Obtain a presentation context + PRInt32 count = doc->GetNumberOfShells(); + if (count == 0) + return NS_OK; + + nsCOMPtr shell(getter_AddRefs(doc->GetShellAt(0))); + if (!shell) + return NS_OK; + + // Retrieve the context + nsCOMPtr presContext; + shell->GetPresContext(getter_AddRefs(presContext)); + + nsCOMPtr esm; + presContext->GetEventStateManager(getter_AddRefs(esm)); + if (esm) + // Make this ESM shift the focus per our instructions. + esm->MoveFocus(aForward, content); + + return NS_OK; +} + ///// // nsIDOMFocusListener ///// diff --git a/dom/src/base/nsFocusController.h b/dom/src/base/nsFocusController.h index f431551f504d..844ade460ade 100644 --- a/dom/src/base/nsFocusController.h +++ b/dom/src/base/nsFocusController.h @@ -65,6 +65,8 @@ public: NS_IMETHOD GetControllerForCommand(const nsAReadableString& aCommand, nsIController** aResult); NS_IMETHOD GetControllers(nsIControllers** aResult); + NS_IMETHOD MoveFocus(PRBool aForward, nsIDOMElement* aElt); + // nsIDOMFocusListener virtual nsresult Focus(nsIDOMEvent* aEvent); virtual nsresult Blur(nsIDOMEvent* aEvent); diff --git a/dom/src/xul/nsJSXULCommandDispatcher.cpp b/dom/src/xul/nsJSXULCommandDispatcher.cpp index ae3868698fa2..07d515ac6324 100644 --- a/dom/src/xul/nsJSXULCommandDispatcher.cpp +++ b/dom/src/xul/nsJSXULCommandDispatcher.cpp @@ -445,6 +445,123 @@ XULCommandDispatcherGetControllers(JSContext *cx, JSObject *obj, uintN argc, jsv } +// +// Native method AdvanceFocus +// +PR_STATIC_CALLBACK(JSBool) +XULCommandDispatcherAdvanceFocus(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMXULCommandDispatcher *nativeThis = (nsIDOMXULCommandDispatcher*)nsJSUtils::nsGetNativeThis(cx, obj); + nsresult result = NS_OK; + // If there's no private data, this must be the prototype, so ignore + if (nsnull == nativeThis) { + return JS_TRUE; + } + + { + *rval = JSVAL_NULL; + nsIScriptSecurityManager *secMan = nsJSUtils::nsGetSecurityManager(cx, obj); + if (!secMan) + return PR_FALSE; + result = secMan->CheckScriptAccess(cx, obj, NS_DOM_PROP_XULCOMMANDDISPATCHER_ADVANCEFOCUS, PR_FALSE); + if (NS_FAILED(result)) { + return nsJSUtils::nsReportError(cx, obj, result); + } + + result = nativeThis->AdvanceFocus(); + if (NS_FAILED(result)) { + return nsJSUtils::nsReportError(cx, obj, result); + } + + *rval = JSVAL_VOID; + } + + return JS_TRUE; +} + + +// +// Native method RewindFocus +// +PR_STATIC_CALLBACK(JSBool) +XULCommandDispatcherRewindFocus(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMXULCommandDispatcher *nativeThis = (nsIDOMXULCommandDispatcher*)nsJSUtils::nsGetNativeThis(cx, obj); + nsresult result = NS_OK; + // If there's no private data, this must be the prototype, so ignore + if (nsnull == nativeThis) { + return JS_TRUE; + } + + { + *rval = JSVAL_NULL; + nsIScriptSecurityManager *secMan = nsJSUtils::nsGetSecurityManager(cx, obj); + if (!secMan) + return PR_FALSE; + result = secMan->CheckScriptAccess(cx, obj, NS_DOM_PROP_XULCOMMANDDISPATCHER_REWINDFOCUS, PR_FALSE); + if (NS_FAILED(result)) { + return nsJSUtils::nsReportError(cx, obj, result); + } + + result = nativeThis->RewindFocus(); + if (NS_FAILED(result)) { + return nsJSUtils::nsReportError(cx, obj, result); + } + + *rval = JSVAL_VOID; + } + + return JS_TRUE; +} + + +// +// Native method AdvanceFocusIntoSubtree +// +PR_STATIC_CALLBACK(JSBool) +XULCommandDispatcherAdvanceFocusIntoSubtree(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMXULCommandDispatcher *nativeThis = (nsIDOMXULCommandDispatcher*)nsJSUtils::nsGetNativeThis(cx, obj); + nsresult result = NS_OK; + nsCOMPtr b0; + // If there's no private data, this must be the prototype, so ignore + if (nsnull == nativeThis) { + return JS_TRUE; + } + + { + *rval = JSVAL_NULL; + nsIScriptSecurityManager *secMan = nsJSUtils::nsGetSecurityManager(cx, obj); + if (!secMan) + return PR_FALSE; + result = secMan->CheckScriptAccess(cx, obj, NS_DOM_PROP_XULCOMMANDDISPATCHER_ADVANCEFOCUSINTOSUBTREE, PR_FALSE); + if (NS_FAILED(result)) { + return nsJSUtils::nsReportError(cx, obj, result); + } + if (argc < 1) { + return nsJSUtils::nsReportError(cx, obj, NS_ERROR_DOM_TOO_FEW_PARAMETERS_ERR); + } + + if (JS_FALSE == nsJSUtils::nsConvertJSValToObject((nsISupports **)(void**)getter_AddRefs(b0), + kIElementIID, + NS_ConvertASCIItoUCS2("Element"), + cx, + argv[0])) { + return nsJSUtils::nsReportError(cx, obj, NS_ERROR_DOM_NOT_OBJECT_ERR); + } + + result = nativeThis->AdvanceFocusIntoSubtree(b0); + if (NS_FAILED(result)) { + return nsJSUtils::nsReportError(cx, obj, result); + } + + *rval = JSVAL_VOID; + } + + return JS_TRUE; +} + + /***********************************************************************/ // // class for XULCommandDispatcher @@ -475,6 +592,9 @@ static JSFunctionSpec XULCommandDispatcherMethods[] = {"updateCommands", XULCommandDispatcherUpdateCommands, 1}, {"getControllerForCommand", XULCommandDispatcherGetControllerForCommand, 1}, {"getControllers", XULCommandDispatcherGetControllers, 0}, + {"advanceFocus", XULCommandDispatcherAdvanceFocus, 0}, + {"rewindFocus", XULCommandDispatcherRewindFocus, 0}, + {"advanceFocusIntoSubtree", XULCommandDispatcherAdvanceFocusIntoSubtree, 1}, {0} };