зеркало из https://github.com/mozilla/pjs.git
Bug 387659, popup coordinates are not set within popupshowing event,r=eli,sr=bz
This commit is contained in:
Родитель
5a29248630
Коммит
6112095836
|
@ -46,6 +46,7 @@
|
|||
#include "nsIRollupListener.h"
|
||||
#include "nsIMenuRollup.h"
|
||||
#include "nsIDOMKeyListener.h"
|
||||
#include "nsPoint.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsITimer.h"
|
||||
|
@ -359,8 +360,9 @@ public:
|
|||
// This is used by the implementation of nsIDOMXULDocument::GetPopupRangeParent
|
||||
// and nsIDOMXULDocument::GetPopupRangeOffset.
|
||||
void GetMouseLocation(nsIDOMNode** aNode, PRInt32* aOffset);
|
||||
// set the mouse event that was used to activate the next popup to be opened.
|
||||
void SetMouseLocation(nsIDOMEvent* aEvent);
|
||||
// set the mouse event that was used to activate the next popup, specified by
|
||||
// aPopup, to be opened.
|
||||
void SetMouseLocation(nsIDOMEvent* aEvent, nsIContent* aPopup);
|
||||
|
||||
/**
|
||||
* Open a <menu> given its content node. If aSelectFirstItem is
|
||||
|
@ -626,6 +628,7 @@ protected:
|
|||
// range parent and offset set in SetMouseLocation
|
||||
nsCOMPtr<nsIDOMNode> mRangeParent;
|
||||
PRInt32 mRangeOffset;
|
||||
nsPoint mCachedMousePoint;
|
||||
|
||||
// set to the currently active menu bar, if any
|
||||
nsMenuBarFrame* mActiveMenuBar;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMNSEvent.h"
|
||||
#include "nsIDOMNSUIEvent.h"
|
||||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
@ -236,13 +237,40 @@ nsXULPopupManager::GetMouseLocation(nsIDOMNode** aNode, PRInt32* aOffset)
|
|||
}
|
||||
|
||||
void
|
||||
nsXULPopupManager::SetMouseLocation(nsIDOMEvent* aEvent)
|
||||
nsXULPopupManager::SetMouseLocation(nsIDOMEvent* aEvent, nsIContent* aPopup)
|
||||
{
|
||||
mCachedMousePoint = nsPoint(0, 0);
|
||||
|
||||
nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(aEvent);
|
||||
NS_ASSERTION(uiEvent, "Expected an nsIDOMNSUIEvent");
|
||||
NS_ASSERTION(!aEvent || uiEvent, "Expected an nsIDOMNSUIEvent");
|
||||
if (uiEvent) {
|
||||
uiEvent->GetRangeParent(getter_AddRefs(mRangeParent));
|
||||
uiEvent->GetRangeOffset(&mRangeOffset);
|
||||
|
||||
// get the event coordinates relative to the root frame of the document
|
||||
// containing the popup.
|
||||
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aEvent));
|
||||
if (privateEvent) {
|
||||
NS_ASSERTION(aPopup, "Expected a popup node");
|
||||
nsEvent* event;
|
||||
nsresult rv = privateEvent->GetInternalNSEvent(&event);
|
||||
if (NS_SUCCEEDED(rv) && event) {
|
||||
nsIDocument* doc = aPopup->GetCurrentDoc();
|
||||
if (doc) {
|
||||
nsIPresShell* presShell = doc->GetPrimaryShell();
|
||||
if (presShell) {
|
||||
nsPresContext* presContext = presShell->GetPresContext();
|
||||
nsIFrame* rootFrame = presShell->GetRootFrame();
|
||||
if (rootFrame && presContext) {
|
||||
nsPoint pnt =
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(event, rootFrame);
|
||||
mCachedMousePoint = nsPoint(presContext->AppUnitsToDevPixels(pnt.x),
|
||||
presContext->AppUnitsToDevPixels(pnt.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mRangeParent = nsnull;
|
||||
|
@ -293,6 +321,7 @@ nsXULPopupManager::ShowMenu(nsIContent *aMenu,
|
|||
popupFrame->InitializePopup(aMenu, position, 0, 0, PR_TRUE);
|
||||
|
||||
if (aAsynchronous) {
|
||||
SetMouseLocation(nsnull, nsnull);
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new nsXULPopupShowingEvent(popupFrame->GetContent(), aMenu,
|
||||
parentIsContextMenu, aSelectFirstItem);
|
||||
|
@ -539,7 +568,7 @@ nsXULPopupManager::HidePopupCallback(nsIContent* aPopup,
|
|||
|
||||
// send the popuphidden event synchronously. This event has no default behaviour.
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsEvent event(PR_TRUE, NS_XUL_POPUP_HIDDEN);
|
||||
nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_HIDDEN, nsnull, nsMouseEvent::eReal);
|
||||
nsEventDispatcher::Dispatch(aPopup, aPopupFrame->PresContext(),
|
||||
&event, nsnull, &status);
|
||||
|
||||
|
@ -678,8 +707,13 @@ nsXULPopupManager::FirePopupShowingEvent(nsIContent* aPopup,
|
|||
// is where those details would be retrieved. This removes the need for
|
||||
// all the globals people keep adding to nsIDOMXULDocument.
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsEvent event(PR_TRUE, NS_XUL_POPUP_SHOWING);
|
||||
nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_SHOWING, nsnull, nsMouseEvent::eReal);
|
||||
nsPoint pnt;
|
||||
event.widget = presShell->GetRootFrame()->
|
||||
GetClosestView()->GetNearestWidget(&pnt);
|
||||
event.refPoint = mCachedMousePoint;
|
||||
nsEventDispatcher::Dispatch(aPopup, aPresContext, &event, nsnull, &status);
|
||||
mCachedMousePoint = nsPoint(0, 0);
|
||||
|
||||
// it is common to append content to the menu during the popupshowing event.
|
||||
// Flush the notifications so that the frames are up to date before showing
|
||||
|
@ -712,7 +746,7 @@ nsXULPopupManager::FirePopupHidingEvent(nsIContent* aPopup,
|
|||
nsCOMPtr<nsIPresShell> presShell = aPresContext->PresShell();
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsEvent event(PR_TRUE, NS_XUL_POPUP_HIDING);
|
||||
nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_HIDING, nsnull, nsMouseEvent::eReal);
|
||||
nsEventDispatcher::Dispatch(aPopup, aPresContext, &event, nsnull, &status);
|
||||
|
||||
// get frame again in case it went away
|
||||
|
|
|
@ -48,6 +48,7 @@ _TEST_FILES = test_bug360220.xul \
|
|||
test_bug359754.xul \
|
||||
test_bug365773.xul \
|
||||
test_colorpicker_popup.xul \
|
||||
test_popup_coords.xul \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
<?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="Popup Coordinate Tests"
|
||||
onload="setTimeout(openThePopup, 0, 'outer');"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<title>Popup Tests</title>
|
||||
<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>
|
||||
|
||||
<deck style="margin-top: 5px; padding-top: 5px;">
|
||||
<label id="outer" popup="outerpopup" value="Popup"/>
|
||||
</deck>
|
||||
|
||||
<panel id="outerpopup"
|
||||
onpopupshowing="popupShowingEventOccured(event);"
|
||||
onpopupshown="eventOccured(event); openThePopup('inner')"
|
||||
onpopuphiding="eventOccured(event);"
|
||||
onpopuphidden="eventOccured(event); SimpleTest.finish();">
|
||||
<button id="item1" label="First"/>
|
||||
<label id="inner" value="Second" popup="innerpopup"/>
|
||||
<button id="item2" label="Third"/>
|
||||
</panel>
|
||||
|
||||
<menupopup id="innerpopup"
|
||||
onpopupshowing="popupShowingEventOccured(event);"
|
||||
onpopupshown="eventOccured(event); event.target.hidePopup();"
|
||||
onpopuphiding="eventOccured(event);"
|
||||
onpopuphidden="eventOccured(event); document.getElementById('outerpopup').hidePopup();">
|
||||
<menuitem id="inner1" label="Inner First"/>
|
||||
<menuitem id="inner2" label="Inner Second"/>
|
||||
</menupopup>
|
||||
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function openThePopup(id)
|
||||
{
|
||||
if (id == "inner")
|
||||
document.getElementById("item1").focus();
|
||||
|
||||
var trigger = document.getElementById(id);
|
||||
synthesizeMouse(trigger, 4, 5, { });
|
||||
}
|
||||
|
||||
function eventOccured(event)
|
||||
{
|
||||
var testname = event.type + " on " + event.target.id + " ";
|
||||
ok(event instanceof MouseEvent, testname + "is a mouse event");
|
||||
is(event.clientX, 0, testname + "clientX");
|
||||
is(event.clientY, 0, testname + "clientY");
|
||||
is(event.rangeParent, null, testname + "rangeParent");
|
||||
is(event.rangeOffset, 0, testname + "rangeOffset");
|
||||
}
|
||||
|
||||
function popupShowingEventOccured(event)
|
||||
{
|
||||
// the popupshowing event should have the event coordinates and
|
||||
// range position filled in.
|
||||
var testname = "popupshowing on " + event.target.id + " ";
|
||||
ok(event instanceof MouseEvent, testname + "is a mouse event");
|
||||
|
||||
var trigger = document.getElementById(event.target.id == "outerpopup" ? "outer" : "inner");
|
||||
var rect = trigger.getBoundingClientRect();
|
||||
is(event.clientX, Math.round(rect.left) + 4, testname + "clientX");
|
||||
is(event.clientY, Math.round(rect.top) + 5, testname + "clientY");
|
||||
// rangeOffset should be just after the trigger element. As rangeOffset
|
||||
// considers the zeroth position to be before the first element, the value
|
||||
// should be one higher than its index within its parent.
|
||||
is(event.rangeParent, trigger.parentNode, testname + "rangeParent");
|
||||
is(event.rangeOffset, Array.indexOf(trigger.parentNode.childNodes, trigger) + 1, testname + "rangeOffset");
|
||||
}
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display">
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
</window>
|
Загрузка…
Ссылка в новой задаче