Landing support for the special onItemClick default event handler that can be

placed on tree views (and executed in the context of tree items).
This commit is contained in:
hyatt%netscape.com 1999-02-24 10:38:56 +00:00
Родитель 55f16a9dd4
Коммит df9c54ab16
2 изменённых файлов: 153 добавлений и 8 удалений

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

@ -31,6 +31,15 @@
#include "nsXULAtoms.h" #include "nsXULAtoms.h"
#include "nsCOMPtr.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) static void ForceDrawFrame(nsIFrame * aFrame)
{ {
@ -165,6 +174,8 @@ nsTreeCellFrame::HandleEvent(nsIPresContext& aPresContext,
aEventStatus = nsEventStatus_eConsumeDoDefault; aEventStatus = nsEventStatus_eConsumeDoDefault;
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN)
HandleMouseDownEvent(aPresContext, aEvent, aEventStatus); HandleMouseDownEvent(aPresContext, aEvent, aEventStatus);
else if (aEvent->message == NS_MOUSE_LEFT_CLICK)
HandleClickEvent(aPresContext, aEvent, aEventStatus);
else if (aEvent->message == NS_MOUSE_LEFT_DOUBLECLICK) else if (aEvent->message == NS_MOUSE_LEFT_DOUBLECLICK)
HandleDoubleClickEvent(aPresContext, aEvent, aEventStatus); HandleDoubleClickEvent(aPresContext, aEvent, aEventStatus);
} }
@ -179,7 +190,7 @@ nsTreeCellFrame::HandleMouseDownEvent(nsIPresContext& aPresContext,
{ {
if (mIsHeader) if (mIsHeader)
{ {
// Toggle the sort state // Nothing to do?
} }
else else
{ {
@ -193,6 +204,31 @@ nsTreeCellFrame::HandleMouseDownEvent(nsIPresContext& aPresContext,
return NS_OK; 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 nsresult
nsTreeCellFrame::HandleDoubleClickEvent(nsIPresContext& aPresContext, nsTreeCellFrame::HandleDoubleClickEvent(nsIPresContext& aPresContext,
nsGUIEvent* aEvent, nsGUIEvent* aEvent,
@ -224,6 +260,8 @@ nsTreeCellFrame::HandleDoubleClickEvent(nsIPresContext& aPresContext,
} }
// Ok, try out the hack of doing frame reconstruction // Ok, try out the hack of doing frame reconstruction
// XXX: This needs to change
// XXX: Need to only do this for containers.
nsCOMPtr<nsIPresShell> pShell; nsCOMPtr<nsIPresShell> pShell;
aPresContext.GetShell(getter_AddRefs(pShell)); aPresContext.GetShell(getter_AddRefs(pShell));
nsCOMPtr<nsIStyleSet> pStyleSet; nsCOMPtr<nsIStyleSet> pStyleSet;
@ -252,8 +290,7 @@ nsTreeCellFrame::HandleDoubleClickEvent(nsIPresContext& aPresContext,
} }
void void nsTreeCellFrame::Select(nsIPresContext& aPresContext, PRBool isSelected, PRBool notifyForReflow)
nsTreeCellFrame::Select(nsIPresContext& aPresContext, PRBool isSelected, PRBool notifyForReflow)
{ {
nsCOMPtr<nsIAtom> kSelectedCellAtom(dont_AddRef(NS_NewAtom("selectedcell"))); nsCOMPtr<nsIAtom> kSelectedCellAtom(dont_AddRef(NS_NewAtom("selectedcell")));
nsCOMPtr<nsIAtom> kSelectedAtom(dont_AddRef(NS_NewAtom("selected"))); nsCOMPtr<nsIAtom> kSelectedAtom(dont_AddRef(NS_NewAtom("selected")));
@ -276,3 +313,106 @@ nsTreeCellFrame::Select(nsIPresContext& aPresContext, PRBool isSelected, PRBool
NS_IF_RELEASE(pParentContent); 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<nsIContent> treeitem;
nsCOMPtr<nsIContent> treebody;
nsCOMPtr<nsIContent> 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<nsIDocument> 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<nsIScriptContext> 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?
}

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

@ -53,13 +53,18 @@ protected:
virtual ~nsTreeCellFrame(); virtual ~nsTreeCellFrame();
nsresult HandleMouseDownEvent(nsIPresContext& aPresContext, nsresult HandleMouseDownEvent(nsIPresContext& aPresContext,
nsGUIEvent* aEvent, nsGUIEvent* aEvent,
nsEventStatus& aEventStatus); nsEventStatus& aEventStatus);
nsresult HandleDoubleClickEvent(nsIPresContext& aPresContext, nsresult HandleDoubleClickEvent(nsIPresContext& aPresContext,
nsGUIEvent* aEvent, nsGUIEvent* aEvent,
nsEventStatus& aEventStatus); nsEventStatus& aEventStatus);
nsresult HandleClickEvent(nsIPresContext& aPresContext,
nsGUIEvent* aEvent,
nsEventStatus& aEventStatus);
void ExecuteDefaultJSEventHandler(const nsString& eventName, nsIDOMEvent* aDOMEvent);
protected: protected:
// Data members // Data members