зеркало из https://github.com/mozilla/gecko-dev.git
Bug 383930/552341, allow usage of a property on popups instead of using document.popupNode, should fix leak of popupNode, r=neil,sr=roc
This commit is contained in:
Родитель
c4ca33a0c8
Коммит
d20855b708
|
@ -221,18 +221,6 @@ nsXULPopupListener::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get the document with the popup.
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mElement);
|
||||
|
||||
// Turn the document into a XUL document so we can use SetPopupNode.
|
||||
nsCOMPtr<nsIDOMXULDocument> xulDocument = do_QueryInterface(content->GetDocument());
|
||||
if (!xulDocument) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Store clicked-on node in xul document for context menus and menu popups.
|
||||
xulDocument->SetPopupNode(targetNode);
|
||||
|
||||
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aMouseEvent));
|
||||
|
||||
if (mIsContext) {
|
||||
|
|
|
@ -378,7 +378,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULDocument, nsXMLDocument)
|
|||
cb.NoteXPCOMChild(static_cast<nsIScriptGlobalObjectOwner*>(tmp->mPrototypes[i]));
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTooltipNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLocalStore)
|
||||
|
||||
if (tmp->mOverlayLoadObservers.IsInitialized())
|
||||
|
@ -388,7 +387,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULDocument, nsXMLDocument)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULDocument, nsXMLDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTooltipNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsXULDocument, nsXMLDocument)
|
||||
|
@ -1527,26 +1525,23 @@ nsXULDocument::GetHeight(PRInt32* aHeight)
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::GetPopupNode(nsIDOMNode** aNode)
|
||||
{
|
||||
// Get popup node.
|
||||
nsresult rv = TrustedGetPopupNode(aNode); // addref happens here
|
||||
|
||||
if (NS_SUCCEEDED(rv) && *aNode && !nsContentUtils::CanCallerAccess(*aNode)) {
|
||||
NS_RELEASE(*aNode);
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::TrustedGetPopupNode(nsIDOMNode** aNode)
|
||||
{
|
||||
*aNode = nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
nsCOMPtr<nsPIWindowRoot> rootWin = GetWindowRoot();
|
||||
if (rootWin)
|
||||
rootWin->GetPopupNode(aNode); // addref happens here
|
||||
node = rootWin->GetPopupNode(); // addref happens here
|
||||
|
||||
if (!node) {
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm) {
|
||||
node = pm->GetLastTriggerPopupNode(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (node && nsContentUtils::CanCallerAccess(node))
|
||||
node.swap(*aNode);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1615,25 +1610,22 @@ nsXULDocument::GetPopupRangeOffset(PRInt32* aRangeOffset)
|
|||
NS_IMETHODIMP
|
||||
nsXULDocument::GetTooltipNode(nsIDOMNode** aNode)
|
||||
{
|
||||
if (mTooltipNode && !nsContentUtils::CanCallerAccess(mTooltipNode)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
*aNode = mTooltipNode;
|
||||
NS_IF_ADDREF(*aNode);
|
||||
return NS_OK;
|
||||
}
|
||||
*aNode = nsnull;
|
||||
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm) {
|
||||
nsCOMPtr<nsIDOMNode> node = pm->GetLastTriggerTooltipNode(this);
|
||||
if (node && nsContentUtils::CanCallerAccess(node))
|
||||
node.swap(*aNode);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::TrustedGetTooltipNode(nsIDOMNode** aNode)
|
||||
{
|
||||
NS_IF_ADDREF(*aNode = mTooltipNode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::SetTooltipNode(nsIDOMNode* aNode)
|
||||
{
|
||||
mTooltipNode = aNode;
|
||||
// do nothing
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=449457
|
|||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
/** Test for Bug 449457 **/
|
||||
document.tooltipNode = document;
|
||||
document.popupNode = document;
|
||||
ok(true, "This is just a leak test");
|
||||
|
||||
]]></script>
|
||||
|
|
|
@ -48,10 +48,10 @@ class nsIControllers;
|
|||
class nsIController;
|
||||
struct JSContext;
|
||||
|
||||
// 2e26a297-6e40-41c1-81c9-7306571f955e
|
||||
// 426C1B56-E38A-435E-B291-BE1557F2A0A2
|
||||
#define NS_IWINDOWROOT_IID \
|
||||
{ 0x2e26a297, 0x6e40, 0x41c1, \
|
||||
{ 0x81, 0xc9, 0x73, 0x06, 0x57, 0x1f, 0x95, 0x5e } }
|
||||
{ 0x426c1b56, 0xe38a, 0x435e, \
|
||||
{ 0xb2, 0x91, 0xbe, 0x15, 0x57, 0xf2, 0xa0, 0xa2 } }
|
||||
|
||||
class nsPIWindowRoot : public nsPIDOMEventTarget {
|
||||
public:
|
||||
|
@ -59,7 +59,8 @@ public:
|
|||
|
||||
virtual nsPIDOMWindow* GetWindow()=0;
|
||||
|
||||
virtual void GetPopupNode(nsIDOMNode** aNode) = 0;
|
||||
// get and set the node that is the context of a popup menu
|
||||
virtual nsIDOMNode* GetPopupNode() = 0;
|
||||
virtual void SetPopupNode(nsIDOMNode* aNode) = 0;
|
||||
|
||||
virtual nsresult GetControllerForCommand(const char *aCommand,
|
||||
|
|
|
@ -355,10 +355,10 @@ nsWindowRoot::GetControllerForCommand(const char * aCommand,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindowRoot::GetPopupNode(nsIDOMNode** aNode)
|
||||
nsIDOMNode*
|
||||
nsWindowRoot::GetPopupNode()
|
||||
{
|
||||
NS_IF_ADDREF(*aNode = mPopupNode);
|
||||
return mPopupNode;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -95,7 +95,7 @@ public:
|
|||
virtual nsresult GetControllerForCommand(const char * aCommand,
|
||||
nsIController** _retval);
|
||||
|
||||
virtual void GetPopupNode(nsIDOMNode** aNode);
|
||||
virtual nsIDOMNode* GetPopupNode();
|
||||
virtual void SetPopupNode(nsIDOMNode* aNode);
|
||||
|
||||
virtual void SetParentTarget(nsPIDOMEventTarget* aTarget)
|
||||
|
|
|
@ -43,7 +43,7 @@ interface nsIDOMXULCommandDispatcher;
|
|||
interface nsIObserver;
|
||||
interface nsIBoxObject;
|
||||
|
||||
[scriptable, uuid(d55c39B4-b54a-4df5-9e68-09919e4538f9)]
|
||||
[scriptable, uuid(b16d13c3-837d-445d-8f56-05d83d9b9eae)]
|
||||
interface nsIDOMXULDocument : nsISupports
|
||||
{
|
||||
attribute nsIDOMNode popupNode;
|
||||
|
@ -101,16 +101,4 @@ interface nsIDOMXULDocument : nsISupports
|
|||
* - Ben Goodger (8/23/2005)
|
||||
*/
|
||||
void loadOverlay(in DOMString url, in nsIObserver aObserver);
|
||||
|
||||
/**
|
||||
* Get the popup node from this XUL document without doing a security check to
|
||||
* make sure that the caller has access to this node. This is for use from C++
|
||||
* callers that can indirectly be called from content.
|
||||
*/
|
||||
[noscript] nsIDOMNode trustedGetPopupNode();
|
||||
|
||||
/**
|
||||
* Like trustedGetPopupNode, but gets the tooltip node instead.
|
||||
*/
|
||||
[noscript] nsIDOMNode trustedGetTooltipNode();
|
||||
};
|
||||
|
|
|
@ -3340,7 +3340,7 @@ DocumentViewerImpl::GetPopupNode(nsIDOMNode** aNode)
|
|||
NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
|
||||
|
||||
// get the popup node
|
||||
root->GetPopupNode(aNode); // addref happens here
|
||||
NS_IF_ADDREF(*aNode = root->GetPopupNode());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -40,8 +40,10 @@
|
|||
#include "nsIBoxObject.idl"
|
||||
|
||||
interface nsIDOMElement;
|
||||
interface nsIDOMNode;
|
||||
interface nsIDOMEvent;
|
||||
|
||||
[scriptable, uuid(88DC87BF-83EC-4F45-847A-E04C15DDA2FA)]
|
||||
[scriptable, uuid(e4c3845b-97d2-4fdf-860e-949746d15fb9)]
|
||||
interface nsIPopupBoxObject : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -136,12 +138,14 @@ interface nsIPopupBoxObject : nsISupports
|
|||
* @param y vertical offset
|
||||
* @param isContextMenu true for context menus, false for other popups
|
||||
* @param attributesOverride true if popup node attributes override position
|
||||
* @param triggerEvent the event that triggered this popup (mouse click for example)
|
||||
*/
|
||||
void openPopup(in nsIDOMElement anchorElement,
|
||||
in AString position,
|
||||
in long x, in long y,
|
||||
in boolean isContextMenu,
|
||||
in boolean attributesOverride);
|
||||
in boolean attributesOverride,
|
||||
in nsIDOMEvent triggerEvent);
|
||||
|
||||
/**
|
||||
* Open the popup at a specific screen position specified by x and y. This
|
||||
|
@ -153,8 +157,11 @@ interface nsIPopupBoxObject : nsISupports
|
|||
* @param isContextMenu true for context menus, false for other popups
|
||||
* @param x horizontal screen position
|
||||
* @param y vertical screen position
|
||||
* @param triggerEvent the event that triggered this popup (mouse click for example)
|
||||
*/
|
||||
void openPopupAtScreen(in long x, in long y, in boolean isContextMenu);
|
||||
void openPopupAtScreen(in long x, in long y,
|
||||
in boolean isContextMenu,
|
||||
in nsIDOMEvent triggerEvent);
|
||||
|
||||
/**
|
||||
* Returns the state of the popup:
|
||||
|
@ -164,6 +171,12 @@ interface nsIPopupBoxObject : nsISupports
|
|||
* hiding - the popup is in the process of being hidden
|
||||
*/
|
||||
readonly attribute AString popupState;
|
||||
|
||||
/**
|
||||
* The node that triggered the popup. If the popup is not open, will return
|
||||
* null.
|
||||
*/
|
||||
readonly attribute nsIDOMNode triggerNode;
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
|
|
@ -404,9 +404,8 @@ public:
|
|||
* similar to those for nsIPopupBoxObject::OpenPopup.
|
||||
*
|
||||
* aTriggerEvent should be the event that triggered the event. This is used
|
||||
* to determine the coordinates for the popupshowing event. This may be null
|
||||
* if the popup was not triggered by an event, or the coordinates are not
|
||||
* important. Note that this may be reworked in bug 383930.
|
||||
* to determine the coordinates and trigger node for the popup. This may be
|
||||
* null if the popup was not triggered by an event.
|
||||
*
|
||||
* This fires the popupshowing event synchronously.
|
||||
*/
|
||||
|
@ -518,6 +517,21 @@ public:
|
|||
*/
|
||||
nsTArray<nsIFrame *> GetVisiblePopups();
|
||||
|
||||
/**
|
||||
* Get the node that last triggered a popup or tooltip in the document
|
||||
* aDocument. aDocument must be non-null and be a document contained within
|
||||
* the same window hierarchy as the popup to retrieve.
|
||||
*/
|
||||
already_AddRefed<nsIDOMNode> GetLastTriggerPopupNode(nsIDocument* aDocument)
|
||||
{
|
||||
return GetLastTriggerNode(aDocument, PR_FALSE);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMNode> GetLastTriggerTooltipNode(nsIDocument* aDocument)
|
||||
{
|
||||
return GetLastTriggerNode(aDocument, PR_TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false if a popup may not be opened. This will return false if the
|
||||
* popup is already open, if the popup is in a content shell that is not
|
||||
|
@ -616,7 +630,7 @@ protected:
|
|||
nsMenuFrame* GetMenuFrameForContent(nsIContent* aContent);
|
||||
|
||||
// get the nsMenuPopupFrame, if any, for the given content node
|
||||
nsMenuPopupFrame* GetPopupFrameForContent(nsIContent* aContent);
|
||||
nsMenuPopupFrame* GetPopupFrameForContent(nsIContent* aContent, PRBool aShouldFlush);
|
||||
|
||||
// return the topmost menu, skipping over invisible popups
|
||||
nsMenuChainItem* GetTopVisibleMenu();
|
||||
|
@ -628,9 +642,9 @@ protected:
|
|||
void HidePopupsInList(const nsTArray<nsMenuPopupFrame *> &aFrames,
|
||||
PRBool aDeselectMenu);
|
||||
|
||||
// set the event that was used to trigger the popup, or null to
|
||||
// clear the event details.
|
||||
void SetTriggerEvent(nsIDOMEvent* aEvent, nsIContent* aPopup);
|
||||
// set the event that was used to trigger the popup, or null to clear the
|
||||
// event details. aTriggerContent will be set to the target of the event.
|
||||
void InitTriggerEvent(nsIDOMEvent* aEvent, nsIContent* aPopup, nsIContent** aTriggerContent);
|
||||
|
||||
// callbacks for ShowPopup and HidePopup as events may be done asynchronously
|
||||
void ShowPopupCallback(nsIContent* aPopup,
|
||||
|
@ -712,6 +726,8 @@ private:
|
|||
|
||||
protected:
|
||||
|
||||
already_AddRefed<nsIDOMNode> GetLastTriggerNode(nsIDocument* aDocument, PRBool aIsTooltip);
|
||||
|
||||
/**
|
||||
* Set mouse capturing for the current popup. This traps mouse clicks that
|
||||
* occur outside the popup so that it can be closed up. aOldPopup should be
|
||||
|
@ -764,6 +780,10 @@ protected:
|
|||
|
||||
// a popup that is waiting on the timer
|
||||
nsMenuPopupFrame* mTimerMenu;
|
||||
|
||||
// the popup that is currently being opened, stored only during the
|
||||
// popupshowing event
|
||||
nsCOMPtr<nsIContent> mOpeningPopup;
|
||||
};
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -6,8 +6,8 @@ function boom() {
|
|||
var x = a.popupBoxObject;
|
||||
a.parentNode.removeChild(a);
|
||||
x.enableKeyboardNavigator(true);
|
||||
x.openPopup(null, "after_start", 0, 0, false, false);
|
||||
x.openPopupAtScreen(2, 2, false);
|
||||
x.openPopup(null, "after_start", 0, 0, false, false, null);
|
||||
x.openPopupAtScreen(2, 2, false, null);
|
||||
x.showPopup(document.documentElement, a, -1, -1, "popup", "topleft", "topleft");
|
||||
x.hidePopup();
|
||||
document.documentElement.removeAttribute("class");
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
#include "nsIEventStateManager.h"
|
||||
#include "nsIBoxLayout.h"
|
||||
#include "nsIPopupBoxObject.h"
|
||||
#include "nsPIWindowRoot.h"
|
||||
#include "nsIReflowCallback.h"
|
||||
#include "nsBindingManager.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
|
@ -356,7 +357,7 @@ nsMenuPopupFrame::GetShadowStyle()
|
|||
return NS_STYLE_WINDOW_SHADOW_DEFAULT;
|
||||
}
|
||||
|
||||
// this class is used for dispatching popupshowing events asynchronously.
|
||||
// this class is used for dispatching popupshown events asynchronously.
|
||||
class nsXULPopupShownEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
|
@ -512,6 +513,8 @@ void
|
|||
nsMenuPopupFrame::InitPositionFromAnchorAlign(const nsAString& aAnchor,
|
||||
const nsAString& aAlign)
|
||||
{
|
||||
mTriggerContent = nsnull;
|
||||
|
||||
if (aAnchor.EqualsLiteral("topleft"))
|
||||
mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
|
||||
else if (aAnchor.EqualsLiteral("topright"))
|
||||
|
@ -537,6 +540,7 @@ nsMenuPopupFrame::InitPositionFromAnchorAlign(const nsAString& aAnchor,
|
|||
|
||||
void
|
||||
nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
|
||||
nsIContent* aTriggerContent,
|
||||
const nsAString& aPosition,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aAttributesOverride)
|
||||
|
@ -545,6 +549,7 @@ nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
|
|||
|
||||
mPopupState = ePopupShowing;
|
||||
mAnchorContent = aAnchorContent;
|
||||
mTriggerContent = aTriggerContent;
|
||||
mXPos = aXPos;
|
||||
mYPos = aYPos;
|
||||
mAdjustOffsetForContextMenu = PR_FALSE;
|
||||
|
@ -643,13 +648,15 @@ nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
|
|||
}
|
||||
|
||||
void
|
||||
nsMenuPopupFrame::InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos,
|
||||
nsMenuPopupFrame::InitializePopupAtScreen(nsIContent* aTriggerContent,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aIsContextMenu)
|
||||
{
|
||||
EnsureWidget();
|
||||
|
||||
mPopupState = ePopupShowing;
|
||||
mAnchorContent = nsnull;
|
||||
mTriggerContent = aTriggerContent;
|
||||
mScreenXPos = aXPos;
|
||||
mScreenYPos = aYPos;
|
||||
mPopupAnchor = POPUPALIGNMENT_NONE;
|
||||
|
@ -734,10 +741,10 @@ nsMenuPopupFrame::ShowPopup(PRBool aIsContextMenu, PRBool aSelectFirstItem)
|
|||
mPopupState = ePopupOpen;
|
||||
mIsOpenChanged = PR_TRUE;
|
||||
|
||||
nsIFrame* parent = GetParent();
|
||||
if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
|
||||
nsMenuFrame* menuFrame = GetParentMenu();
|
||||
if (menuFrame) {
|
||||
nsWeakFrame weakFrame(this);
|
||||
(static_cast<nsMenuFrame*>(parent))->PopupOpened();
|
||||
menuFrame->PopupOpened();
|
||||
if (!weakFrame.IsAlive())
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
@ -775,6 +782,27 @@ nsMenuPopupFrame::HidePopup(PRBool aDeselectMenu, nsPopupState aNewState)
|
|||
if (mPopupState == ePopupClosed || mPopupState == ePopupShowing)
|
||||
return;
|
||||
|
||||
// clear the trigger content if the popup is being closed. But don't clear
|
||||
// it if the popup is just being made invisible as a popuphiding or command
|
||||
// event may want to retrieve it.
|
||||
if (aNewState == ePopupClosed) {
|
||||
// if the popup had a trigger node set, clear the global window popup node
|
||||
// as well
|
||||
if (mTriggerContent) {
|
||||
nsIDocument* doc = mContent->GetCurrentDoc();
|
||||
if (doc) {
|
||||
nsPIDOMWindow* win = doc->GetWindow();
|
||||
if (win) {
|
||||
nsCOMPtr<nsPIWindowRoot> root = win->GetTopWindowRoot();
|
||||
if (root) {
|
||||
root->SetPopupNode(nsnull);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mTriggerContent = nsnull;
|
||||
}
|
||||
|
||||
// when invisible and about to be closed, HidePopup has already been called,
|
||||
// so just set the new state to closed and return
|
||||
if (mPopupState == ePopupInvisible) {
|
||||
|
@ -813,9 +841,9 @@ nsMenuPopupFrame::HidePopup(PRBool aDeselectMenu, nsPopupState aNewState)
|
|||
if (state & NS_EVENT_STATE_HOVER)
|
||||
esm->SetContentState(nsnull, NS_EVENT_STATE_HOVER);
|
||||
|
||||
nsIFrame* parent = GetParent();
|
||||
if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
|
||||
(static_cast<nsMenuFrame*>(parent))->PopupClosed(aDeselectMenu);
|
||||
nsMenuFrame* menuFrame = GetParentMenu();
|
||||
if (menuFrame) {
|
||||
menuFrame->PopupClosed(aDeselectMenu);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -230,6 +230,18 @@ public:
|
|||
PRBool IsMenu() { return mPopupType == ePopupTypeMenu; }
|
||||
PRBool IsOpen() { return mPopupState == ePopupOpen || mPopupState == ePopupOpenAndVisible; }
|
||||
|
||||
// returns the parent menupopup, if any
|
||||
nsMenuFrame* GetParentMenu() {
|
||||
nsIFrame* parent = GetParent();
|
||||
if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
|
||||
return static_cast<nsMenuFrame *>(parent);
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIContent* GetTriggerContent() { return mTriggerContent; }
|
||||
void SetTriggerContent(nsIContent* aTriggerContent) { mTriggerContent = aTriggerContent; }
|
||||
|
||||
// returns true if the popup is in a content shell, or false for a popup in
|
||||
// a chrome shell
|
||||
PRBool IsInContentShell() { return mInContentShell; }
|
||||
|
@ -237,6 +249,7 @@ public:
|
|||
// the Initialize methods are used to set the anchor position for
|
||||
// each way of opening a popup.
|
||||
void InitializePopup(nsIContent* aAnchorContent,
|
||||
nsIContent* aTriggerContent,
|
||||
const nsAString& aPosition,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aAttributesOverride);
|
||||
|
@ -246,7 +259,8 @@ public:
|
|||
* positioned at a slight offset from aXPos/aYPos to ensure the
|
||||
* (presumed) mouse position is not over the menu.
|
||||
*/
|
||||
void InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos,
|
||||
void InitializePopupAtScreen(nsIContent* aTriggerContent,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aIsContextMenu);
|
||||
|
||||
void InitializePopupWithAnchorAlign(nsIContent* aAnchorContent,
|
||||
|
@ -366,6 +380,10 @@ protected:
|
|||
// different document than the popup.
|
||||
nsCOMPtr<nsIContent> mAnchorContent;
|
||||
|
||||
// the content that triggered the popup, typically the node where the mouse
|
||||
// was clicked. It will be cleared when the popup is hidden.
|
||||
nsCOMPtr<nsIContent> mTriggerContent;
|
||||
|
||||
nsMenuFrame* mCurrentMenu; // The current menu that is active.
|
||||
|
||||
// A popup's preferred size may be different than its actual size stored in
|
||||
|
|
|
@ -124,24 +124,27 @@ nsPopupBoxObject::OpenPopup(nsIDOMElement* aAnchorElement,
|
|||
const nsAString& aPosition,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aIsContextMenu,
|
||||
PRBool aAttributesOverride)
|
||||
PRBool aAttributesOverride,
|
||||
nsIDOMEvent* aTriggerEvent)
|
||||
{
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm && mContent) {
|
||||
nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
|
||||
pm->ShowPopup(mContent, anchorContent, aPosition, aXPos, aYPos,
|
||||
aIsContextMenu, aAttributesOverride, PR_FALSE, nsnull);
|
||||
aIsContextMenu, aAttributesOverride, PR_FALSE, aTriggerEvent);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPopupBoxObject::OpenPopupAtScreen(PRInt32 aXPos, PRInt32 aYPos, PRBool aIsContextMenu)
|
||||
nsPopupBoxObject::OpenPopupAtScreen(PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aIsContextMenu,
|
||||
nsIDOMEvent* aTriggerEvent)
|
||||
{
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm && mContent)
|
||||
pm->ShowPopupAtScreen(mContent, aXPos, aYPos, aIsContextMenu, nsnull);
|
||||
pm->ShowPopupAtScreen(mContent, aXPos, aYPos, aIsContextMenu, aTriggerEvent);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -260,6 +263,33 @@ nsPopupBoxObject::GetPopupState(nsAString& aState)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPopupBoxObject::GetTriggerNode(nsIDOMNode** aTriggerNode)
|
||||
{
|
||||
*aTriggerNode = nsnull;
|
||||
|
||||
nsMenuPopupFrame *menuPopupFrame = GetMenuPopupFrame();
|
||||
while (menuPopupFrame) {
|
||||
nsIContent* triggerContent = menuPopupFrame->GetTriggerContent();
|
||||
if (triggerContent) {
|
||||
CallQueryInterface(triggerContent, aTriggerNode);
|
||||
break;
|
||||
}
|
||||
|
||||
// check up the menu hierarchy until a popup with a trigger node is found
|
||||
nsMenuFrame* menuFrame = menuPopupFrame->GetParentMenu();
|
||||
if (!menuFrame)
|
||||
break;
|
||||
|
||||
nsMenuParent* parentPopup = menuFrame->GetMenuParent();
|
||||
if (!parentPopup || !parentPopup->IsMenu())
|
||||
break;
|
||||
|
||||
menuPopupFrame = static_cast<nsMenuPopupFrame *>(parentPopup);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Creation Routine ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "nsIDOMNSEvent.h"
|
||||
#include "nsIDOMNSUIEvent.h"
|
||||
#include "nsIDOMXULElement.h"
|
||||
#include "nsIXULDocument.h"
|
||||
#include "nsIXULTemplateBuilder.h"
|
||||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
|
@ -67,6 +68,7 @@
|
|||
#include "nsCaret.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsPIWindowRoot.h"
|
||||
#include "nsFrameManager.h"
|
||||
|
||||
const nsNavigationDirection DirectionFromKeyCodeTable[2][6] = {
|
||||
|
@ -379,10 +381,10 @@ nsXULPopupManager::GetMenuFrameForContent(nsIContent* aContent)
|
|||
}
|
||||
|
||||
nsMenuPopupFrame*
|
||||
nsXULPopupManager::GetPopupFrameForContent(nsIContent* aContent)
|
||||
nsXULPopupManager::GetPopupFrameForContent(nsIContent* aContent, PRBool aShouldFlush)
|
||||
{
|
||||
return static_cast<nsMenuPopupFrame *>
|
||||
(GetFrameOfTypeForContent(aContent, nsGkAtoms::menuPopupFrame, PR_TRUE));
|
||||
(GetFrameOfTypeForContent(aContent, nsGkAtoms::menuPopupFrame, aShouldFlush));
|
||||
}
|
||||
|
||||
nsMenuChainItem*
|
||||
|
@ -403,10 +405,23 @@ nsXULPopupManager::GetMouseLocation(nsIDOMNode** aNode, PRInt32* aOffset)
|
|||
}
|
||||
|
||||
void
|
||||
nsXULPopupManager::SetTriggerEvent(nsIDOMEvent* aEvent, nsIContent* aPopup)
|
||||
nsXULPopupManager::InitTriggerEvent(nsIDOMEvent* aEvent, nsIContent* aPopup,
|
||||
nsIContent** aTriggerContent)
|
||||
{
|
||||
mCachedMousePoint = nsIntPoint(0, 0);
|
||||
|
||||
if (aTriggerContent) {
|
||||
*aTriggerContent = nsnull;
|
||||
if (aEvent) {
|
||||
// get the trigger content from the event
|
||||
nsCOMPtr<nsIDOMEventTarget> target;
|
||||
aEvent->GetTarget(getter_AddRefs(target));
|
||||
if (target) {
|
||||
CallQueryInterface(target, aTriggerContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(aEvent);
|
||||
if (uiEvent) {
|
||||
uiEvent->GetRangeParent(getter_AddRefs(mRangeParent));
|
||||
|
@ -524,10 +539,12 @@ nsXULPopupManager::ShowMenu(nsIContent *aMenu,
|
|||
position.AssignLiteral("after_start");
|
||||
else
|
||||
position.AssignLiteral("end_before");
|
||||
popupFrame->InitializePopup(aMenu, position, 0, 0, PR_TRUE);
|
||||
|
||||
popupFrame->InitializePopup(aMenu, nsnull, position, 0, 0, PR_TRUE);
|
||||
|
||||
if (aAsynchronous) {
|
||||
SetTriggerEvent(nsnull, nsnull);
|
||||
// there is no trigger event for menus
|
||||
InitTriggerEvent(nsnull, nsnull, nsnull);
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new nsXULPopupShowingEvent(popupFrame->GetContent(), aMenu, popupFrame->PopupType(),
|
||||
parentIsContextMenu, aSelectFirstItem);
|
||||
|
@ -551,14 +568,15 @@ nsXULPopupManager::ShowPopup(nsIContent* aPopup,
|
|||
PRBool aSelectFirstItem,
|
||||
nsIDOMEvent* aTriggerEvent)
|
||||
{
|
||||
nsMenuPopupFrame* popupFrame = GetPopupFrameForContent(aPopup);
|
||||
nsMenuPopupFrame* popupFrame = GetPopupFrameForContent(aPopup, PR_TRUE);
|
||||
if (!popupFrame || !MayShowPopup(popupFrame))
|
||||
return;
|
||||
|
||||
SetTriggerEvent(aTriggerEvent, aPopup);
|
||||
nsCOMPtr<nsIContent> triggerContent;
|
||||
InitTriggerEvent(aTriggerEvent, aPopup, getter_AddRefs(triggerContent));
|
||||
|
||||
popupFrame->InitializePopup(aAnchorContent, aPosition, aXPos, aYPos,
|
||||
aAttributesOverride);
|
||||
popupFrame->InitializePopup(aAnchorContent, triggerContent, aPosition,
|
||||
aXPos, aYPos, aAttributesOverride);
|
||||
|
||||
FirePopupShowingEvent(aPopup, nsnull, popupFrame->PresContext(),
|
||||
popupFrame->PopupType(), aIsContextMenu, aSelectFirstItem);
|
||||
|
@ -570,13 +588,14 @@ nsXULPopupManager::ShowPopupAtScreen(nsIContent* aPopup,
|
|||
PRBool aIsContextMenu,
|
||||
nsIDOMEvent* aTriggerEvent)
|
||||
{
|
||||
nsMenuPopupFrame* popupFrame = GetPopupFrameForContent(aPopup);
|
||||
nsMenuPopupFrame* popupFrame = GetPopupFrameForContent(aPopup, PR_TRUE);
|
||||
if (!popupFrame || !MayShowPopup(popupFrame))
|
||||
return;
|
||||
|
||||
SetTriggerEvent(aTriggerEvent, aPopup);
|
||||
nsCOMPtr<nsIContent> triggerContent;
|
||||
InitTriggerEvent(aTriggerEvent, aPopup, getter_AddRefs(triggerContent));
|
||||
|
||||
popupFrame->InitializePopupAtScreen(aXPos, aYPos, aIsContextMenu);
|
||||
popupFrame->InitializePopupAtScreen(triggerContent, aXPos, aYPos, aIsContextMenu);
|
||||
|
||||
FirePopupShowingEvent(aPopup, nsnull, popupFrame->PresContext(),
|
||||
popupFrame->PopupType(), aIsContextMenu, PR_FALSE);
|
||||
|
@ -590,11 +609,11 @@ nsXULPopupManager::ShowPopupWithAnchorAlign(nsIContent* aPopup,
|
|||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aIsContextMenu)
|
||||
{
|
||||
nsMenuPopupFrame* popupFrame = GetPopupFrameForContent(aPopup);
|
||||
nsMenuPopupFrame* popupFrame = GetPopupFrameForContent(aPopup, PR_TRUE);
|
||||
if (!popupFrame || !MayShowPopup(popupFrame))
|
||||
return;
|
||||
|
||||
SetTriggerEvent(nsnull, nsnull);
|
||||
InitTriggerEvent(nsnull, aPopup, nsnull);
|
||||
|
||||
popupFrame->InitializePopupWithAnchorAlign(aAnchorContent, aAnchor,
|
||||
aAlign, aXPos, aYPos);
|
||||
|
@ -641,10 +660,6 @@ nsXULPopupManager::ShowPopupCallback(nsIContent* aPopup,
|
|||
PRBool aIsContextMenu,
|
||||
PRBool aSelectFirstItem)
|
||||
{
|
||||
// clear these as they are no longer valid
|
||||
mRangeParent = nsnull;
|
||||
mRangeOffset = 0;
|
||||
|
||||
nsPopupType popupType = aPopupFrame->PopupType();
|
||||
PRBool ismenu = (popupType == ePopupTypeMenu);
|
||||
|
||||
|
@ -663,9 +678,8 @@ nsXULPopupManager::ShowPopupCallback(nsIContent* aPopup,
|
|||
|
||||
if (ismenu) {
|
||||
// if the menu is on a menubar, use the menubar's listener instead
|
||||
nsIFrame* parent = aPopupFrame->GetParent();
|
||||
if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
|
||||
nsMenuFrame* menuFrame = static_cast<nsMenuFrame *>(parent);
|
||||
nsMenuFrame* menuFrame = aPopupFrame->GetParentMenu();
|
||||
if (menuFrame) {
|
||||
item->SetOnMenuBar(menuFrame->IsOnMenuBar());
|
||||
}
|
||||
}
|
||||
|
@ -800,7 +814,7 @@ nsXULPopupManager::HidePopup(nsIContent* aPopup,
|
|||
if (state != ePopupInvisible)
|
||||
popupFrame->SetPopupState(ePopupHiding);
|
||||
|
||||
// for menus, popupToHide is always the frommost item in the list to hide.
|
||||
// for menus, popupToHide is always the frontmost item in the list to hide.
|
||||
if (aAsynchronous) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new nsXULPopupHidingEvent(popupToHide, nextPopup, lastPopup,
|
||||
|
@ -1075,11 +1089,11 @@ nsXULPopupManager::FirePopupShowingEvent(nsIContent* aPopup,
|
|||
{
|
||||
nsCOMPtr<nsIPresShell> presShell = aPresContext->PresShell();
|
||||
|
||||
// XXXndeakin (bug 383930)
|
||||
// eventually, the popup events will be a different event type with
|
||||
// additional fields for the anchor node and position and so forth. This
|
||||
// is where those details would be retrieved. This removes the need for
|
||||
// all the globals people keep adding to nsIDOMXULDocument.
|
||||
// cache the popup so that document.popupNode can retrieve the trigger node
|
||||
// during the popupshowing event. It will be cleared below after the event
|
||||
// has fired.
|
||||
mOpeningPopup = aPopup;
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_SHOWING, nsnull, nsMouseEvent::eReal);
|
||||
|
||||
|
@ -1097,6 +1111,7 @@ nsXULPopupManager::FirePopupShowingEvent(nsIContent* aPopup,
|
|||
event.refPoint = mCachedMousePoint;
|
||||
nsEventDispatcher::Dispatch(aPopup, aPresContext, &event, nsnull, &status);
|
||||
mCachedMousePoint = nsIntPoint(0, 0);
|
||||
mOpeningPopup = nsnull;
|
||||
|
||||
// if a panel, blur whatever has focus so that the panel can take the focus.
|
||||
// This is done after the popupshowing event in case that event is cancelled.
|
||||
|
@ -1133,15 +1148,20 @@ nsXULPopupManager::FirePopupShowingEvent(nsIContent* aPopup,
|
|||
if (document)
|
||||
document->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
// clear these as they are no longer valid
|
||||
mRangeParent = nsnull;
|
||||
mRangeOffset = 0;
|
||||
|
||||
// get the frame again in case it went away
|
||||
nsIFrame* frame = aPopup->GetPrimaryFrame();
|
||||
if (frame && frame->GetType() == nsGkAtoms::menuPopupFrame) {
|
||||
nsMenuPopupFrame* popupFrame = static_cast<nsMenuPopupFrame *>(frame);
|
||||
|
||||
// if the event was cancelled, don't open the popup, and reset it's
|
||||
// state back to closed
|
||||
// if the event was cancelled, don't open the popup, reset its state back
|
||||
// to closed and clear its trigger content.
|
||||
if (status == nsEventStatus_eConsumeNoDefault) {
|
||||
popupFrame->SetPopupState(ePopupClosed);
|
||||
popupFrame->SetTriggerContent(nsnull);
|
||||
}
|
||||
else {
|
||||
ShowPopupCallback(aPopup, popupFrame, aIsContextMenu, aSelectFirstItem);
|
||||
|
@ -1187,7 +1207,7 @@ nsXULPopupManager::FirePopupHidingEvent(nsIContent* aPopup,
|
|||
if (frame && frame->GetType() == nsGkAtoms::menuPopupFrame) {
|
||||
nsMenuPopupFrame* popupFrame = static_cast<nsMenuPopupFrame *>(frame);
|
||||
|
||||
// if the event was cancelled, don't hide the popup, and reset it's
|
||||
// if the event was cancelled, don't hide the popup, and reset its
|
||||
// state back to open. Only popups in chrome shells can prevent a popup
|
||||
// from hiding.
|
||||
if (status == nsEventStatus_eConsumeNoDefault &&
|
||||
|
@ -1241,11 +1261,9 @@ nsXULPopupManager::IsPopupOpenForMenuParent(nsMenuParent* aMenuParent)
|
|||
while (item) {
|
||||
nsMenuPopupFrame* popup = item->Frame();
|
||||
if (popup && popup->IsOpen()) {
|
||||
nsIFrame* parent = popup->GetParent();
|
||||
if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
|
||||
nsMenuFrame* menuFrame = static_cast<nsMenuFrame *>(parent);
|
||||
if (menuFrame->GetMenuParent() == aMenuParent)
|
||||
return PR_TRUE;
|
||||
nsMenuFrame* menuFrame = popup->GetParentMenu();
|
||||
if (menuFrame && menuFrame->GetMenuParent() == aMenuParent) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
item = item->GetParent();
|
||||
|
@ -1257,7 +1275,7 @@ nsXULPopupManager::IsPopupOpenForMenuParent(nsMenuParent* aMenuParent)
|
|||
nsIFrame*
|
||||
nsXULPopupManager::GetTopPopup(nsPopupType aType)
|
||||
{
|
||||
if (aType == ePopupTypePanel && mNoHidePanels)
|
||||
if ((aType == ePopupTypePanel || aType == ePopupTypeTooltip) && mNoHidePanels)
|
||||
return mNoHidePanels->Frame();
|
||||
|
||||
nsMenuChainItem* item = GetTopVisibleMenu();
|
||||
|
@ -1292,6 +1310,39 @@ nsXULPopupManager::GetVisiblePopups()
|
|||
return popups;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMNode>
|
||||
nsXULPopupManager::GetLastTriggerNode(nsIDocument* aDocument, PRBool aIsTooltip)
|
||||
{
|
||||
if (!aDocument)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
|
||||
// if mOpeningPopup is set, it means that a popupshowing event is being
|
||||
// fired. In this case, just use the cached node, as the popup is not yet in
|
||||
// the list of open popups.
|
||||
if (mOpeningPopup && mOpeningPopup->GetCurrentDoc() == aDocument &&
|
||||
aIsTooltip == (mOpeningPopup->Tag() == nsGkAtoms::tooltip)) {
|
||||
nsMenuPopupFrame* popupFrame = GetPopupFrameForContent(mOpeningPopup, PR_FALSE);
|
||||
if (popupFrame)
|
||||
node = do_QueryInterface(popupFrame->GetTriggerContent());
|
||||
}
|
||||
else {
|
||||
nsMenuChainItem* item = aIsTooltip ? mNoHidePanels : mPopups;
|
||||
while (item) {
|
||||
// look for a popup of the same type and document.
|
||||
if ((item->PopupType() == ePopupTypeTooltip) == aIsTooltip &&
|
||||
item->Content()->GetCurrentDoc() == aDocument) {
|
||||
node = do_QueryInterface(item->Frame()->GetTriggerContent());
|
||||
break;
|
||||
}
|
||||
item = item->GetParent();
|
||||
}
|
||||
}
|
||||
|
||||
return node.forget();
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsXULPopupManager::MayShowPopup(nsMenuPopupFrame* aPopup)
|
||||
{
|
||||
|
@ -1370,9 +1421,8 @@ nsXULPopupManager::MayShowPopup(nsMenuPopupFrame* aPopup)
|
|||
}
|
||||
|
||||
// cannot open a popup that is a submenu of a menupopup that isn't open.
|
||||
nsIFrame* parent = aPopup->GetParent();
|
||||
if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
|
||||
nsMenuFrame* menuFrame = static_cast<nsMenuFrame *>(parent);
|
||||
nsMenuFrame* menuFrame = aPopup->GetParentMenu();
|
||||
if (menuFrame) {
|
||||
nsMenuParent* parentPopup = menuFrame->GetMenuParent();
|
||||
if (parentPopup && !parentPopup->IsOpen())
|
||||
return PR_FALSE;
|
||||
|
@ -1702,13 +1752,8 @@ nsXULPopupManager::HandleKeyboardNavigation(PRUint32 aKeyCode)
|
|||
// be if the parent is in a different frame hierarchy, for example, for a
|
||||
// context menu opened on another menu.
|
||||
nsMenuParent* expectedParent = static_cast<nsMenuParent *>(nextitem->Frame());
|
||||
nsIFrame* parent = item->Frame()->GetParent();
|
||||
if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
|
||||
nsMenuFrame* menuFrame = static_cast<nsMenuFrame *>(parent);
|
||||
if (menuFrame->GetMenuParent() != expectedParent)
|
||||
break;
|
||||
}
|
||||
else {
|
||||
nsMenuFrame* menuFrame = item->Frame()->GetParentMenu();
|
||||
if (!menuFrame || menuFrame->GetMenuParent() != expectedParent) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "nsGkAtoms.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIPopupBoxObject.h"
|
||||
#include "nsMenuPopupFrame.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsIDOMNSDocument.h"
|
||||
|
@ -156,6 +157,7 @@ nsXULTooltipListener::MouseOut(nsIDOMEvent* aMouseEvent)
|
|||
return NS_OK;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
// check to see if the mouse left the targetNode, and if so,
|
||||
// hide the tooltip
|
||||
if (currentTooltip) {
|
||||
|
@ -164,26 +166,23 @@ nsXULTooltipListener::MouseOut(nsIDOMEvent* aMouseEvent)
|
|||
aMouseEvent->GetTarget(getter_AddRefs(eventTarget));
|
||||
nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(eventTarget));
|
||||
|
||||
// which node is our tooltip on?
|
||||
nsCOMPtr<nsIDOMXULDocument> xulDoc(do_QueryInterface(currentTooltip->GetDocument()));
|
||||
if (!xulDoc) // remotely possible someone could have
|
||||
return NS_OK; // removed tooltip from dom while it was open
|
||||
nsCOMPtr<nsIDOMNode> tooltipNode;
|
||||
xulDoc->TrustedGetTooltipNode (getter_AddRefs(tooltipNode));
|
||||
|
||||
// if they're the same, the mouse left the node the tooltip appeared on,
|
||||
// close the tooltip.
|
||||
if (tooltipNode == targetNode) {
|
||||
HideTooltip();
|
||||
#ifdef MOZ_XUL
|
||||
// reset special tree tracking
|
||||
if (mIsSourceTree) {
|
||||
mLastTreeRow = -1;
|
||||
mLastTreeCol = nsnull;
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm) {
|
||||
nsCOMPtr<nsIDOMNode> tooltipNode =
|
||||
pm->GetLastTriggerTooltipNode(currentTooltip->GetCurrentDoc());
|
||||
if (tooltipNode == targetNode) {
|
||||
// if the target node is the current tooltip target node, the mouse
|
||||
// left the node the tooltip appeared on, so close the tooltip.
|
||||
HideTooltip();
|
||||
// reset special tree tracking
|
||||
if (mIsSourceTree) {
|
||||
mLastTreeRow = -1;
|
||||
mLastTreeCol = nsnull;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -449,8 +448,6 @@ nsXULTooltipListener::ShowTooltip()
|
|||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIDOMNode> targetNode = do_QueryReferent(mTargetNode);
|
||||
xulDoc->SetTooltipNode(targetNode);
|
||||
mCurrentTooltip = do_GetWeakReference(tooltipNode);
|
||||
LaunchTooltip();
|
||||
mTargetNode = nsnull;
|
||||
|
@ -707,10 +704,6 @@ nsXULTooltipListener::DestroyTooltip()
|
|||
// clear out the tooltip node on the document
|
||||
nsCOMPtr<nsIDocument> doc = currentTooltip->GetDocument();
|
||||
if (doc) {
|
||||
nsCOMPtr<nsIDOMXULDocument> xulDoc(do_QueryInterface(doc));
|
||||
if (xulDoc)
|
||||
xulDoc->SetTooltipNode(nsnull);
|
||||
|
||||
// remove the mousedown and keydown listener from document
|
||||
nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(doc));
|
||||
evtTarget->RemoveEventListener(NS_LITERAL_STRING("DOMMouseScroll"), static_cast<nsIDOMMouseListener*>(this), PR_TRUE);
|
||||
|
|
|
@ -75,6 +75,7 @@ _TEST_FILES = test_bug360220.xul \
|
|||
popup_trigger.js \
|
||||
window_popup_button.xul \
|
||||
window_popup_attribute.xul \
|
||||
popup_childframe_node.xul \
|
||||
test_tooltip.xul \
|
||||
test_progressmeter.xul \
|
||||
test_props.xul \
|
||||
|
@ -115,6 +116,7 @@ _TEST_FILES = test_bug360220.xul \
|
|||
test_scrollbar.xul \
|
||||
test_sorttemplate.xul \
|
||||
test_contextmenu_list.xul \
|
||||
test_contextmenu_nested.xul \
|
||||
test_videocontrols.html \
|
||||
test_richlist_direction.xul \
|
||||
test_videocontrols_video_direction.html \
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" width="80" height="80"
|
||||
onclick="document.documentElement.setAttribute('data', 'x' + document.popupNode)"/>
|
|
@ -34,6 +34,7 @@ var gTestStepIndex = 0;
|
|||
var gTestEventIndex = 0;
|
||||
var gAutoHide = false;
|
||||
var gExpectedEventDetails = null;
|
||||
var gExpectedTriggerNode = null;
|
||||
var gWindowUtils;
|
||||
|
||||
function startPopupTests(tests)
|
||||
|
@ -139,6 +140,18 @@ function eventOccurred(event)
|
|||
case "popuphidden": expectedState = "closed"; break;
|
||||
}
|
||||
|
||||
if (gExpectedTriggerNode && event.type == "popupshowing") {
|
||||
if (gExpectedTriggerNode == "notset") // check against null instead
|
||||
gExpectedTriggerNode = null;
|
||||
|
||||
is(event.originalTarget.triggerNode, gExpectedTriggerNode, test.testname + " popupshowing triggerNode");
|
||||
var isTooltip = (event.target.localName == "tooltip");
|
||||
is(document.popupNode, isTooltip ? null : gExpectedTriggerNode,
|
||||
test.testname + " popupshowing document.popupNode");
|
||||
is(document.tooltipNode, isTooltip ? gExpectedTriggerNode : null,
|
||||
test.testname + " popupshowing document.tooltipNode");
|
||||
}
|
||||
|
||||
if (expectedState)
|
||||
is(event.originalTarget.state, expectedState,
|
||||
test.testname + " " + event.type + " state");
|
||||
|
|
|
@ -2,6 +2,7 @@ var gMenuPopup = null;
|
|||
var gTrigger = null;
|
||||
var gIsMenu = false;
|
||||
var gScreenX = -1, gScreenY = -1;
|
||||
var gCachedEvent = null;
|
||||
|
||||
function runTests()
|
||||
{
|
||||
|
@ -17,6 +18,8 @@ function runTests()
|
|||
var mouseFn = function(event) {
|
||||
gScreenX = event.screenX;
|
||||
gScreenY = event.screenY;
|
||||
// cache the event so that we can use it in calls to openPopup
|
||||
gCachedEvent = event;
|
||||
}
|
||||
|
||||
// a hacky way to get the screen position of the document
|
||||
|
@ -30,8 +33,21 @@ var popupTests = [
|
|||
{
|
||||
testname: "mouse click on trigger",
|
||||
events: [ "popupshowing thepopup", "popupshown thepopup" ],
|
||||
test: function() { synthesizeMouse(gTrigger, 4, 4, { }); },
|
||||
test: function() {
|
||||
// for menus, no trigger will be set. For non-menus using the popup
|
||||
// attribute, the trigger will be set to the node with the popup attribute
|
||||
gExpectedTriggerNode = gIsMenu ? "notset" : gTrigger;
|
||||
synthesizeMouse(gTrigger, 4, 4, { });
|
||||
},
|
||||
result: function (testname) {
|
||||
gExpectedTriggerNode = null;
|
||||
is(gMenuPopup.triggerNode, gIsMenu ? null : gTrigger, testname + " triggerNode");
|
||||
is(document.popupNode, gIsMenu ? null : gTrigger, testname + " document.popupNode");
|
||||
is(document.tooltipNode, null, testname + " document.tooltipNode");
|
||||
// check to ensure the popup node for a different document isn't used
|
||||
if (window.opener)
|
||||
is(window.opener.document.popupNode, null, testname + " opener.document.popupNode");
|
||||
|
||||
checkActive(gMenuPopup, "", testname);
|
||||
checkOpen("trigger", testname);
|
||||
// if a menu, the popup should be opened underneath the menu in the
|
||||
|
@ -136,7 +152,11 @@ var popupTests = [
|
|||
// rollup this way.
|
||||
// synthesizeMouse(gTrigger, 0, -12, { });
|
||||
},
|
||||
result: function(testname, step) { checkClosed("trigger", testname); }
|
||||
result: function(testname, step) {
|
||||
is(gMenuPopup.triggerNode, null, testname + " triggerNode");
|
||||
is(document.popupNode, null, testname + " document.popupNode");
|
||||
checkClosed("trigger", testname);
|
||||
}
|
||||
},
|
||||
{
|
||||
// these tests check to ensure that passing an anchor and position
|
||||
|
@ -146,8 +166,17 @@ var popupTests = [
|
|||
autohide: "thepopup",
|
||||
steps: ["before_start", "before_end", "after_start", "after_end",
|
||||
"start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap"],
|
||||
test: function(testname, step) { gMenuPopup.openPopup(gTrigger, step, 0, 0, false, false); },
|
||||
result: function(testname, step) { compareEdge(gTrigger, gMenuPopup, step, 0, 0, testname); }
|
||||
test: function(testname, step) {
|
||||
gExpectedTriggerNode = "notset";
|
||||
gMenuPopup.openPopup(gTrigger, step, 0, 0, false, false);
|
||||
},
|
||||
result: function(testname, step) {
|
||||
// no triggerNode because it was opened without passing an event
|
||||
gExpectedTriggerNode = null;
|
||||
is(gMenuPopup.triggerNode, null, testname + " triggerNode");
|
||||
is(document.popupNode, null, testname + " document.popupNode");
|
||||
compareEdge(gTrigger, gMenuPopup, step, 0, 0, testname);
|
||||
}
|
||||
},
|
||||
{
|
||||
// these tests check the same but with a 10 pixel margin on the popup
|
||||
|
@ -204,16 +233,23 @@ var popupTests = [
|
|||
result: function(testname, step) { compareEdge(gTrigger, gMenuPopup, step, 0, 0, testname); }
|
||||
},
|
||||
{
|
||||
// this test checks to ensure that attributes override flag to openPopup
|
||||
// can be used to override the popup's position
|
||||
// this test checks to ensure that the attributes override flag to openPopup
|
||||
// can be used to override the popup's position. This test also passes an
|
||||
// event to openPopup to check the trigger node.
|
||||
testname: "open popup anchored with override",
|
||||
events: [ "popupshowing thepopup", "popupshown thepopup" ],
|
||||
test: function(testname, step) {
|
||||
// attribute overrides the position passed in
|
||||
gMenuPopup.setAttribute("position", "end_after");
|
||||
gMenuPopup.openPopup(gTrigger, "before_start", 0, 0, false, true);
|
||||
gExpectedTriggerNode = gCachedEvent.target;
|
||||
gMenuPopup.openPopup(gTrigger, "before_start", 0, 0, false, true, gCachedEvent);
|
||||
},
|
||||
result: function(testname, step) { compareEdge(gTrigger, gMenuPopup, "end_after", 0, 0, testname); }
|
||||
result: function(testname, step) {
|
||||
gExpectedTriggerNode = null;
|
||||
is(gMenuPopup.triggerNode, gCachedEvent.target, testname + " triggerNode");
|
||||
is(document.popupNode, gCachedEvent.target, testname + " document.popupNode");
|
||||
compareEdge(gTrigger, gMenuPopup, "end_after", 0, 0, testname);
|
||||
}
|
||||
},
|
||||
{
|
||||
testname: "close popup with escape",
|
||||
|
@ -319,9 +355,13 @@ var popupTests = [
|
|||
testname: "open popup at screen",
|
||||
events: [ "popupshowing thepopup", "popupshown thepopup" ],
|
||||
test: function(testname, step) {
|
||||
gExpectedTriggerNode = "notset";
|
||||
gMenuPopup.openPopupAtScreen(gScreenX + 24, gScreenY + 20, false);
|
||||
},
|
||||
result: function(testname, step) {
|
||||
gExpectedTriggerNode = null;
|
||||
is(gMenuPopup.triggerNode, null, testname + " triggerNode");
|
||||
is(document.popupNode, null, testname + " document.popupNode");
|
||||
var rect = gMenuPopup.getBoundingClientRect();
|
||||
is(rect.left, 24, testname + " left");
|
||||
is(rect.top, 20, testname + " top");
|
||||
|
@ -346,9 +386,30 @@ var popupTests = [
|
|||
testname: "open context popup at screen",
|
||||
events: [ "popupshowing thepopup", "popupshown thepopup" ],
|
||||
test: function(testname, step) {
|
||||
gMenuPopup.openPopupAtScreen(gScreenX + 8, gScreenY + 16, true);
|
||||
gExpectedTriggerNode = gCachedEvent.target;
|
||||
gMenuPopup.openPopupAtScreen(gScreenX + 8, gScreenY + 16, true, gCachedEvent);
|
||||
},
|
||||
result: function(testname, step) {
|
||||
gExpectedTriggerNode = null;
|
||||
is(gMenuPopup.triggerNode, gCachedEvent.target, testname + " triggerNode");
|
||||
is(document.popupNode, gCachedEvent.target, testname + " document.popupNode");
|
||||
|
||||
var childframe = document.getElementById("childframe");
|
||||
if (childframe) {
|
||||
for (var t = 0; t < 2; t++) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var child = childframe.contentDocument;
|
||||
var evt = child.createEvent("Event");
|
||||
evt.initEvent("click", true, true);
|
||||
child.documentElement.dispatchEvent(evt);
|
||||
is(child.documentElement.getAttribute("data"), "xnull",
|
||||
"cannot get popupNode from other document");
|
||||
child.documentElement.setAttribute("data", "none");
|
||||
// now try again with document.popupNode set explicitly
|
||||
document.popupNode = gCachedEvent.target;
|
||||
}
|
||||
}
|
||||
|
||||
var rect = gMenuPopup.getBoundingClientRect();
|
||||
is(rect.left, 10, testname + " left");
|
||||
is(rect.top, 18, testname + " top");
|
||||
|
@ -681,6 +742,6 @@ var popupTests = [
|
|||
var popup = document.getElementById("thepopup");
|
||||
popup.parentNode.removeChild(popup);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
];
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window title="Nested Context Menu Tests"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="popup_shared.js"></script>
|
||||
|
||||
<menupopup id="outercontext">
|
||||
<menuitem label="Context One"/>
|
||||
<menu id="outercontextmenu" label="Sub">
|
||||
<menupopup id="innercontext">
|
||||
<menuitem id="innercontextmenu" label="Sub Context One"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
</menupopup>
|
||||
|
||||
<menupopup id="outermain">
|
||||
<menuitem label="One"/>
|
||||
<menu id="outermenu" label="Sub">
|
||||
<menupopup id="innermain">
|
||||
<menuitem id="innermenu" label="Sub One" context="outercontext"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
</menupopup>
|
||||
|
||||
<button label="Check"/>
|
||||
|
||||
<vbox id="popuparea" popup="outermain" width="20" height="20"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var popupTests = [
|
||||
{
|
||||
testname: "open outer popup",
|
||||
events: [ "popupshowing outermain", "popupshown outermain" ],
|
||||
test: function () synthesizeMouse($("popuparea"), 4, 4, {}),
|
||||
result: function (testname) is($("outermain").triggerNode, $("popuparea"), testname)
|
||||
},
|
||||
{
|
||||
testname: "open inner popup",
|
||||
events: [ "DOMMenuItemActive outermenu", "popupshowing innermain", "popupshown innermain" ],
|
||||
test: function () {
|
||||
synthesizeMouse($("outermenu"), 4, 4, { type: "mousemove" });
|
||||
synthesizeMouse($("outermenu"), 2, 2, { type: "mousemove" });
|
||||
},
|
||||
result: function (testname) {
|
||||
is($("outermain").triggerNode, $("popuparea"), testname + " outer");
|
||||
is($("innermain").triggerNode, $("popuparea"), testname + " inner");
|
||||
is($("outercontext").triggerNode, null, testname + " outer context");
|
||||
}
|
||||
},
|
||||
{
|
||||
testname: "open outer context",
|
||||
condition: function() { return (navigator.platform.indexOf("Mac") == -1); },
|
||||
events: [ "popupshowing outercontext", "popupshown outercontext" ],
|
||||
test: function () synthesizeMouse($("innermenu"), 4, 4, { type: "contextmenu", button: 2 }),
|
||||
result: function (testname) {
|
||||
is($("outermain").triggerNode, $("popuparea"), testname + " outer");
|
||||
is($("innermain").triggerNode, $("popuparea"), testname + " inner");
|
||||
is($("outercontext").triggerNode, $("innermenu"), testname + " outer context");
|
||||
}
|
||||
},
|
||||
{
|
||||
testname: "open inner context",
|
||||
condition: function() { return (navigator.platform.indexOf("Mac") == -1); },
|
||||
events: [ "DOMMenuItemActive outercontextmenu", "popupshowing innercontext", "popupshown innercontext" ],
|
||||
test: function () {
|
||||
synthesizeMouse($("outercontextmenu"), 4, 4, { type: "mousemove" });
|
||||
synthesizeMouse($("outercontextmenu"), 2, 2, { type: "mousemove" });
|
||||
},
|
||||
result: function (testname) {
|
||||
is($("outermain").triggerNode, $("popuparea"), testname + " outer");
|
||||
is($("innermain").triggerNode, $("popuparea"), testname + " inner");
|
||||
is($("outercontext").triggerNode, $("innermenu"), testname + " outer context");
|
||||
is($("innercontext").triggerNode, $("innermenu"), testname + " inner context");
|
||||
}
|
||||
},
|
||||
{
|
||||
testname: "close context",
|
||||
condition: function() { return (navigator.platform.indexOf("Mac") == -1); },
|
||||
events: [ "popuphiding innercontext", "popuphidden innercontext",
|
||||
"popuphiding outercontext", "popuphidden outercontext",
|
||||
"DOMMenuInactive innercontext",
|
||||
"DOMMenuItemInactive outercontextmenu", "DOMMenuItemInactive outercontextmenu",
|
||||
"DOMMenuInactive outercontext" ],
|
||||
test: function () $("outercontext").hidePopup()
|
||||
},
|
||||
{
|
||||
testname: "hide menus",
|
||||
events: [ "popuphiding innermain", "popuphidden innermain",
|
||||
"popuphiding outermain", "popuphidden outermain",
|
||||
"DOMMenuInactive innermain",
|
||||
"DOMMenuItemInactive outermenu", "DOMMenuItemInactive outermenu",
|
||||
"DOMMenuInactive outermain" ],
|
||||
|
||||
test: function () $("outermain").hidePopup(),
|
||||
result: function (testname) {
|
||||
is($("outermain").triggerNode, null, testname + " outer");
|
||||
is($("innermain").triggerNode, null, testname + " inner");
|
||||
is($("outercontext").triggerNode, null, testname + " outer context");
|
||||
is($("innercontext").triggerNode, null, testname + " inner context");
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
SimpleTest.waitForFocus(function runTest() startPopupTests(popupTests));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"><p id="display"/></body>
|
||||
|
||||
</window>
|
|
@ -24,6 +24,8 @@
|
|||
specific sizing differences -->
|
||||
<button id="withtooltip" label="Tooltip Element" tooltip="thetooltip"
|
||||
class="plain" style="-moz-appearance: none; padding: 0;"/>
|
||||
<iframe id="childframe" type="content" width="10" height="10"
|
||||
src="http://sectest2.example.org:80/tests/toolkit/content/tests/widgets/popup_childframe_node.xul"/>
|
||||
</box>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
|
@ -76,7 +78,7 @@ var popupTests = [
|
|||
disableNonTestMouse(true);
|
||||
synthesizeMouse(document.documentElement, 2, 2, { type: "mousemove" });
|
||||
disableNonTestMouse(false);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
testname: "hover inherited tooltip",
|
||||
|
@ -97,6 +99,7 @@ var popupTests = [
|
|||
"popupshowing thetooltip", "popupshown thetooltip" ],
|
||||
test: function() {
|
||||
gButton = document.getElementById("withtooltip");
|
||||
gExpectedTriggerNode = gButton;
|
||||
disableNonTestMouse(true);
|
||||
synthesizeMouse(gButton, 2, 2, { type: "mouseover" });
|
||||
synthesizeMouse(gButton, 4, 4, { type: "mousemove" });
|
||||
|
@ -104,8 +107,22 @@ var popupTests = [
|
|||
disableNonTestMouse(false);
|
||||
},
|
||||
result: function(testname) {
|
||||
var tooltip = document.getElementById("thetooltip");
|
||||
gExpectedTriggerNode = null;
|
||||
is(tooltip.triggerNode, gButton, testname + " triggerNode");
|
||||
is(document.popupNode, null, testname + " document.popupNode");
|
||||
is(document.tooltipNode, gButton, testname + " document.tooltipNode");
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var child = $("childframe").contentDocument;
|
||||
var evt = child.createEvent("Event");
|
||||
evt.initEvent("click", true, true);
|
||||
child.documentElement.dispatchEvent(evt);
|
||||
is(child.documentElement.getAttribute("data"), "xnull",
|
||||
"cannot get tooltipNode from other document");
|
||||
|
||||
var buttonrect = document.getElementById("withtooltip").getBoundingClientRect();
|
||||
var rect = document.getElementById("thetooltip").getBoundingClientRect();
|
||||
var rect = tooltip.getBoundingClientRect();
|
||||
var popupstyle = window.getComputedStyle(document.getElementById("thetooltip"), "");
|
||||
|
||||
is(Math.round(rect.left),
|
||||
|
@ -131,6 +148,12 @@ var popupTests = [
|
|||
gButton = document.getElementById("withtooltip");
|
||||
synthesizeMouse(gButton, 2, 2, { });
|
||||
},
|
||||
result: function(testname) {
|
||||
var tooltip = document.getElementById("thetooltip");
|
||||
is(tooltip.triggerNode, null, testname + " triggerNode");
|
||||
is(document.popupNode, null, testname + " document.popupNode");
|
||||
is(document.tooltipNode, null, testname + " document.tooltipNode");
|
||||
}
|
||||
},
|
||||
{
|
||||
testname: "hover tooltip after size increased",
|
||||
|
@ -211,7 +234,7 @@ var popupTests = [
|
|||
is(gOriginalWidth, rect.right - rect.left, testname + " tooltip is original width");
|
||||
is(gOriginalHeight, rect.bottom - rect.top, testname + " tooltip is original height");
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@ window.opener.SimpleTest.waitForFocus(runTests, window);
|
|||
<hbox style="margin-left: 325px; margin-top: 325px;">
|
||||
<label id="trigger" popup="thepopup" value="Popup"/>
|
||||
</hbox>
|
||||
<!-- this frame is used to check that document.popupNode
|
||||
is inaccessible from different sources -->
|
||||
<iframe id="childframe" type="content" width="10" height="10"
|
||||
src="http://sectest2.example.org:80/tests/toolkit/content/tests/widgets/popup_childframe_node.xul"/>
|
||||
|
||||
<menupopup id="thepopup">
|
||||
<menuitem id="item1" label="First"/>
|
||||
|
|
|
@ -34,4 +34,9 @@ window.opener.SimpleTest.waitForFocus(runTests, window);
|
|||
</button>
|
||||
</hbox>
|
||||
|
||||
<!-- this frame is used to check that document.popupNode
|
||||
is inaccessible from different sources -->
|
||||
<iframe id="childframe" type="content" width="10" height="10"
|
||||
src="http://sectest2.example.org:80/tests/toolkit/content/tests/widgets/popup_childframe_node.xul"/>
|
||||
|
||||
</window>
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
<property name="state" readonly="true"
|
||||
onget="return this.popupBoxObject.popupState"/>
|
||||
|
||||
<property name="triggerNode" readonly="true"
|
||||
onget="return this.popupBoxObject.triggerNode"/>
|
||||
|
||||
<method name="openPopup">
|
||||
<parameter name="aAnchorElement"/>
|
||||
<parameter name="aPosition"/>
|
||||
|
@ -31,13 +34,14 @@
|
|||
<parameter name="aY"/>
|
||||
<parameter name="aIsContextMenu"/>
|
||||
<parameter name="aAttributesOverride"/>
|
||||
<parameter name="aTriggerEvent"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
try {
|
||||
var popupBox = this.popupBoxObject;
|
||||
if (popupBox)
|
||||
popupBox.openPopup(aAnchorElement, aPosition, aX, aY,
|
||||
aIsContextMenu, aAttributesOverride);
|
||||
aIsContextMenu, aAttributesOverride, aTriggerEvent);
|
||||
} catch(e) {}
|
||||
]]>
|
||||
</body>
|
||||
|
@ -47,12 +51,13 @@
|
|||
<parameter name="aX"/>
|
||||
<parameter name="aY"/>
|
||||
<parameter name="aIsContextMenu"/>
|
||||
<parameter name="aTriggerEvent"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
try {
|
||||
var popupBox = this.popupBoxObject;
|
||||
if (popupBox)
|
||||
popupBox.openPopupAtScreen(aX, aY, aIsContextMenu);
|
||||
popupBox.openPopupAtScreen(aX, aY, aIsContextMenu, aTriggerEvent);
|
||||
} catch(e) {}
|
||||
]]>
|
||||
</body>
|
||||
|
|
Загрузка…
Ссылка в новой задаче