mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 798226 - allow the anchor arrow on a panel to move while the popup is open. r=enndeakin
This commit is contained in:
parent
7a5086e339
commit
7f48b6b697
@ -555,6 +555,8 @@ nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
|
||||
mYPos = aYPos;
|
||||
mAdjustOffsetForContextMenu = false;
|
||||
mPosition = POPUPPOSITION_UNKNOWN;
|
||||
mVFlip = false;
|
||||
mHFlip = false;
|
||||
|
||||
// if aAttributesOverride is true, then the popupanchor, popupalign and
|
||||
// position attributes on the <popup> override those values passed in.
|
||||
@ -1183,12 +1185,19 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove)
|
||||
}
|
||||
|
||||
// mXPos and mYPos specify an additonal offset passed to OpenPopup that
|
||||
// should be added to the position
|
||||
if (IsDirectionRTL())
|
||||
screenPoint.x -= presContext->CSSPixelsToAppUnits(mXPos);
|
||||
else
|
||||
screenPoint.x += presContext->CSSPixelsToAppUnits(mXPos);
|
||||
screenPoint.y += presContext->CSSPixelsToAppUnits(mYPos);
|
||||
// should be added to the position. We also add the offset to the anchor
|
||||
// pos so a later flip/resize takes the offset into account.
|
||||
nscoord anchorXOffset = presContext->CSSPixelsToAppUnits(mXPos);
|
||||
if (IsDirectionRTL()) {
|
||||
screenPoint.x -= anchorXOffset;
|
||||
anchorRect.x -= anchorXOffset;
|
||||
} else {
|
||||
screenPoint.x += anchorXOffset;
|
||||
anchorRect.x += anchorXOffset;
|
||||
}
|
||||
nscoord anchorYOffset = presContext->CSSPixelsToAppUnits(mYPos);
|
||||
screenPoint.y += anchorYOffset;
|
||||
anchorRect.y += anchorYOffset;
|
||||
|
||||
// If this is a noautohide popup, set the screen coordinates of the popup.
|
||||
// This way, the popup stays at the location where it was opened even when
|
||||
|
@ -21,6 +21,7 @@ MOCHITEST_FILES = \
|
||||
test_tree_column_reorder.xul \
|
||||
tree_shared.js \
|
||||
test_mousecapture_area.html \
|
||||
test_popupanchor.xul \
|
||||
popup_shared.js \
|
||||
test_videocontrols.html \
|
||||
test_videocontrols_video_direction.html \
|
||||
|
271
toolkit/content/tests/widgets/test_popupanchor.xul
Normal file
271
toolkit/content/tests/widgets/test_popupanchor.xul
Normal file
@ -0,0 +1,271 @@
|
||||
<?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 Anchor Tests"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<title>Popup Popup Tests</title>
|
||||
|
||||
<panel id="testPanel"
|
||||
type="arrow"
|
||||
noautohide="true">
|
||||
</panel>
|
||||
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script>
|
||||
<![CDATA[
|
||||
var anchor, panel, arrow;
|
||||
|
||||
function isArrowPositionedOn(side, offset) {
|
||||
var arrowRect = arrow.getBoundingClientRect();
|
||||
var arrowMidX = (arrowRect.left + arrowRect.right) / 2;
|
||||
var arrowMidY = (arrowRect.top + arrowRect.bottom) / 2;
|
||||
var panelRect = panel.getBoundingClientRect();
|
||||
var panelMidX = (panelRect.left + panelRect.right) / 2;
|
||||
var panelMidY = (panelRect.top + panelRect.bottom) / 2;
|
||||
// First check the "flip" of the panel is correct. If we are expecting the
|
||||
// arrow to be pointing to the left side of the anchor, the arrow must
|
||||
// also be on the left side of the panel (and vice-versa)
|
||||
// XXX - on OSX, the arrow seems to always be exactly in the center, hence
|
||||
// the 'equals' sign in the "<=" and ">=" comparisons. NFI why though...
|
||||
switch (side) {
|
||||
case "left":
|
||||
ok(arrowMidX <= panelMidX, "arrow should be on the left of the panel");
|
||||
break;
|
||||
case "right":
|
||||
ok(arrowMidX >= panelMidX, "arrow should be on the right of the panel");
|
||||
break;
|
||||
case "top":
|
||||
ok(arrowMidY <= panelMidY, "arrow should be on the top of the panel");
|
||||
break;
|
||||
case "bottom":
|
||||
ok(arrowMidY >= panelMidY, "arrow should be on the bottom of the panel");
|
||||
break;
|
||||
default:
|
||||
ok(false, "invalid position " + where);
|
||||
break;
|
||||
}
|
||||
function is_close(got, exp, msg) {
|
||||
// on some platforms we see differences of a fraction of a pixel - so
|
||||
// allow any difference of < 1 pixels as being OK.
|
||||
ok(Math.abs(got - exp) < 1, msg + ": " + got + " should be equal to " + exp);
|
||||
}
|
||||
// Now check the arrow really is pointing where we expect. The middle of
|
||||
// the arrow should be pointing exactly to the left (or right) side of the
|
||||
// anchor rect, +- any offsets.
|
||||
offset = offset || 0; // no param means no offset expected.
|
||||
var anchorRect = anchor.getBoundingClientRect();
|
||||
var anchorPos = anchorRect[side];
|
||||
switch (side) {
|
||||
case "left":
|
||||
case "right":
|
||||
is_close(arrowMidX - anchorPos, offset, "arrow should be " + offset + "px from " + side + " side of anchor");
|
||||
is_close(panelRect.top, anchorRect.bottom, "top of panel should be at bottom of anchor");
|
||||
break;
|
||||
case "top":
|
||||
case "bottom":
|
||||
is_close(arrowMidY - anchorPos, offset, "arrow should be " + offset + "px from " + side + " side of anchor");
|
||||
is_close(panelRect.right, anchorRect.left, "right of panel should be left of anchor");
|
||||
break;
|
||||
default:
|
||||
ok(false, "unknown side " + side);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function openPopup(position, callback) {
|
||||
panel.addEventListener("popupshown", function popupshown() {
|
||||
panel.removeEventListener("popupshown", popupshown);
|
||||
callback();
|
||||
}, false);
|
||||
panel.openPopup(anchor, position);
|
||||
}
|
||||
|
||||
var tests = {
|
||||
// A panel with the anchor after_end - the anchor should not move on resize
|
||||
simpleResizeHorizontal: function(next, bHorizontal) {
|
||||
openPopup("after_end", function() {
|
||||
isArrowPositionedOn("right");
|
||||
var origPanelRect = panel.getBoundingClientRect();
|
||||
panel.sizeTo(100, 100);
|
||||
isArrowPositionedOn("right"); // should not have flipped, so still "right"
|
||||
panel.sizeTo(origPanelRect.width, origPanelRect.height);
|
||||
isArrowPositionedOn("right"); // should not have flipped, so still "right"
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
simpleResizeVertical: function(next) {
|
||||
openPopup("start_after", function() {
|
||||
isArrowPositionedOn("bottom");
|
||||
var origPanelRect = panel.getBoundingClientRect();
|
||||
panel.sizeTo(100, 100);
|
||||
isArrowPositionedOn("bottom"); // should not have flipped
|
||||
panel.sizeTo(origPanelRect.width, origPanelRect.height);
|
||||
isArrowPositionedOn("bottom"); // should not have flipped
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
flippingResizeHorizontal: function(next, bHorizontal) {
|
||||
openPopup("after_end", function() {
|
||||
isArrowPositionedOn("right");
|
||||
panel.sizeTo(anchor.getBoundingClientRect().left + 50, 50);
|
||||
isArrowPositionedOn("left"); // check it flipped and has zero offset.
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
flippingResizeVertical: function(next, bHorizontal) {
|
||||
openPopup("start_after", function() {
|
||||
isArrowPositionedOn("bottom");
|
||||
panel.sizeTo(50, anchor.getBoundingClientRect().top + 50);
|
||||
isArrowPositionedOn("top"); // check it flipped and has zero offset.
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
simpleMoveToAnchorHorizontal: function(next) {
|
||||
openPopup("after_end", function() {
|
||||
isArrowPositionedOn("right");
|
||||
panel.moveToAnchor(anchor, "after_end", 20, 0);
|
||||
// the anchor and the panel should have moved 20px right without flipping.
|
||||
isArrowPositionedOn("right", 20);
|
||||
panel.moveToAnchor(anchor, "after_end", -20, 0);
|
||||
// the anchor and the panel should have moved 20px left without flipping.
|
||||
isArrowPositionedOn("right", -20);
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
simpleMoveToAnchorVertical: function(next) {
|
||||
openPopup("start_after", function() {
|
||||
isArrowPositionedOn("bottom");
|
||||
panel.moveToAnchor(anchor, "start_after", 0, 20);
|
||||
// the anchor and the panel should have moved 20px down without flipping.
|
||||
isArrowPositionedOn("bottom", 20);
|
||||
panel.moveToAnchor(anchor, "start_after", 0, -20);
|
||||
// the anchor and the panel should have moved 20px up without flipping.
|
||||
isArrowPositionedOn("bottom", -20);
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
// Do a moveToAnchor that causes the panel to flip horizontally
|
||||
flippingMoveToAnchorHorizontal: function(next) {
|
||||
var anchorRight = anchor.getBoundingClientRect().right;
|
||||
// Size the panel such that it only just fits from the left-hand side of
|
||||
// the window to the right of the anchor - thus, it will fit when
|
||||
// anchored to the right-hand side of the anchor.
|
||||
panel.sizeTo(anchorRight - 10, 100);
|
||||
openPopup("after_end", function() {
|
||||
isArrowPositionedOn("right");
|
||||
// Ask for it to be anchored 1/2 way between the left edge of the window
|
||||
// and the anchor right - it can't fit with the panel on the left/arrow
|
||||
// on the right, so it must flip (arrow on the left, panel on the right)
|
||||
var offset = Math.floor(-anchorRight / 2);
|
||||
panel.moveToAnchor(anchor, "after_end", offset, 0);
|
||||
isArrowPositionedOn("left", offset); // should have flipped and have the offset.
|
||||
// resize back to original and move to a zero offset - it should flip back.
|
||||
panel.sizeTo(anchorRight - 10, 100);
|
||||
panel.moveToAnchor(anchor, "after_end", 0, 0);
|
||||
isArrowPositionedOn("right"); // should have flipped back and no offset
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
// Do a moveToAnchor that causes the panel to flip vertically
|
||||
flippingMoveToAnchorVertical: function(next) {
|
||||
var anchorBottom = anchor.getBoundingClientRect().bottom;
|
||||
// See comments above in flippingMoveToAnchorHorizontal, but read
|
||||
// "top/bottom" instead of "left/right"
|
||||
panel.sizeTo(100, anchorBottom - 10);
|
||||
openPopup("start_after", function() {
|
||||
isArrowPositionedOn("bottom");
|
||||
var offset = Math.floor(-anchorBottom / 2);
|
||||
panel.moveToAnchor(anchor, "start_after", 0, offset);
|
||||
isArrowPositionedOn("top", offset);
|
||||
panel.sizeTo(100, anchorBottom - 10);
|
||||
panel.moveToAnchor(anchor, "start_after", 0, 0);
|
||||
isArrowPositionedOn("bottom");
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
veryWidePanel: function(next) {
|
||||
openPopup("after_end", function() {
|
||||
var origArrowRect = arrow.getBoundingClientRect();
|
||||
// Now move it such that the arrow can't be at either end of the panel but
|
||||
// instead somewhere in the middle as that is the only way things fit.
|
||||
// XXX - these tests might not be quite correct even when bug 812943
|
||||
// is fixed.
|
||||
panel.sizeTo(window.innerWidth - 10, 60);
|
||||
todo_is(panel.getBoundingClientRect().width, window.innerWidth - 10, "Bug 812943 - width is what we requested.")
|
||||
// the arrow should not have moved.
|
||||
var curArrowRect = arrow.getBoundingClientRect();
|
||||
todo_is(curArrowRect.left, origArrowRect.left, "Bug 812943 - arrow should not have moved");
|
||||
is(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
|
||||
next();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
panel.sizeTo(50, 50);
|
||||
|
||||
var testIter = Iterator(tests);
|
||||
|
||||
function runNextTest() {
|
||||
var name, func;
|
||||
try {
|
||||
[name, func] = testIter.next();
|
||||
} catch (err if err instanceof StopIteration) {
|
||||
// out of tests
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
SimpleTest.info("sub-test " + name + " starting");
|
||||
try {
|
||||
func.call(tests, function() {
|
||||
setTimeout(function() {
|
||||
panel.hidePopup();
|
||||
panel.sizeTo(50, 50);
|
||||
runNextTest();
|
||||
}, 0);
|
||||
});
|
||||
} catch (ex) {
|
||||
SimpleTest.ok(false, "sub-test " + name + " failed: " + ex.toString() +"\n"+ex.stack);
|
||||
runNextTest();
|
||||
}
|
||||
}
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addEventListener("load", function() {
|
||||
anchor = document.getElementById("anchor");
|
||||
panel = document.getElementById("testPanel");
|
||||
arrow = document.getAnonymousElementByAttribute(panel, "anonid", "arrow");
|
||||
// Cancel the arrow panel slide-in transition (bug 767133) so the size and
|
||||
// position are "stable" enough to test without jumping through hoops...
|
||||
arrow.style.transition = "none";
|
||||
runTest();
|
||||
});
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<!-- Our tests assume at least 100px around the anchor on all sides, else the
|
||||
panel may flip when we don't expect it to
|
||||
-->
|
||||
<div style="margin: 100px 100px 100px 100px;">
|
||||
<p id="display">The anchor --> <span id="anchor">v</span> <--</p>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</window>
|
@ -340,10 +340,45 @@
|
||||
</content>
|
||||
<implementation>
|
||||
<field name="_fadeTimer">null</field>
|
||||
</implementation>
|
||||
<handlers>
|
||||
<handler event="popupshowing" phase="target">
|
||||
<![CDATA[
|
||||
<method name="sizeTo">
|
||||
<parameter name="aWidth"/>
|
||||
<parameter name="aHeight"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this.popupBoxObject.sizeTo(aWidth, aHeight);
|
||||
if (this.state == "open")
|
||||
this.adjustArrowPosition();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
<method name="moveTo">
|
||||
<parameter name="aLeft"/>
|
||||
<parameter name="aTop"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this.popupBoxObject.moveTo(aLeft, aTop);
|
||||
if (this.state == "open")
|
||||
this.adjustArrowPosition();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
<method name="moveToAnchor">
|
||||
<parameter name="aAnchorElement"/>
|
||||
<parameter name="aPosition"/>
|
||||
<parameter name="aX"/>
|
||||
<parameter name="aY"/>
|
||||
<parameter name="aAttributesOverride"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this.popupBoxObject.moveToAnchor(aAnchorElement, aPosition, aX, aY, aAttributesOverride);
|
||||
if (this.state == "open")
|
||||
this.adjustArrowPosition();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
<method name="adjustArrowPosition">
|
||||
<body>
|
||||
<![CDATA[
|
||||
var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow");
|
||||
|
||||
var anchor = this.anchorNode;
|
||||
@ -389,7 +424,14 @@
|
||||
}
|
||||
|
||||
arrow.hidden = false;
|
||||
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
<handlers>
|
||||
<handler event="popupshowing" phase="target">
|
||||
<![CDATA[
|
||||
this.adjustArrowPosition();
|
||||
// set fading
|
||||
var fade = this.getAttribute("fade");
|
||||
var fadeDelay = (fade == "fast") ? 1 : fade == "slow" ? 4000 : 0;
|
||||
@ -508,4 +550,3 @@
|
||||
</binding>
|
||||
|
||||
</bindings>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user