зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
55f16a9dd4
Коммит
df9c54ab16
|
@ -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<nsIPresShell> pShell;
|
||||
aPresContext.GetShell(getter_AddRefs(pShell));
|
||||
nsCOMPtr<nsIStyleSet> 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<nsIAtom> kSelectedCellAtom(dont_AddRef(NS_NewAtom("selectedcell")));
|
||||
nsCOMPtr<nsIAtom> 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<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?
|
||||
}
|
|
@ -60,6 +60,11 @@ protected:
|
|||
nsGUIEvent* aEvent,
|
||||
nsEventStatus& aEventStatus);
|
||||
|
||||
nsresult HandleClickEvent(nsIPresContext& aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus& aEventStatus);
|
||||
|
||||
void ExecuteDefaultJSEventHandler(const nsString& eventName, nsIDOMEvent* aDOMEvent);
|
||||
|
||||
protected:
|
||||
// Data members
|
||||
|
|
Загрузка…
Ссылка в новой задаче