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"
|
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"
|
2019-01-02 16:05:23 +03:00
|
|
|
#include "mozilla/dom/Document.h"
|
2004-11-25 01:48:45 +03:00
|
|
|
#include "nsServiceManagerUtils.h"
|
2007-07-04 19:49:38 +04:00
|
|
|
#include "nsLayoutUtils.h"
|
2016-07-21 13:36:34 +03:00
|
|
|
#include "mozilla/ReflowInput.h"
|
2008-10-28 04:59:17 +03:00
|
|
|
#include "nsIObjectLoadingContent.h"
|
2019-12-05 07:44:32 +03:00
|
|
|
#include "mozilla/BasePrincipal.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"
|
2018-04-26 17:37:46 +03:00
|
|
|
#include "mozilla/dom/Element.h"
|
2018-04-20 07:49:29 +03:00
|
|
|
#include "mozilla/dom/Event.h" // for Event
|
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"
|
2018-03-20 07:16:05 +03:00
|
|
|
#include "mozilla/dom/MouseEvent.h"
|
2018-03-20 07:16:06 +03:00
|
|
|
#include "mozilla/dom/MouseEventBinding.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"
|
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) { 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
|
|
|
|
2018-04-20 07:49:29 +03:00
|
|
|
nsresult nsXULPopupListener::HandleEvent(Event* aEvent) {
|
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
|
|
|
|
2018-04-20 07:49:30 +03:00
|
|
|
MouseEvent* mouseEvent = aEvent->AsMouseEvent();
|
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.
|
2018-03-20 07:16:05 +03:00
|
|
|
EventTarget* target = mouseEvent->GetTarget();
|
2013-08-07 02:00:07 +04:00
|
|
|
nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
|
|
|
|
if (!targetContent) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2017-09-19 08:52:21 +03:00
|
|
|
|
|
|
|
{
|
2018-03-20 07:16:05 +03:00
|
|
|
EventTarget* originalTarget = mouseEvent->GetOriginalTarget();
|
2017-09-19 08:52:21 +03:00
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(originalTarget);
|
|
|
|
if (content && EventStateManager::IsRemoteTarget(content)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2013-08-07 02:00:07 +04:00
|
|
|
}
|
|
|
|
|
2018-03-20 07:16:05 +03:00
|
|
|
bool preventDefault = mouseEvent->DefaultPrevented();
|
2018-05-26 07:23:04 +03:00
|
|
|
if (preventDefault && 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.
|
2018-05-26 07:23:04 +03:00
|
|
|
nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(targetContent);
|
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.
|
2019-12-05 07:44:32 +03:00
|
|
|
if (!targetContent->NodePrincipal()->IsSystemPrincipal()) {
|
2018-05-26 07:23:04 +03:00
|
|
|
// This isn't chrome. Cancel the preventDefault() and
|
|
|
|
// let the event go forth.
|
|
|
|
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.
|
2018-05-26 07:23:04 +03:00
|
|
|
if (!mIsContext &&
|
|
|
|
targetContent->IsAnyOfXULElements(nsGkAtoms::menu, nsGkAtoms::menuitem)) {
|
|
|
|
return NS_OK;
|
2001-08-30 02:33:18 +04:00
|
|
|
}
|
|
|
|
|
2007-07-04 19:49:38 +04:00
|
|
|
if (mIsContext) {
|
2001-03-30 08:45:40 +04:00
|
|
|
#ifndef NS_CONTEXT_MENU_IS_MOUSEUP
|
2018-03-20 07:16:06 +03:00
|
|
|
uint16_t inputSource = mouseEvent->MozInputSource();
|
2018-06-26 00:20:54 +03:00
|
|
|
bool isTouch = inputSource == MouseEvent_Binding::MOZ_SOURCE_TOUCH;
|
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
|
2018-05-26 07:23:04 +03:00
|
|
|
FireFocusOnTargetContent(targetContent, isTouch);
|
2001-03-29 07:33:09 +04:00
|
|
|
#endif
|
2007-07-04 19:49:38 +04:00
|
|
|
} else {
|
|
|
|
// Only open popups when the left mouse button is down.
|
2018-03-20 07:16:05 +03:00
|
|
|
if (mouseEvent->Button() != 0) {
|
2007-07-04 19:49:38 +04:00
|
|
|
return NS_OK;
|
2018-03-20 07:16:05 +03:00
|
|
|
}
|
2007-07-04 19:49:38 +04:00
|
|
|
}
|
|
|
|
|
2013-05-31 13:49:26 +04:00
|
|
|
// Open the popup. LaunchPopup will call StopPropagation and PreventDefault
|
|
|
|
// in the right situations.
|
2018-05-26 07:23:04 +03:00
|
|
|
LaunchPopup(mouseEvent);
|
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
|
2018-05-26 07:23:04 +03:00
|
|
|
nsresult nsXULPopupListener::FireFocusOnTargetContent(
|
|
|
|
nsIContent* aTargetContent, bool aIsTouch) {
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> doc = aTargetContent->OwnerDoc();
|
2018-01-30 07:10:52 +03:00
|
|
|
|
|
|
|
// strong reference to keep this from going away between events
|
|
|
|
// XXXbz between what events? We don't use this local at all!
|
2018-02-21 01:00:10 +03:00
|
|
|
RefPtr<nsPresContext> context = doc->GetPresContext();
|
|
|
|
if (!context) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2018-01-30 07:10:52 +03:00
|
|
|
|
2018-05-26 07:23:04 +03:00
|
|
|
nsIFrame* targetFrame = aTargetContent->GetPrimaryFrame();
|
2018-01-30 07:10:52 +03:00
|
|
|
if (!targetFrame) return NS_ERROR_FAILURE;
|
|
|
|
|
2018-08-14 11:37:37 +03:00
|
|
|
const nsStyleUI* ui = targetFrame->StyleUI();
|
2018-01-30 07:10:52 +03:00
|
|
|
bool suppressBlur = (ui->mUserFocus == StyleUserFocus::Ignore);
|
|
|
|
|
2018-04-26 17:37:46 +03:00
|
|
|
RefPtr<Element> newFocusElement;
|
2018-01-30 07:10:52 +03:00
|
|
|
|
|
|
|
nsIFrame* currFrame = targetFrame;
|
|
|
|
// Look for the nearest enclosing focusable frame.
|
|
|
|
while (currFrame) {
|
|
|
|
int32_t tabIndexUnused;
|
2018-04-26 17:37:46 +03:00
|
|
|
if (currFrame->IsFocusable(&tabIndexUnused, true) &&
|
|
|
|
currFrame->GetContent()->IsElement()) {
|
|
|
|
newFocusElement = currFrame->GetContent()->AsElement();
|
|
|
|
break;
|
2017-07-06 15:00:35 +03:00
|
|
|
}
|
2018-01-30 07:10:52 +03:00
|
|
|
currFrame = currFrame->GetParent();
|
|
|
|
}
|
2000-08-20 04:29:24 +04:00
|
|
|
|
2018-01-30 07:10:52 +03:00
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
if (fm) {
|
2018-04-26 17:37:46 +03:00
|
|
|
if (newFocusElement) {
|
2018-01-30 07:10:52 +03:00
|
|
|
uint32_t focusFlags =
|
|
|
|
nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL;
|
|
|
|
if (aIsTouch) {
|
|
|
|
focusFlags |= nsIFocusManager::FLAG_BYTOUCH;
|
2005-11-12 09:34:12 +03:00
|
|
|
}
|
2018-04-26 17:37:46 +03:00
|
|
|
fm->SetFocus(newFocusElement, focusFlags);
|
2018-01-30 07:10:52 +03:00
|
|
|
} else if (!suppressBlur) {
|
|
|
|
nsPIDOMWindowOuter* window = doc->GetWindow();
|
|
|
|
fm->ClearFocus(window);
|
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
|
|
|
}
|
2000-08-20 04:29:24 +04:00
|
|
|
}
|
2018-01-30 07:10:52 +03:00
|
|
|
|
|
|
|
EventStateManager* esm = context->EventStateManager();
|
2018-04-26 17:37:46 +03:00
|
|
|
esm->SetContentState(newFocusElement, NS_EVENT_STATE_ACTIVE);
|
2018-01-30 07:10:52 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
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() {
|
|
|
|
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
|
2017-07-06 15:00:35 +03:00
|
|
|
// fire events during destruction.
|
2007-07-04 19:49:38 +04:00
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
2014-04-08 16:45:52 +04:00
|
|
|
if (pm) 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
|
|
|
|
2017-10-03 01:05:19 +03:00
|
|
|
static already_AddRefed<Element> GetImmediateChild(nsIContent* aContent,
|
|
|
|
nsAtom* aTag) {
|
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)) {
|
2017-12-07 21:13:50 +03:00
|
|
|
RefPtr<Element> ret = child->AsElement();
|
2013-04-22 15:15:59 +04:00
|
|
|
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
|
2017-07-06 15:00:35 +03: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
|
|
|
//
|
2017-07-06 15:00:35 +03: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.
|
|
|
|
//
|
2018-05-26 07:23:04 +03:00
|
|
|
nsresult nsXULPopupListener::LaunchPopup(MouseEvent* aEvent) {
|
1999-05-14 23:10:01 +04:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
1999-06-25 01:19:02 +04:00
|
|
|
nsAutoString identifier;
|
2017-10-03 01:05:19 +03:00
|
|
|
nsAtom* type = mIsContext ? nsGkAtoms::context : nsGkAtoms::popup;
|
2013-05-31 13:49:26 +04:00
|
|
|
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.
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> 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
|
2017-12-07 21:13:50 +03:00
|
|
|
RefPtr<Element> 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);
|
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?
|
|
|
|
//
|
2017-07-06 15:00:35 +03: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) return NS_OK;
|
1999-05-14 23:10:01 +04:00
|
|
|
|
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());
|
2007-07-04 19:49:38 +04:00
|
|
|
if (menu) 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, false, true,
|
2011-10-17 18:59:28 +04:00
|
|
|
false, aEvent);
|
2007-07-04 19:49:38 +04:00
|
|
|
} else {
|
2018-03-20 07:16:05 +03:00
|
|
|
int32_t xPos = aEvent->ScreenX(CallerType::System);
|
|
|
|
int32_t yPos = aEvent->ScreenY(CallerType::System);
|
2007-07-04 19:49:38 +04:00
|
|
|
|
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;
|
|
|
|
}
|