2003-11-19 04:20:56 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
1999-05-14 09:37:20 +04:00
|
|
|
|
|
|
|
/*
|
1999-07-01 10:27:42 +04:00
|
|
|
This file provides the implementation for xul popup listener which
|
2001-12-05 01:32:49 +03:00
|
|
|
tracks xul popups and context menus
|
1999-05-14 09:37:20 +04:00
|
|
|
*/
|
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
#include "nsXULPopupListener.h"
|
1999-05-14 09:37:20 +04:00
|
|
|
#include "nsCOMPtr.h"
|
2006-12-26 20:47:52 +03:00
|
|
|
#include "nsGkAtoms.h"
|
1999-05-14 09:37:20 +04:00
|
|
|
#include "nsIDOMElement.h"
|
2000-05-31 11:32:36 +04:00
|
|
|
#include "nsIDOMXULElement.h"
|
2000-05-03 02:48:17 +04:00
|
|
|
#include "nsIDOMNodeList.h"
|
2003-03-26 10:41:30 +03:00
|
|
|
#include "nsIDOMDocument.h"
|
2000-06-02 12:13:29 +04:00
|
|
|
#include "nsIDOMDocumentXBL.h"
|
2001-02-22 06:01:34 +03:00
|
|
|
#include "nsContentCID.h"
|
2004-03-06 05:58:08 +03:00
|
|
|
#include "nsContentUtils.h"
|
2007-07-04 19:49:38 +04:00
|
|
|
#include "nsXULPopupManager.h"
|
2001-07-16 06:40:48 +04:00
|
|
|
#include "nsIScriptContext.h"
|
2011-07-15 14:31:34 +04:00
|
|
|
#include "nsIDOMWindow.h"
|
1999-05-14 23:10:01 +04:00
|
|
|
#include "nsIDOMXULDocument.h"
|
|
|
|
#include "nsIDocument.h"
|
2004-11-25 01:48:45 +03:00
|
|
|
#include "nsServiceManagerUtils.h"
|
2004-03-06 05:58:08 +03:00
|
|
|
#include "nsIPrincipal.h"
|
|
|
|
#include "nsIScriptSecurityManager.h"
|
2007-07-04 19:49:38 +04:00
|
|
|
#include "nsLayoutUtils.h"
|
|
|
|
#include "nsHTMLReflowState.h"
|
2008-10-28 04:59:17 +03:00
|
|
|
#include "nsIObjectLoadingContent.h"
|
2014-04-01 08:09:23 +04:00
|
|
|
#include "mozilla/EventStateManager.h"
|
2014-04-03 08:18:36 +04:00
|
|
|
#include "mozilla/EventStates.h"
|
2011-05-25 10:31:59 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2014-03-05 04:37:43 +04:00
|
|
|
#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
|
2013-04-06 04:44:26 +04:00
|
|
|
#include "mozilla/dom/EventTarget.h"
|
2012-10-16 16:37:26 +04:00
|
|
|
#include "mozilla/dom/FragmentOrElement.h"
|
2000-05-31 11:32:36 +04:00
|
|
|
|
2000-08-20 04:29:24 +04:00
|
|
|
// for event firing in context menus
|
2004-08-01 03:15:21 +04:00
|
|
|
#include "nsPresContext.h"
|
2000-08-20 04:29:24 +04:00
|
|
|
#include "nsIPresShell.h"
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 22:00:39 +04:00
|
|
|
#include "nsFocusManager.h"
|
2005-11-12 09:34:12 +03:00
|
|
|
#include "nsPIDOMWindow.h"
|
2013-01-05 07:12:24 +04:00
|
|
|
#include "nsViewManager.h"
|
2012-07-27 18:03:27 +04:00
|
|
|
#include "nsError.h"
|
2012-07-31 04:43:28 +04:00
|
|
|
#include "nsMenuFrame.h"
|
2000-08-20 04:29:24 +04:00
|
|
|
|
2011-05-25 10:31:59 +04:00
|
|
|
using namespace mozilla;
|
2013-04-06 04:44:26 +04:00
|
|
|
using namespace mozilla::dom;
|
2011-05-25 10:31:59 +04:00
|
|
|
|
2001-03-30 08:45:40 +04:00
|
|
|
// on win32 and os/2, context menus come up on mouse up. On other platforms,
|
|
|
|
// they appear on mouse down. Certain bits of code care about this difference.
|
2014-02-11 02:57:01 +04:00
|
|
|
#if defined(XP_WIN)
|
2001-03-30 08:45:40 +04:00
|
|
|
#define NS_CONTEXT_MENU_IS_MOUSEUP 1
|
|
|
|
#endif
|
|
|
|
|
2012-10-16 16:37:26 +04:00
|
|
|
nsXULPopupListener::nsXULPopupListener(mozilla::dom::Element* aElement,
|
|
|
|
bool aIsContext)
|
2012-07-30 18:20:58 +04:00
|
|
|
: mElement(aElement), mPopupContent(nullptr), mIsContext(aIsContext)
|
1999-05-14 09:37:20 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
nsXULPopupListener::~nsXULPopupListener(void)
|
1999-05-14 09:37:20 +04:00
|
|
|
{
|
2007-07-04 19:49:38 +04:00
|
|
|
ClosePopup();
|
1999-05-14 09:37:20 +04:00
|
|
|
}
|
|
|
|
|
2014-04-25 20:49:00 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION(nsXULPopupListener, mElement, mPopupContent)
|
2007-09-04 19:26:35 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULPopupListener)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULPopupListener)
|
1999-05-14 09:37:20 +04:00
|
|
|
|
2012-10-16 16:37:26 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXULPopupListener)
|
|
|
|
// If the owner, mElement, can be skipped, so can we.
|
|
|
|
if (tmp->mElement) {
|
|
|
|
return mozilla::dom::FragmentOrElement::CanSkip(tmp->mElement, true);
|
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsXULPopupListener)
|
|
|
|
if (tmp->mElement) {
|
|
|
|
return mozilla::dom::FragmentOrElement::CanSkipInCC(tmp->mElement);
|
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsXULPopupListener)
|
|
|
|
if (tmp->mElement) {
|
|
|
|
return mozilla::dom::FragmentOrElement::CanSkipThis(tmp->mElement);
|
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
|
|
|
|
|
2007-09-04 19:26:35 +04:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPopupListener)
|
2011-06-27 23:25:55 +04:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
1999-12-21 22:28:15 +03:00
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
1999-05-14 09:37:20 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
2011-06-27 23:25:55 +04:00
|
|
|
// nsIDOMEventListener
|
1999-05-14 09:37:20 +04:00
|
|
|
|
|
|
|
nsresult
|
2011-06-27 23:25:55 +04:00
|
|
|
nsXULPopupListener::HandleEvent(nsIDOMEvent* aEvent)
|
2000-08-20 04:29:24 +04:00
|
|
|
{
|
2011-06-27 23:25:55 +04:00
|
|
|
nsAutoString eventType;
|
|
|
|
aEvent->GetType(eventType);
|
2000-08-20 04:29:24 +04:00
|
|
|
|
2011-06-27 23:25:55 +04:00
|
|
|
if(!((eventType.EqualsLiteral("mousedown") && !mIsContext) ||
|
|
|
|
(eventType.EqualsLiteral("contextmenu") && mIsContext)))
|
2001-03-29 07:33:09 +04:00
|
|
|
return NS_OK;
|
2001-03-23 06:34:15 +03:00
|
|
|
|
2014-02-20 22:38:13 +04:00
|
|
|
int16_t button;
|
1999-05-14 11:20:12 +04:00
|
|
|
|
2011-06-27 23:25:55 +04:00
|
|
|
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
|
1999-11-03 10:11:45 +03:00
|
|
|
if (!mouseEvent) {
|
1999-05-19 03:51:04 +04:00
|
|
|
//non-ui event passed in. bad things.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2004-03-06 05:58:08 +03:00
|
|
|
// Get the node that was clicked on.
|
2013-04-06 04:44:26 +04:00
|
|
|
EventTarget* target = mouseEvent->InternalDOMEvent()->GetTarget();
|
2004-03-06 05:58:08 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(target);
|
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
if (!targetNode && mIsContext) {
|
2007-06-08 15:54:16 +04:00
|
|
|
// Not a DOM node, see if it's the DOM window (bug 380818).
|
|
|
|
nsCOMPtr<nsIDOMWindow> domWin = do_QueryInterface(target);
|
|
|
|
if (!domWin) {
|
|
|
|
return NS_ERROR_DOM_WRONG_TYPE_ERR;
|
|
|
|
}
|
|
|
|
// Try to use the root node as target node.
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
|
|
domWin->GetDocument(getter_AddRefs(domDoc));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
|
|
|
|
if (doc)
|
2010-04-30 17:12:05 +04:00
|
|
|
targetNode = do_QueryInterface(doc->GetRootElement());
|
2007-06-08 15:54:16 +04:00
|
|
|
if (!targetNode) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-07 02:00:07 +04:00
|
|
|
nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
|
|
|
|
if (!targetContent) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2015-03-03 14:09:00 +03:00
|
|
|
if (targetContent->IsXULElement(nsGkAtoms::browser) &&
|
2014-04-01 08:09:23 +04:00
|
|
|
EventStateManager::IsRemoteTarget(targetContent)) {
|
2013-08-07 02:00:07 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool preventDefault;
|
2013-05-26 01:05:36 +04:00
|
|
|
mouseEvent->GetDefaultPrevented(&preventDefault);
|
2007-07-04 19:49:38 +04:00
|
|
|
if (preventDefault && targetNode && mIsContext) {
|
2004-03-06 05:58:08 +03:00
|
|
|
// Someone called preventDefault on a context menu.
|
|
|
|
// Let's make sure they are allowed to do so.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool eventEnabled =
|
|
|
|
Preferences::GetBool("dom.event.contextmenu.enabled", true);
|
2004-04-30 03:34:19 +04:00
|
|
|
if (!eventEnabled) {
|
2008-10-28 04:59:17 +03:00
|
|
|
// If the target node is for plug-in, we should not open XUL context
|
|
|
|
// menu on windowless plug-ins.
|
|
|
|
nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(targetNode);
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t type;
|
2008-10-28 04:59:17 +03:00
|
|
|
if (olc && NS_SUCCEEDED(olc->GetDisplayedType(&type)) &&
|
|
|
|
type == nsIObjectLoadingContent::TYPE_PLUGIN) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2004-03-06 05:58:08 +03:00
|
|
|
// The user wants his contextmenus. Let's make sure that this is a website
|
|
|
|
// and not chrome since there could be places in chrome which don't want
|
|
|
|
// contextmenus.
|
2006-02-02 23:02:34 +03:00
|
|
|
nsCOMPtr<nsINode> node = do_QueryInterface(targetNode);
|
|
|
|
if (node) {
|
2004-03-06 05:58:08 +03:00
|
|
|
nsCOMPtr<nsIPrincipal> system;
|
2006-04-27 22:21:11 +04:00
|
|
|
nsContentUtils::GetSecurityManager()->
|
|
|
|
GetSystemPrincipal(getter_AddRefs(system));
|
|
|
|
if (node->NodePrincipal() != system) {
|
2004-03-06 05:58:08 +03:00
|
|
|
// This isn't chrome. Cancel the preventDefault() and
|
|
|
|
// let the event go forth.
|
2011-10-17 18:59:28 +04:00
|
|
|
preventDefault = false;
|
2004-03-06 05:58:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-04-24 06:07:06 +04:00
|
|
|
if (preventDefault) {
|
|
|
|
// someone called preventDefault. bail.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
// prevent popups on menu and menuitems as they handle their own popups
|
|
|
|
// This was added for bug 96920.
|
2001-08-30 02:33:18 +04:00
|
|
|
// If a menu item child was clicked on that leads to a popup needing
|
|
|
|
// to show, we know (guaranteed) that we're dealing with a menu or
|
|
|
|
// submenu of an already-showing popup. We don't need to do anything at all.
|
2007-07-04 19:49:38 +04:00
|
|
|
if (!mIsContext) {
|
2015-03-03 14:09:00 +03:00
|
|
|
if (targetContent &&
|
|
|
|
targetContent->IsAnyOfXULElements(nsGkAtoms::menu, nsGkAtoms::menuitem))
|
2001-08-30 02:33:18 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
if (mIsContext) {
|
2001-03-30 08:45:40 +04:00
|
|
|
#ifndef NS_CONTEXT_MENU_IS_MOUSEUP
|
2007-07-04 19:49:38 +04:00
|
|
|
// If the context menu launches on mousedown,
|
|
|
|
// we have to fire focus on the content we clicked on
|
|
|
|
FireFocusOnTargetContent(targetNode);
|
2001-03-29 07:33:09 +04:00
|
|
|
#endif
|
1999-05-14 11:20:12 +04:00
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
else {
|
|
|
|
// Only open popups when the left mouse button is down.
|
|
|
|
mouseEvent->GetButton(&button);
|
|
|
|
if (button != 0)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-05-31 13:49:26 +04:00
|
|
|
// Open the popup. LaunchPopup will call StopPropagation and PreventDefault
|
|
|
|
// in the right situations.
|
2011-06-27 23:25:55 +04:00
|
|
|
LaunchPopup(aEvent, targetContent);
|
2007-07-04 19:49:38 +04:00
|
|
|
|
1999-05-14 09:37:20 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-09-30 03:44:28 +04:00
|
|
|
#ifndef NS_CONTEXT_MENU_IS_MOUSEUP
|
2000-08-20 04:29:24 +04:00
|
|
|
nsresult
|
2007-07-04 19:49:38 +04:00
|
|
|
nsXULPopupListener::FireFocusOnTargetContent(nsIDOMNode* aTargetNode)
|
2000-08-20 04:29:24 +04:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
|
|
rv = aTargetNode->GetOwnerDocument(getter_AddRefs(domDoc));
|
|
|
|
if(NS_SUCCEEDED(rv) && domDoc)
|
|
|
|
{
|
2005-11-12 09:34:12 +03:00
|
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
|
2003-09-27 08:18:26 +04:00
|
|
|
|
|
|
|
// Get nsIDOMElement for targetNode
|
2010-06-25 17:59:57 +04:00
|
|
|
nsIPresShell *shell = doc->GetShell();
|
2001-12-21 04:10:07 +03:00
|
|
|
if (!shell)
|
2003-09-27 08:18:26 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
2001-12-21 04:10:07 +03:00
|
|
|
|
2004-08-21 00:34:37 +04:00
|
|
|
// strong reference to keep this from going away between events
|
2009-12-25 00:20:05 +03:00
|
|
|
// XXXbz between what events? We don't use this local at all!
|
2010-03-31 15:09:11 +04:00
|
|
|
nsRefPtr<nsPresContext> context = shell->GetPresContext();
|
2000-08-20 04:29:24 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aTargetNode);
|
2009-12-25 00:20:05 +03:00
|
|
|
nsIFrame* targetFrame = content->GetPrimaryFrame();
|
2002-05-09 05:43:18 +04:00
|
|
|
if (!targetFrame) return NS_ERROR_FAILURE;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 22:00:39 +04:00
|
|
|
|
2013-02-17 01:51:02 +04:00
|
|
|
const nsStyleUserInterface* ui = targetFrame->StyleUserInterface();
|
2011-09-29 10:19:26 +04:00
|
|
|
bool suppressBlur = (ui->mUserFocus == NS_STYLE_USER_FOCUS_IGNORE);
|
2000-08-20 04:29:24 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> element;
|
|
|
|
nsCOMPtr<nsIContent> newFocus = do_QueryInterface(content);
|
|
|
|
|
|
|
|
nsIFrame* currFrame = targetFrame;
|
|
|
|
// Look for the nearest enclosing focusable frame.
|
|
|
|
while (currFrame) {
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t tabIndexUnused;
|
2011-10-17 18:59:28 +04:00
|
|
|
if (currFrame->IsFocusable(&tabIndexUnused, true)) {
|
2003-08-06 07:07:12 +04:00
|
|
|
newFocus = currFrame->GetContent();
|
2000-08-20 04:29:24 +04:00
|
|
|
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocus));
|
|
|
|
if (domElement) {
|
|
|
|
element = domElement;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-08-06 07:07:12 +04:00
|
|
|
currFrame = currFrame->GetParent();
|
2000-08-20 04:29:24 +04:00
|
|
|
}
|
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 22:00:39 +04:00
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
if (fm) {
|
|
|
|
if (element) {
|
|
|
|
fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE |
|
|
|
|
nsIFocusManager::FLAG_NOSCROLL);
|
|
|
|
} else if (!suppressBlur) {
|
|
|
|
nsPIDOMWindow *window = doc->GetWindow();
|
|
|
|
fm->ClearFocus(window);
|
2005-11-12 09:34:12 +03:00
|
|
|
}
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 22:00:39 +04:00
|
|
|
}
|
2005-11-12 09:34:12 +03:00
|
|
|
|
2014-04-01 08:09:23 +04:00
|
|
|
EventStateManager* esm = context->EventStateManager();
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 22:00:39 +04:00
|
|
|
nsCOMPtr<nsIContent> focusableContent = do_QueryInterface(element);
|
2010-10-21 12:58:05 +04:00
|
|
|
esm->SetContentState(focusableContent, NS_EVENT_STATE_ACTIVE);
|
2000-08-20 04:29:24 +04:00
|
|
|
}
|
2000-08-24 08:00:12 +04:00
|
|
|
return rv;
|
2000-08-20 04:29:24 +04:00
|
|
|
}
|
2008-09-30 03:44:28 +04:00
|
|
|
#endif
|
2001-03-14 05:32:27 +03:00
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
// ClosePopup
|
1999-07-01 04:07:41 +04:00
|
|
|
//
|
2007-07-04 19:49:38 +04:00
|
|
|
// Do everything needed to shut down the popup.
|
2007-06-29 23:04:45 +04:00
|
|
|
//
|
2007-07-04 19:49:38 +04:00
|
|
|
// NOTE: This routine is safe to call even if the popup is already closed.
|
|
|
|
//
|
|
|
|
void
|
|
|
|
nsXULPopupListener::ClosePopup()
|
1999-07-01 04:07:41 +04:00
|
|
|
{
|
2007-07-04 19:49:38 +04:00
|
|
|
if (mPopupContent) {
|
|
|
|
// this is called when the listener is going away, so make sure that the
|
|
|
|
// popup is hidden. Use asynchronous hiding just to be safe so we don't
|
|
|
|
// fire events during destruction.
|
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
|
|
|
if (pm)
|
2014-04-08 16:45:52 +04:00
|
|
|
pm->HidePopup(mPopupContent, false, true, true, false);
|
2012-07-30 18:20:58 +04:00
|
|
|
mPopupContent = nullptr; // release the popup
|
1999-07-01 04:07:41 +04:00
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
} // ClosePopup
|
1999-07-01 04:07:41 +04:00
|
|
|
|
2011-09-27 11:54:58 +04:00
|
|
|
static already_AddRefed<nsIContent>
|
|
|
|
GetImmediateChild(nsIContent* aContent, nsIAtom *aTag)
|
2000-04-29 00:31:26 +04:00
|
|
|
{
|
2011-09-27 11:54:58 +04:00
|
|
|
for (nsIContent* child = aContent->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
2015-03-03 14:09:00 +03:00
|
|
|
if (child->IsXULElement(aTag)) {
|
2013-04-22 15:15:59 +04:00
|
|
|
nsCOMPtr<nsIContent> ret = child;
|
|
|
|
return ret.forget();
|
2000-04-29 00:31:26 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2000-04-29 00:31:26 +04:00
|
|
|
}
|
|
|
|
|
1999-07-01 04:07:41 +04:00
|
|
|
//
|
|
|
|
// LaunchPopup
|
|
|
|
//
|
|
|
|
// Given the element on which the event was triggered and the mouse locations in
|
1999-09-10 12:49:32 +04:00
|
|
|
// Client and widget coordinates, popup a new window showing the appropriate
|
1999-07-01 04:07:41 +04:00
|
|
|
// content.
|
|
|
|
//
|
2007-07-04 19:49:38 +04:00
|
|
|
// aTargetContent is the target of the mouse event aEvent that triggered the
|
2007-11-17 18:47:38 +03:00
|
|
|
// popup. mElement is the element that the popup menu is attached to.
|
|
|
|
// aTargetContent may be equal to mElement or it may be a descendant.
|
2007-07-04 19:49:38 +04:00
|
|
|
//
|
|
|
|
// This looks for an attribute on |mElement| of the appropriate popup type
|
2001-12-05 01:32:49 +03:00
|
|
|
// (popup, context) and uses that attribute's value as an ID for
|
1999-07-01 04:07:41 +04:00
|
|
|
// the popup content in the document.
|
|
|
|
//
|
|
|
|
nsresult
|
2007-07-04 19:49:38 +04:00
|
|
|
nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
|
1999-05-14 23:10:01 +04:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
1999-06-25 01:19:02 +04:00
|
|
|
nsAutoString identifier;
|
2013-05-31 13:49:26 +04:00
|
|
|
nsIAtom* type = mIsContext ? nsGkAtoms::context : nsGkAtoms::popup;
|
|
|
|
bool hasPopupAttr = mElement->GetAttr(kNameSpaceID_None, type, identifier);
|
1999-05-14 23:10:01 +04:00
|
|
|
|
2001-08-18 05:04:47 +04:00
|
|
|
if (identifier.IsEmpty()) {
|
2013-05-31 13:49:26 +04:00
|
|
|
hasPopupAttr = mElement->GetAttr(kNameSpaceID_None,
|
|
|
|
mIsContext ? nsGkAtoms::contextmenu : nsGkAtoms::menu,
|
|
|
|
identifier) || hasPopupAttr;
|
2001-08-18 05:04:47 +04:00
|
|
|
}
|
1999-05-14 23:10:01 +04:00
|
|
|
|
2013-05-31 13:49:26 +04:00
|
|
|
if (hasPopupAttr) {
|
|
|
|
aEvent->StopPropagation();
|
|
|
|
aEvent->PreventDefault();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (identifier.IsEmpty())
|
|
|
|
return rv;
|
|
|
|
|
2001-12-05 01:32:49 +03:00
|
|
|
// Try to find the popup content and the document.
|
2014-08-23 00:11:27 +04:00
|
|
|
nsCOMPtr<nsIDocument> document = mElement->GetComposedDoc();
|
2012-10-16 16:37:26 +04:00
|
|
|
if (!document) {
|
|
|
|
NS_WARNING("No document!");
|
1999-05-14 23:10:01 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2000-04-29 00:31:26 +04:00
|
|
|
// Handle the _child case for popups and context menus
|
2012-10-16 16:37:26 +04:00
|
|
|
nsCOMPtr<nsIContent> popup;
|
2004-05-23 02:15:22 +04:00
|
|
|
if (identifier.EqualsLiteral("_child")) {
|
2012-10-16 16:37:26 +04:00
|
|
|
popup = GetImmediateChild(mElement, nsGkAtoms::menupopup);
|
|
|
|
if (!popup) {
|
|
|
|
nsCOMPtr<nsIDOMDocumentXBL> nsDoc(do_QueryInterface(document));
|
2000-05-03 02:48:17 +04:00
|
|
|
nsCOMPtr<nsIDOMNodeList> list;
|
2012-10-16 16:37:26 +04:00
|
|
|
nsCOMPtr<nsIDOMElement> el = do_QueryInterface(mElement);
|
|
|
|
nsDoc->GetAnonymousNodes(el, getter_AddRefs(list));
|
2000-05-03 02:48:17 +04:00
|
|
|
if (list) {
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t ctr,listLength;
|
2000-05-03 02:48:17 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
list->GetLength(&listLength);
|
|
|
|
for (ctr = 0; ctr < listLength; ctr++) {
|
|
|
|
list->Item(ctr, getter_AddRefs(node));
|
|
|
|
nsCOMPtr<nsIContent> childContent(do_QueryInterface(node));
|
2003-11-19 04:20:56 +03:00
|
|
|
|
2006-12-26 20:47:52 +03:00
|
|
|
if (childContent->NodeInfo()->Equals(nsGkAtoms::menupopup,
|
2005-09-24 22:43:15 +04:00
|
|
|
kNameSpaceID_XUL)) {
|
2012-10-16 16:37:26 +04:00
|
|
|
popup.swap(childContent);
|
2000-05-03 02:48:17 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-04-29 00:31:26 +04:00
|
|
|
}
|
2014-08-23 00:11:27 +04:00
|
|
|
} else if (!mElement->IsInUncomposedDoc() ||
|
|
|
|
!(popup = document->GetElementById(identifier))) {
|
|
|
|
// XXXsmaug Should we try to use ShadowRoot::GetElementById in case
|
|
|
|
// mElement is in shadow DOM?
|
|
|
|
//
|
2000-04-29 00:31:26 +04:00
|
|
|
// Use getElementById to obtain the popup content and gracefully fail if
|
|
|
|
// we didn't find any popup content in the document.
|
2014-08-23 00:11:27 +04:00
|
|
|
NS_WARNING("GetElementById had some kind of spasm.");
|
1999-05-14 23:10:01 +04:00
|
|
|
return rv;
|
|
|
|
}
|
2007-07-04 01:16:48 +04:00
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
// return if no popup was found or the popup is the element itself.
|
2012-10-16 16:37:26 +04:00
|
|
|
if (!popup || popup == mElement)
|
1999-05-14 23:10:01 +04:00
|
|
|
return NS_OK;
|
|
|
|
|
2006-08-02 12:24:21 +04:00
|
|
|
// Submenus can't be used as context menus or popups, bug 288763.
|
|
|
|
// Similar code also in nsXULTooltipListener::GetTooltipFor.
|
|
|
|
nsIContent* parent = popup->GetParent();
|
|
|
|
if (parent) {
|
2012-07-31 04:43:28 +04:00
|
|
|
nsMenuFrame* menu = do_QueryFrame(parent->GetPrimaryFrame());
|
|
|
|
if (menu)
|
2007-07-04 19:49:38 +04:00
|
|
|
return NS_OK;
|
2006-08-02 12:24:21 +04:00
|
|
|
}
|
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
|
|
|
if (!pm)
|
|
|
|
return NS_OK;
|
2007-06-30 02:15:59 +04:00
|
|
|
|
2007-08-03 21:57:44 +04:00
|
|
|
// For left-clicks, if the popup has an position attribute, or both the
|
|
|
|
// popupanchor and popupalign attributes are used, anchor the popup to the
|
|
|
|
// element, otherwise just open it at the screen position where the mouse
|
|
|
|
// was clicked. Context menus always open at the mouse position.
|
2007-07-04 19:49:38 +04:00
|
|
|
mPopupContent = popup;
|
2007-08-03 21:57:44 +04:00
|
|
|
if (!mIsContext &&
|
|
|
|
(mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::position) ||
|
|
|
|
(mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupanchor) &&
|
|
|
|
mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupalign)))) {
|
2012-10-16 16:37:26 +04:00
|
|
|
pm->ShowPopup(mPopupContent, mElement, EmptyString(), 0, 0,
|
2011-10-17 18:59:28 +04:00
|
|
|
false, true, false, aEvent);
|
2007-07-04 19:49:38 +04:00
|
|
|
}
|
|
|
|
else {
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t xPos = 0, yPos = 0;
|
2007-07-04 19:49:38 +04:00
|
|
|
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
|
|
|
|
mouseEvent->GetScreenX(&xPos);
|
|
|
|
mouseEvent->GetScreenY(&yPos);
|
|
|
|
|
2007-11-17 18:47:38 +03:00
|
|
|
pm->ShowPopupAtScreen(mPopupContent, xPos, yPos, mIsContext, aEvent);
|
1999-05-14 23:10:01 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|