зеркало из 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 "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?
|
||||||
|
}
|
|
@ -60,6 +60,11 @@ protected:
|
||||||
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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче