diff --git a/layout/xul/base/src/nsTreeCellFrame.cpp b/layout/xul/base/src/nsTreeCellFrame.cpp index fa6ea5c5b800..0eed3dc60798 100644 --- a/layout/xul/base/src/nsTreeCellFrame.cpp +++ b/layout/xul/base/src/nsTreeCellFrame.cpp @@ -31,6 +31,15 @@ #include "nsXULAtoms.h" #include "nsCOMPtr.h" +// Includes related to the execution of custom JS event handlers +#include "nsIPrivateDOMEvent.h" +#include "nsIDOMEvent.h" +#include "nsIScriptContextOwner.h" +#include "nsIScriptContext.h" +#include "nsIScriptObjectOwner.h" +#include "nsIJSScriptObject.h" + +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); static void ForceDrawFrame(nsIFrame * aFrame) { @@ -165,6 +174,8 @@ nsTreeCellFrame::HandleEvent(nsIPresContext& aPresContext, aEventStatus = nsEventStatus_eConsumeDoDefault; if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) HandleMouseDownEvent(aPresContext, aEvent, aEventStatus); + else if (aEvent->message == NS_MOUSE_LEFT_CLICK) + HandleClickEvent(aPresContext, aEvent, aEventStatus); else if (aEvent->message == NS_MOUSE_LEFT_DOUBLECLICK) HandleDoubleClickEvent(aPresContext, aEvent, aEventStatus); } @@ -179,7 +190,7 @@ nsTreeCellFrame::HandleMouseDownEvent(nsIPresContext& aPresContext, { if (mIsHeader) { - // Toggle the sort state + // Nothing to do? } else { @@ -193,6 +204,31 @@ nsTreeCellFrame::HandleMouseDownEvent(nsIPresContext& aPresContext, return NS_OK; } +nsresult +nsTreeCellFrame::HandleClickEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus) +{ + if (mIsHeader) + { + // Nothing to do? + } + else + { + // Need to look for an "onItemClick" handler in the tree tag (our great-grandparent). + // If one exists, then we should execute the JavaScript code in the context of the + // treeitem (our parent). + // Create a DOM event from the nsGUIEvent that occurred. + nsIDOMEvent* aDOMEvent; + NS_NewDOMEvent(&aDOMEvent, aPresContext, aEvent); + ExecuteDefaultJSEventHandler("onitemclick", aDOMEvent); + // Release the DOM event. We don't care about it any more. + NS_IF_RELEASE(aDOMEvent); + } + return NS_OK; +} + + nsresult nsTreeCellFrame::HandleDoubleClickEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, @@ -224,6 +260,8 @@ nsTreeCellFrame::HandleDoubleClickEvent(nsIPresContext& aPresContext, } // Ok, try out the hack of doing frame reconstruction + // XXX: This needs to change + // XXX: Need to only do this for containers. nsCOMPtr pShell; aPresContext.GetShell(getter_AddRefs(pShell)); nsCOMPtr pStyleSet; @@ -252,8 +290,7 @@ nsTreeCellFrame::HandleDoubleClickEvent(nsIPresContext& aPresContext, } -void -nsTreeCellFrame::Select(nsIPresContext& aPresContext, PRBool isSelected, PRBool notifyForReflow) +void nsTreeCellFrame::Select(nsIPresContext& aPresContext, PRBool isSelected, PRBool notifyForReflow) { nsCOMPtr kSelectedCellAtom(dont_AddRef(NS_NewAtom("selectedcell"))); nsCOMPtr kSelectedAtom(dont_AddRef(NS_NewAtom("selected"))); @@ -276,3 +313,106 @@ nsTreeCellFrame::Select(nsIPresContext& aPresContext, PRBool isSelected, PRBool NS_IF_RELEASE(pParentContent); } + +const char* cEvent[] = {"event"}; + +void nsTreeCellFrame::ExecuteDefaultJSEventHandler(const nsString& eventName, + nsIDOMEvent* aDOMEvent) +{ + // Get our parent, grandparent, and great-grandparent nodes + nsCOMPtr treeitem; + nsCOMPtr treebody; + nsCOMPtr tree; + + mContent->GetParent(*(getter_AddRefs(treeitem))); + treeitem->GetParent(*(getter_AddRefs(treebody))); + treebody->GetParent(*(getter_AddRefs(tree))); + + // See if the attribute is even present on the tree node. + PRInt32 namespaceID; + tree->GetNameSpaceID(namespaceID); + nsIAtom* eventNameAtom = NS_NewAtom(eventName); + nsString codeText; + nsresult rv = tree->GetAttribute(namespaceID, eventNameAtom, codeText); + NS_IF_RELEASE(eventNameAtom); + + if (rv == NS_CONTENT_ATTR_HAS_VALUE) + { + // Compile/execute the JavaScript code in the context of the treeitem. + // XXX: Make this code more robust. Check for null pointers. + + // Retrieve our document. + nsCOMPtr document; + rv = tree->GetDocument(*getter_AddRefs(document)); + if (rv != NS_OK) + return; + + // Retrieve the script context owner for the document. + nsIScriptContextOwner* scriptContextOwner = document->GetScriptContextOwner(); + + // Retrieve the script context from the owner. + nsCOMPtr scriptContext; + rv = scriptContextOwner->GetScriptContext(getter_AddRefs(scriptContext)); + if (rv != NS_OK) + return; + + NS_IF_RELEASE(scriptContextOwner); + + // The TREEITEM is considered to be the script object owner. + nsIScriptObjectOwner* scriptObjectOwner; + if (treeitem->QueryInterface(kIScriptObjectOwnerIID, (void**) &scriptObjectOwner) != NS_OK) + return; + + // Obtain the script object from its owner. + JSObject* jsObject; + rv = scriptObjectOwner->GetScriptObject(scriptContext, (void**)&jsObject); + NS_IF_RELEASE(scriptObjectOwner); + if (rv != NS_OK) + return; + + // Obtain the JS native context + JSContext* jsContext = (JSContext*)scriptContext->GetNativeContext(); + + nsString lowerEventName; + eventName.ToLowerCase(lowerEventName); + + char* charName = lowerEventName.ToNewCString(); + + if (charName) + { + // Compile the function. + JS_CompileUCFunction(jsContext, jsObject, charName, + 1, cEvent, (jschar*)codeText.GetUnicode(), codeText.Length(), + nsnull, 0); + + // Execute the function. + jsval funval, result; + jsval argv[1]; + + if (!JS_LookupProperty(jsContext, jsObject, charName, &funval)) { + delete charName; + return; + } + + delete charName; + + if (JS_TypeOfValue(jsContext, funval) != JSTYPE_FUNCTION) { + return; + } + + JSObject* aEventObj; + nsIScriptContext *scriptCX = (nsIScriptContext *)JS_GetContextPrivate(jsContext); + if (NS_OK != NS_NewScriptEvent(scriptCX, aDOMEvent, nsnull, (void**)&aEventObj)) { + return; + } + + argv[0] = OBJECT_TO_JSVAL(aEventObj); + if (PR_TRUE == JS_CallFunctionValue(jsContext, jsObject, funval, 1, argv, &result)) { + if (JSVAL_IS_BOOLEAN(result) && JSVAL_TO_BOOLEAN(result) == JS_FALSE) { + return; // XXX: Denoted failure. Do I care? + } + return; // XXX: Denoted success. + } + } + } // XXX: Am I missing out on some necessary cleanup? +} \ No newline at end of file diff --git a/layout/xul/base/src/nsTreeCellFrame.h b/layout/xul/base/src/nsTreeCellFrame.h index fef6de963814..1d3b28c21e09 100644 --- a/layout/xul/base/src/nsTreeCellFrame.h +++ b/layout/xul/base/src/nsTreeCellFrame.h @@ -53,14 +53,19 @@ protected: virtual ~nsTreeCellFrame(); nsresult HandleMouseDownEvent(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsEventStatus& aEventStatus); + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus); nsresult HandleDoubleClickEvent(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsEventStatus& aEventStatus); + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus); + + nsresult HandleClickEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus); + + void ExecuteDefaultJSEventHandler(const nsString& eventName, nsIDOMEvent* aDOMEvent); - protected: // Data members PRBool mIsHeader; // Whether or not we're a column header