Bug 554937 - Implement arrow panels and use them for some notifications, r=gavin, a=betaN+
|
@ -338,7 +338,7 @@
|
|||
|
||||
<menupopup id="placesContext"/>
|
||||
|
||||
<panel id="notification-popup" position="after_start" noautofocus="true" hidden="true"/>
|
||||
<panel id="notification-popup" type="arrow" position="after_start" noautofocus="true" hidden="true"/>
|
||||
|
||||
<!-- Popup for site identity information -->
|
||||
<panel id="identity-popup" position="after_start" hidden="true" noautofocus="true"
|
||||
|
|
|
@ -1916,8 +1916,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
}
|
||||
|
||||
/* Popup Bounding Box */
|
||||
#identity-popup,
|
||||
#notification-popup {
|
||||
#identity-popup {
|
||||
-moz-appearance: none;
|
||||
-moz-window-shadow: none;
|
||||
background-color: transparent;
|
||||
|
@ -1938,8 +1937,8 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
|
||||
#notification-popup {
|
||||
color: #fff;
|
||||
margin-top: -1px;
|
||||
margin-left: -27px;
|
||||
margin-left: -16px;
|
||||
margin-right: -16px;
|
||||
}
|
||||
|
||||
#notification-popup-box {
|
||||
|
|
|
@ -40,8 +40,7 @@
|
|||
/* Bug 413060, comment 16: Vista Aero is a special case where we use a
|
||||
tooltip appearance for the address bar popup panels */
|
||||
#identity-popup,
|
||||
#editBookmarkPanel,
|
||||
#notification-popup {
|
||||
#editBookmarkPanel {
|
||||
-moz-appearance: tooltip;
|
||||
color: InfoText;
|
||||
}
|
||||
|
|
|
@ -1848,8 +1848,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
|||
}
|
||||
|
||||
/* Popup Bounding Box */
|
||||
#identity-popup,
|
||||
#notification-popup {
|
||||
#identity-popup {
|
||||
-moz-appearance: menupopup;
|
||||
color: MenuText;
|
||||
}
|
||||
|
@ -1866,7 +1865,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
|||
/* Notification popup */
|
||||
#notification-popup {
|
||||
padding: 10px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.popup-notification-icon {
|
||||
|
|
|
@ -377,6 +377,7 @@ GK_ATOM(fixedList, "Fixed-list")
|
|||
GK_ATOM(flags, "flags")
|
||||
GK_ATOM(flex, "flex")
|
||||
GK_ATOM(flexgroup, "flexgroup")
|
||||
GK_ATOM(flip, "flip")
|
||||
GK_ATOM(floating, "floating")
|
||||
GK_ATOM(floatList, "Float-list")
|
||||
GK_ATOM(floor, "floor")
|
||||
|
|
|
@ -113,6 +113,7 @@ nsMenuPopupFrame::nsMenuPopupFrame(nsIPresShell* aShell, nsStyleContext* aContex
|
|||
mPopupState(ePopupClosed),
|
||||
mPopupAlignment(POPUPALIGNMENT_NONE),
|
||||
mPopupAnchor(POPUPALIGNMENT_NONE),
|
||||
mFlipBoth(PR_FALSE),
|
||||
mIsOpenChanged(PR_FALSE),
|
||||
mIsContextMenu(PR_FALSE),
|
||||
mAdjustOffsetForContextMenu(PR_FALSE),
|
||||
|
@ -575,10 +576,11 @@ nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
|
|||
// position attributes on the <popup> override those values passed in.
|
||||
// If false, those attributes are only used if the values passed in are empty
|
||||
if (aAnchorContent) {
|
||||
nsAutoString anchor, align, position;
|
||||
nsAutoString anchor, align, position, flip;
|
||||
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupanchor, anchor);
|
||||
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupalign, align);
|
||||
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::position, position);
|
||||
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::flip, flip);
|
||||
|
||||
if (aAttributesOverride) {
|
||||
// if the attributes are set, clear the offset position. Otherwise,
|
||||
|
@ -592,6 +594,8 @@ nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
|
|||
position.Assign(aPosition);
|
||||
}
|
||||
|
||||
mFlipBoth = flip.EqualsLiteral("both");
|
||||
|
||||
if (position.EqualsLiteral("before_start")) {
|
||||
mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
|
||||
mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
|
||||
|
@ -676,6 +680,7 @@ nsMenuPopupFrame::InitializePopupAtScreen(nsIContent* aTriggerContent,
|
|||
mTriggerContent = aTriggerContent;
|
||||
mScreenXPos = aXPos;
|
||||
mScreenYPos = aYPos;
|
||||
mFlipBoth = PR_FALSE;
|
||||
mPopupAnchor = POPUPALIGNMENT_NONE;
|
||||
mPopupAlignment = POPUPALIGNMENT_NONE;
|
||||
mIsContextMenu = aIsContextMenu;
|
||||
|
@ -692,6 +697,7 @@ nsMenuPopupFrame::InitializePopupWithAnchorAlign(nsIContent* aAnchorContent,
|
|||
|
||||
mPopupState = ePopupShowing;
|
||||
mAdjustOffsetForContextMenu = PR_FALSE;
|
||||
mFlipBoth = PR_FALSE;
|
||||
|
||||
// this popup opening function is provided for backwards compatibility
|
||||
// only. It accepts either coordinates or an anchor and alignment value
|
||||
|
@ -776,6 +782,7 @@ nsMenuPopupFrame::HidePopup(PRBool aDeselectMenu, nsPopupState aNewState)
|
|||
}
|
||||
}
|
||||
mTriggerContent = nsnull;
|
||||
mAnchorContent = nsnull;
|
||||
}
|
||||
|
||||
// when invisible and about to be closed, HidePopup has already been called,
|
||||
|
@ -873,7 +880,7 @@ nsMenuPopupFrame::GetRootViewForPopup(nsIFrame* aStartFrame)
|
|||
|
||||
nsPoint
|
||||
nsMenuPopupFrame::AdjustPositionForAnchorAlign(const nsRect& anchorRect,
|
||||
PRBool& aHFlip, PRBool& aVFlip)
|
||||
FlipStyle& aHFlip, FlipStyle& aVFlip)
|
||||
{
|
||||
// flip the anchor and alignment for right-to-left
|
||||
PRInt8 popupAnchor(mPopupAnchor);
|
||||
|
@ -930,9 +937,20 @@ nsMenuPopupFrame::AdjustPositionForAnchorAlign(const nsRect& anchorRect,
|
|||
// the values of the constants are such that both must be positive or both
|
||||
// must be negative. A special case, used for overlap, allows flipping
|
||||
// vertically as well.
|
||||
aHFlip = (popupAnchor == -popupAlign);
|
||||
aVFlip = ((popupAnchor > 0) == (popupAlign > 0)) ||
|
||||
(popupAnchor == POPUPALIGNMENT_TOPLEFT && popupAlign == POPUPALIGNMENT_TOPLEFT);
|
||||
// If we are flipping in both directions, we want to set a flip style both
|
||||
// horizontally and vertically. However, we want to flip on the inside edge
|
||||
// of the anchor. Consider the example of a typical dropdown menu.
|
||||
// Vertically, we flip the popup on the outside edges of the anchor menu,
|
||||
// however horizontally, we want to to use the inside edges so the popup
|
||||
// still appears underneath the anchor menu instead of floating off the
|
||||
// side of the menu.
|
||||
FlipStyle anchorEdge = mFlipBoth ? FlipStyle_Inside: FlipStyle_None;
|
||||
aHFlip = (popupAnchor == -popupAlign) ? FlipStyle_Outside : anchorEdge;
|
||||
if (((popupAnchor > 0) == (popupAlign > 0)) ||
|
||||
(popupAnchor == POPUPALIGNMENT_TOPLEFT && popupAlign == POPUPALIGNMENT_TOPLEFT))
|
||||
aVFlip = FlipStyle_Outside;
|
||||
else
|
||||
aVFlip = anchorEdge;
|
||||
|
||||
return pnt;
|
||||
}
|
||||
|
@ -942,7 +960,7 @@ nsMenuPopupFrame::FlipOrResize(nscoord& aScreenPoint, nscoord aSize,
|
|||
nscoord aScreenBegin, nscoord aScreenEnd,
|
||||
nscoord aAnchorBegin, nscoord aAnchorEnd,
|
||||
nscoord aMarginBegin, nscoord aMarginEnd,
|
||||
nscoord aOffsetForContextMenu, PRBool aFlip,
|
||||
nscoord aOffsetForContextMenu, FlipStyle aFlip,
|
||||
PRPackedBool* aFlipSide)
|
||||
{
|
||||
// all of the coordinates used here are in app units relative to the screen
|
||||
|
@ -951,17 +969,21 @@ nsMenuPopupFrame::FlipOrResize(nscoord& aScreenPoint, nscoord aSize,
|
|||
// at its current position, the popup would extend past the left or top
|
||||
// edge of the screen, so it will have to be moved or resized.
|
||||
if (aFlip) {
|
||||
// for inside flips, we flip on the opposite side of the anchor
|
||||
nscoord startpos = aFlip == FlipStyle_Outside ? aAnchorBegin : aAnchorEnd;
|
||||
nscoord endpos = aFlip == FlipStyle_Outside ? aAnchorEnd : aAnchorBegin;
|
||||
|
||||
// check whether there is more room to the left and right (or top and
|
||||
// bottom) of the anchor and put the popup on the side with more room.
|
||||
if (aAnchorBegin - aScreenBegin >= aScreenEnd - aAnchorEnd) {
|
||||
if (startpos - aScreenBegin >= aScreenEnd - endpos) {
|
||||
aScreenPoint = aScreenBegin;
|
||||
popupSize = aAnchorBegin - aScreenPoint - aMarginEnd;
|
||||
popupSize = startpos - aScreenPoint - aMarginEnd;
|
||||
}
|
||||
else {
|
||||
// flip such that the popup is to the right or bottom of the anchor
|
||||
// point instead. However, when flipping use the same margin size.
|
||||
*aFlipSide = PR_TRUE;
|
||||
aScreenPoint = aAnchorEnd + aMarginEnd;
|
||||
aScreenPoint = endpos + aMarginEnd;
|
||||
// check if the new position is still off the right or bottom edge of
|
||||
// the screen. If so, resize the popup.
|
||||
if (aScreenPoint + aSize > aScreenEnd) {
|
||||
|
@ -977,9 +999,13 @@ nsMenuPopupFrame::FlipOrResize(nscoord& aScreenPoint, nscoord aSize,
|
|||
// at its current position, the popup would extend past the right or
|
||||
// bottom edge of the screen, so it will have to be moved or resized.
|
||||
if (aFlip) {
|
||||
// for inside flips, we flip on the opposite side of the anchor
|
||||
nscoord startpos = aFlip == FlipStyle_Outside ? aAnchorBegin : aAnchorEnd;
|
||||
nscoord endpos = aFlip == FlipStyle_Outside ? aAnchorEnd : aAnchorBegin;
|
||||
|
||||
// check whether there is more room to the left and right (or top and
|
||||
// bottom) of the anchor and put the popup on the side with more room.
|
||||
if (aScreenEnd - aAnchorEnd >= aAnchorBegin - aScreenBegin) {
|
||||
if (aScreenEnd - endpos >= startpos - aScreenBegin) {
|
||||
if (mIsContextMenu) {
|
||||
aScreenPoint = aScreenEnd - aSize;
|
||||
}
|
||||
|
@ -991,13 +1017,14 @@ nsMenuPopupFrame::FlipOrResize(nscoord& aScreenPoint, nscoord aSize,
|
|||
// flip such that the popup is to the left or top of the anchor point
|
||||
// instead.
|
||||
*aFlipSide = PR_TRUE;
|
||||
aScreenPoint = aAnchorBegin - aSize - aMarginBegin - aOffsetForContextMenu;
|
||||
aScreenPoint = startpos - aSize - aMarginBegin - aOffsetForContextMenu;
|
||||
|
||||
// check if the new position is still off the left or top edge of the
|
||||
// screen. If so, resize the popup.
|
||||
if (aScreenPoint < aScreenBegin) {
|
||||
aScreenPoint = aScreenBegin;
|
||||
if (!mIsContextMenu) {
|
||||
popupSize = aAnchorBegin - aScreenPoint - aMarginBegin;
|
||||
popupSize = startpos - aScreenPoint - aMarginBegin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1070,8 +1097,8 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, PRBool aIsMove)
|
|||
nsRect anchorRect = parentRect;
|
||||
|
||||
// indicators of whether the popup should be flipped or resized.
|
||||
PRBool hFlip = PR_FALSE, vFlip = PR_FALSE;
|
||||
|
||||
FlipStyle hFlip = FlipStyle_None, vFlip = FlipStyle_None;
|
||||
|
||||
nsMargin margin(0, 0, 0, 0);
|
||||
GetStyleMargin()->GetMargin(margin);
|
||||
|
||||
|
@ -1151,13 +1178,13 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, PRBool aIsMove)
|
|||
margin.top + offsetForContextMenu);
|
||||
|
||||
// screen positioned popups can be flipped vertically but never horizontally
|
||||
vFlip = PR_TRUE;
|
||||
vFlip = FlipStyle_Outside;
|
||||
}
|
||||
|
||||
// if a panel is being moved, don't flip it. But always do this for content
|
||||
// shells, so that the popup doesn't extend outside the containing frame.
|
||||
if (aIsMove && mPopupType == ePopupTypePanel && !mInContentShell) {
|
||||
hFlip = vFlip = PR_FALSE;
|
||||
hFlip = vFlip = FlipStyle_None;
|
||||
}
|
||||
|
||||
nsRect screenRect = GetConstraintRect(anchorRect, rootScreenRect);
|
||||
|
|
|
@ -92,6 +92,15 @@ enum nsPopupState {
|
|||
ePopupInvisible
|
||||
};
|
||||
|
||||
// How a popup may be flipped. Flipping to the outside edge is like how
|
||||
// a submenu would work. The entire popup is flipped to the opposite side
|
||||
// of the anchor.
|
||||
enum FlipStyle {
|
||||
FlipStyle_None = 0,
|
||||
FlipStyle_Outside = 1,
|
||||
FlipStyle_Inside = 2
|
||||
};
|
||||
|
||||
// values are selected so that the direction can be flipped just by
|
||||
// changing the sign
|
||||
#define POPUPALIGNMENT_NONE 0
|
||||
|
@ -345,8 +354,8 @@ protected:
|
|||
// return the position where the popup should be, when it should be
|
||||
// anchored at anchorRect. aHFlip and aVFlip will be set if the popup may be
|
||||
// flipped in that direction if there is not enough space available.
|
||||
nsPoint AdjustPositionForAnchorAlign(const nsRect& anchorRect, PRBool& aHFlip, PRBool& aVFlip);
|
||||
|
||||
nsPoint AdjustPositionForAnchorAlign(const nsRect& anchorRect,
|
||||
FlipStyle& aHFlip, FlipStyle& aVFlip);
|
||||
|
||||
// check if the popup will fit into the available space and resize it. This
|
||||
// method handles only one axis at a time so is called twice, once for
|
||||
|
@ -361,13 +370,13 @@ protected:
|
|||
// aMarginBegin - the left or top margin of the popup
|
||||
// aMarginEnd - the right or bottom margin of the popup
|
||||
// aOffsetForContextMenu - the additional offset to add for context menus
|
||||
// aFlip - whether to flip or resize the popup when there isn't space
|
||||
// aFlip - how to flip or resize the popup when there isn't space
|
||||
// aFlipSide - pointer to where current flip mode is stored
|
||||
nscoord FlipOrResize(nscoord& aScreenPoint, nscoord aSize,
|
||||
nscoord aScreenBegin, nscoord aScreenEnd,
|
||||
nscoord aAnchorBegin, nscoord aAnchorEnd,
|
||||
nscoord aMarginBegin, nscoord aMarginEnd,
|
||||
nscoord aOffsetForContextMenu, PRBool aFlip,
|
||||
nscoord aOffsetForContextMenu, FlipStyle aFlip,
|
||||
PRPackedBool* aFlipSide);
|
||||
|
||||
// Move the popup to the position specified in its |left| and |top| attributes.
|
||||
|
@ -404,6 +413,7 @@ protected:
|
|||
// popup alignment relative to the anchor node
|
||||
PRInt8 mPopupAlignment;
|
||||
PRInt8 mPopupAnchor;
|
||||
PRPackedBool mFlipBoth; // flip in both directions
|
||||
|
||||
PRPackedBool mIsOpenChanged; // true if the open state changed since the last layout
|
||||
PRPackedBool mIsContextMenu; // true for context menus
|
||||
|
|
|
@ -146,5 +146,9 @@ _TEST_FILES += test_menubar.xul \
|
|||
window_menubar.xul
|
||||
endif
|
||||
|
||||
ifneq (gtk2,$(MOZ_WIDGET_TOOLKIT))
|
||||
_TEST_FILES += test_arrowpanel.xul
|
||||
endif
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
|
||||
|
|
|
@ -41,6 +41,10 @@ var popupTests = [
|
|||
},
|
||||
result: function (testname) {
|
||||
gExpectedTriggerNode = null;
|
||||
// menus are the anchor but non-menus are opened at screen coordinates
|
||||
is(gMenuPopup.anchorNode, gIsMenu ? gTrigger : null, testname + " anchorNode");
|
||||
// menus are opened internally, but non-menus have a mouse event which
|
||||
// triggered them
|
||||
is(gMenuPopup.triggerNode, gIsMenu ? null : gTrigger, testname + " triggerNode");
|
||||
is(document.popupNode, gIsMenu ? null : gTrigger, testname + " document.popupNode");
|
||||
is(document.tooltipNode, null, testname + " document.tooltipNode");
|
||||
|
@ -153,6 +157,7 @@ var popupTests = [
|
|||
// synthesizeMouse(gTrigger, 0, -12, { });
|
||||
},
|
||||
result: function(testname, step) {
|
||||
is(gMenuPopup.anchorNode, null, testname + " anchorNode");
|
||||
is(gMenuPopup.triggerNode, null, testname + " triggerNode");
|
||||
is(document.popupNode, null, testname + " document.popupNode");
|
||||
checkClosed("trigger", testname);
|
||||
|
@ -173,6 +178,7 @@ var popupTests = [
|
|||
result: function(testname, step) {
|
||||
// no triggerNode because it was opened without passing an event
|
||||
gExpectedTriggerNode = null;
|
||||
is(gMenuPopup.anchorNode, gTrigger, testname + " anchorNode");
|
||||
is(gMenuPopup.triggerNode, null, testname + " triggerNode");
|
||||
is(document.popupNode, null, testname + " document.popupNode");
|
||||
compareEdge(gTrigger, gMenuPopup, step, 0, 0, testname);
|
||||
|
@ -246,6 +252,7 @@ var popupTests = [
|
|||
},
|
||||
result: function(testname, step) {
|
||||
gExpectedTriggerNode = null;
|
||||
is(gMenuPopup.anchorNode, gTrigger, testname + " anchorNode");
|
||||
is(gMenuPopup.triggerNode, gCachedEvent.target, testname + " triggerNode");
|
||||
is(document.popupNode, gCachedEvent.target, testname + " document.popupNode");
|
||||
compareEdge(gTrigger, gMenuPopup, "end_after", 0, 0, testname);
|
||||
|
@ -360,6 +367,7 @@ var popupTests = [
|
|||
},
|
||||
result: function(testname, step) {
|
||||
gExpectedTriggerNode = null;
|
||||
is(gMenuPopup.anchorNode, null, testname + " anchorNode");
|
||||
is(gMenuPopup.triggerNode, null, testname + " triggerNode");
|
||||
is(document.popupNode, null, testname + " document.popupNode");
|
||||
var rect = gMenuPopup.getBoundingClientRect();
|
||||
|
@ -391,6 +399,7 @@ var popupTests = [
|
|||
},
|
||||
result: function(testname, step) {
|
||||
gExpectedTriggerNode = null;
|
||||
is(gMenuPopup.anchorNode, null, testname + " anchorNode");
|
||||
is(gMenuPopup.triggerNode, gCachedEvent.target, testname + " triggerNode");
|
||||
is(document.popupNode, gCachedEvent.target, testname + " document.popupNode");
|
||||
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
<?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="Arrow Panels"
|
||||
style="padding: 10px;"
|
||||
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>
|
||||
|
||||
<stack flex="1">
|
||||
<label id="topleft" value="Top Left" left="0" top="0"/>
|
||||
<label id="topright" value="Top Right" right="0" top="0"/>
|
||||
<label id="bottomleft" value="Bottom Left" left="0" bottom="0"/>
|
||||
<label id="bottomright" value="Bottom Right" right="0" bottom="0"/>
|
||||
<label id="middle" value="Middle" left="150" top="150"/>
|
||||
</stack>
|
||||
|
||||
<panel id="panel" type="arrow" onpopupshown="checkPanelPosition(this)" onpopuphidden="runNextTest.next()">
|
||||
<label id="panellabel" value="This is some text" height="80"/>
|
||||
</panel>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var expectedAnchor = null;
|
||||
var expectedSide = "", expectedAnchorEdge = "";
|
||||
var runNextTest;
|
||||
|
||||
function startTest()
|
||||
{
|
||||
runNextTest = nextTest();
|
||||
runNextTest.next();
|
||||
}
|
||||
|
||||
function nextTest()
|
||||
{
|
||||
var panel = $("panel");
|
||||
|
||||
function openPopup(position, anchor, expected, anchorEdge)
|
||||
{
|
||||
expectedAnchor = $(anchor);
|
||||
expectedSide = expected;
|
||||
expectedAnchorEdge = anchorEdge;
|
||||
|
||||
panel.openPopup(expectedAnchor, position, 0, 0, false, false, null);
|
||||
}
|
||||
|
||||
openPopup("after_start", "topleft", "top", "left");
|
||||
yield;
|
||||
openPopup("after_start", "bottomleft", "bottom", "left");
|
||||
yield;
|
||||
openPopup("before_start", "topleft", "top", "left");
|
||||
yield;
|
||||
openPopup("before_start", "bottomleft", "bottom", "left");
|
||||
yield;
|
||||
openPopup("after_start", "middle", "top", "left");
|
||||
yield;
|
||||
openPopup("before_start", "middle", "bottom", "left");
|
||||
yield;
|
||||
|
||||
openPopup("after_start", "topright", "top", "right");
|
||||
yield;
|
||||
openPopup("after_start", "bottomright", "bottom", "right");
|
||||
yield;
|
||||
openPopup("before_start", "topright", "top", "right");
|
||||
yield;
|
||||
openPopup("before_start", "bottomright", "bottom", "right");
|
||||
yield;
|
||||
|
||||
openPopup("start_before", "topleft", "left", "top");
|
||||
yield;
|
||||
openPopup("start_before", "topright", "right", "top");
|
||||
yield;
|
||||
openPopup("end_before", "topleft", "left", "top");
|
||||
yield;
|
||||
openPopup("end_before", "topright", "right", "top");
|
||||
yield;
|
||||
openPopup("start_before", "middle", "right", "top");
|
||||
yield;
|
||||
openPopup("end_before", "middle", "left", "top");
|
||||
yield;
|
||||
|
||||
openPopup("start_before", "bottomleft", "left", "bottom");
|
||||
yield;
|
||||
openPopup("start_before", "bottomright", "right", "bottom");
|
||||
yield;
|
||||
openPopup("end_before", "bottomleft", "left", "bottom");
|
||||
yield;
|
||||
openPopup("end_before", "bottomright", "right", "bottom");
|
||||
yield;
|
||||
|
||||
SimpleTest.finish();
|
||||
yield;
|
||||
}
|
||||
|
||||
function checkPanelPosition(panel)
|
||||
{
|
||||
var anchor = panel.anchorNode;
|
||||
var panelRect = panel.getBoundingClientRect();
|
||||
var anchorRect = anchor.getBoundingClientRect();
|
||||
var labelRect = $("panellabel").getBoundingClientRect();
|
||||
switch (expectedSide) {
|
||||
case "top":
|
||||
ok(labelRect.top > anchorRect.bottom + 5, "panel label is below");
|
||||
break;
|
||||
case "bottom":
|
||||
ok(labelRect.bottom < anchorRect.top - 5, "panel label is above");
|
||||
break;
|
||||
case "left":
|
||||
ok(labelRect.left > anchorRect.right + 5, "panel label is right");
|
||||
break;
|
||||
case "right":
|
||||
ok(labelRect.right < anchorRect.left - 5, "panel label is left");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (expectedAnchorEdge) {
|
||||
case "top":
|
||||
is(panelRect.top, anchorRect.top, "anchored on top");
|
||||
break;
|
||||
case "bottom":
|
||||
is(panelRect.bottom, anchorRect.bottom, "anchored on bottom");
|
||||
break;
|
||||
case "left":
|
||||
is(panelRect.left, anchorRect.left, "anchored on left");
|
||||
break;
|
||||
case "right":
|
||||
is(panelRect.right, anchorRect.right, "anchored on right");
|
||||
break;
|
||||
}
|
||||
|
||||
is(anchor, expectedAnchor, "anchor");
|
||||
|
||||
var arrow = document.getAnonymousElementByAttribute(panel, "anonid", "arrow");
|
||||
is(arrow.getAttribute("side"), expectedSide, "panel arrow side");
|
||||
is(arrow.hidden, false, "panel hidden");
|
||||
|
||||
panel.hidePopup();
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(startTest);
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"/>
|
||||
|
||||
</window>
|
|
@ -278,6 +278,112 @@
|
|||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="arrowpanel" extends="chrome://global/content/bindings/popup.xml#panel">
|
||||
<content flip="both">
|
||||
<xul:box anonid="container" class="panel-arrowcontainer">
|
||||
<xul:box anonid="arrowbox" class="panel-arrowbox">
|
||||
<xul:image anonid="arrow" class="panel-arrow"/>
|
||||
</xul:box>
|
||||
<xul:box class="panel-arrowcontent">
|
||||
<xul:box class="panel-inner-arrowcontent" xbl:inherits="align,dir,orient,pack">
|
||||
<children/>
|
||||
</xul:box>
|
||||
</xul:box>
|
||||
</xul:box>
|
||||
</content>
|
||||
<implementation>
|
||||
<field name="_fadeTimer"/>
|
||||
</implementation>
|
||||
<handlers>
|
||||
<handler event="popupshowing">
|
||||
<![CDATA[
|
||||
var container = document.getAnonymousElementByAttribute(this, "anonid", "container");
|
||||
var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox");
|
||||
var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow");
|
||||
|
||||
var anchor = this.anchorNode;
|
||||
if (!anchor) {
|
||||
arrow.hidden = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var anchorRect = anchor.getBoundingClientRect();
|
||||
var popupRect = this.getBoundingClientRect();
|
||||
|
||||
var horizPos = (Math.round(popupRect.right) <= Math.round(anchorRect.left)) ? -1 :
|
||||
(Math.round(popupRect.left) >= Math.round(anchorRect.right)) ? 1 : 0;
|
||||
var vertPos = (Math.round(popupRect.bottom) <= Math.round(anchorRect.top)) ? -1 :
|
||||
(Math.round(popupRect.top) >= Math.round(anchorRect.bottom)) ? 1 : 0;
|
||||
|
||||
var anchorClass = "";
|
||||
var hideAnchor = false;
|
||||
if (horizPos == 0) {
|
||||
container.orient = "vertical";
|
||||
arrowbox.orient = "";
|
||||
if (vertPos == 0) {
|
||||
hideAnchor = true;
|
||||
}
|
||||
else {
|
||||
arrowbox.pack = popupRect.left + popupRect.width / 2 < anchorRect.left ? "end" : "start";
|
||||
if (vertPos == 1) {
|
||||
container.dir = "";
|
||||
anchorClass = "top";
|
||||
}
|
||||
else if (vertPos == -1) {
|
||||
container.dir = "reverse";
|
||||
anchorClass = "bottom";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (vertPos == 0) {
|
||||
container.orient = "";
|
||||
arrowbox.orient = "vertical";
|
||||
if (horizPos == 0) {
|
||||
hideAnchor = true;
|
||||
}
|
||||
else {
|
||||
arrowbox.pack = popupRect.top + popupRect.height / 2 < anchorRect.top ? "end" : "start";
|
||||
if (horizPos == 1) {
|
||||
container.dir = "";
|
||||
anchorClass = "left";
|
||||
}
|
||||
else if (horizPos == -1) {
|
||||
container.dir = "reverse";
|
||||
anchorClass = "right";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
hideAnchor = true;
|
||||
}
|
||||
arrow.hidden = hideAnchor;
|
||||
arrow.setAttribute("side", anchorClass);
|
||||
|
||||
// set fading
|
||||
var fade = this.getAttribute("fade");
|
||||
var fadeDelay = (fade == "fast") ? 1 : fade == "slow" ? 4000 : 0;
|
||||
if (fadeDelay) {
|
||||
this._fadeTimer = setTimeout(function (self) {
|
||||
self.style.opacity = 0.2;
|
||||
}, fadeDelay, this);
|
||||
}
|
||||
]]>
|
||||
</handler>
|
||||
<handler event="popuphiding">
|
||||
clearTimeout(this._fadeTimer);
|
||||
this.style.removeProperty("opacity");
|
||||
</handler>
|
||||
<handler event="transitionend">
|
||||
<![CDATA[
|
||||
if (event.propertyName == "opacity") {
|
||||
this.hidePopup();
|
||||
this.style.removeProperty("opacity");
|
||||
}
|
||||
]]>
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="tooltip" extends="chrome://global/content/bindings/popup.xml#popup-base">
|
||||
<content>
|
||||
<children>
|
||||
|
|
|
@ -419,6 +419,10 @@ tooltip {
|
|||
margin-top: 21px;
|
||||
}
|
||||
|
||||
panel[type="arrow"] {
|
||||
-moz-binding: url("chrome://global/content/bindings/popup.xml#arrowpanel");
|
||||
}
|
||||
|
||||
%ifdef XP_MACOSX
|
||||
.statusbar-resizerpanel {
|
||||
display: none;
|
||||
|
|
|
@ -47,6 +47,15 @@ panel {
|
|||
color: MenuText;
|
||||
}
|
||||
|
||||
panel[type="arrow"] {
|
||||
-moz-transition: opacity 300ms;
|
||||
}
|
||||
|
||||
.panel-arrowbox {
|
||||
/* the arrows don't display properly on Linux so disable for now */
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ::::: tooltip ::::: */
|
||||
|
||||
tooltip {
|
||||
|
|
После Ширина: | Высота: | Размер: 910 B |
После Ширина: | Высота: | Размер: 826 B |
После Ширина: | Высота: | Размер: 815 B |
|
@ -70,6 +70,9 @@ toolkit.jar:
|
|||
skin/classic/global/arrow/arrow-up-dis.gif (arrow/arrow-up-dis.gif)
|
||||
skin/classic/global/arrow/arrow-up-sharp.gif (arrow/arrow-up-sharp.gif)
|
||||
skin/classic/global/arrow/arrow-up.gif (arrow/arrow-up.gif)
|
||||
skin/classic/global/arrow/panelarrow-up.png (arrow/panelarrow-up.png)
|
||||
skin/classic/global/arrow/panelarrow-down.png (arrow/panelarrow-down.png)
|
||||
skin/classic/global/arrow/panelarrow-horiz.png (arrow/panelarrow-horiz.png)
|
||||
skin/classic/global/checkbox/cbox-check.gif (checkbox/cbox-check.gif)
|
||||
skin/classic/global/checkbox/cbox-check-dis.gif (checkbox/cbox-check-dis.gif)
|
||||
skin/classic/global/console/console-error-caret.gif (console/console-error-caret.gif)
|
||||
|
|
|
@ -57,6 +57,57 @@ panel[titlebar] {
|
|||
-moz-appearance: none; /* to disable rounded corners */
|
||||
}
|
||||
|
||||
panel[type="arrow"] {
|
||||
-moz-appearance: none;
|
||||
background: transparent;
|
||||
-moz-transition: opacity 300ms;
|
||||
}
|
||||
|
||||
.panel-arrowcontent {
|
||||
-moz-appearance: none;
|
||||
color: white;
|
||||
background: -moz-linear-gradient(rgba(85,85,85,1), rgba(75,75,75,.97) 5px, rgba(58,58,58,.97) 17px, rgba(43,43,43,.97) 40px, rgba(40,40,40,.97) 80px, rgba(40,40,40,.97));
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 0 0 1px rgba(255,255,255,.15) inset,
|
||||
0 1px 0 rgba(255,255,255,.05) inset,
|
||||
0 0 0 1px rgba(0,0,0,.25);
|
||||
padding: 6px;
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
.panel-arrow {
|
||||
opacity: 0.97;
|
||||
}
|
||||
|
||||
.panel-arrow[side="top"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-up.png");
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
.panel-arrow[side="bottom"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-down.png");
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.panel-arrow[side="left"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-horiz.png");
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
margin-right: -2px;
|
||||
}
|
||||
|
||||
.panel-arrow[side="right"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-horiz.png");
|
||||
-moz-transform: scaleX(-1);
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
margin-left: -2px;
|
||||
}
|
||||
|
||||
/* ::::: tooltip ::::: */
|
||||
|
||||
tooltip {
|
||||
|
|
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 1.3 KiB |
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 1.3 KiB |
После Ширина: | Высота: | Размер: 917 B |
После Ширина: | Высота: | Размер: 1.2 KiB |
|
@ -76,6 +76,9 @@ toolkit.jar:
|
|||
skin/classic/global/arrow/arrow-up-dis.gif (arrow/arrow-up-dis.gif)
|
||||
skin/classic/global/arrow/arrow-up-hov.gif (arrow/arrow-up-hov.gif)
|
||||
skin/classic/global/arrow/arrow-up-sharp.gif (arrow/arrow-up-sharp.gif)
|
||||
skin/classic/global/arrow/panelarrow-up.png (arrow/panelarrow-up.png)
|
||||
skin/classic/global/arrow/panelarrow-down.png (arrow/panelarrow-down.png)
|
||||
skin/classic/global/arrow/panelarrow-horiz.png (arrow/panelarrow-horiz.png)
|
||||
skin/classic/global/checkbox/cbox-check.gif (checkbox/cbox-check.gif)
|
||||
skin/classic/global/checkbox/cbox-check-dis.gif (checkbox/cbox-check-dis.gif)
|
||||
skin/classic/global/console/console.css (console/console.css)
|
||||
|
@ -204,7 +207,7 @@ toolkit.jar:
|
|||
skin/classic/aero/global/numberbox.css
|
||||
skin/classic/aero/global/notification.css
|
||||
skin/classic/aero/global/passwordmgr.css
|
||||
skin/classic/aero/global/popup.css
|
||||
skin/classic/aero/global/popup.css (popup-aero.css)
|
||||
skin/classic/aero/global/preferences.css
|
||||
skin/classic/aero/global/printPageSetup.css
|
||||
skin/classic/aero/global/printPreview.css
|
||||
|
@ -245,6 +248,9 @@ toolkit.jar:
|
|||
skin/classic/aero/global/arrow/arrow-up-dis.gif (arrow/arrow-up-dis.gif)
|
||||
skin/classic/aero/global/arrow/arrow-up-hov.gif (arrow/arrow-up-hov.gif)
|
||||
skin/classic/aero/global/arrow/arrow-up-sharp.gif (arrow/arrow-up-sharp.gif)
|
||||
skin/classic/aero/global/arrow/panelarrow-up.png (arrow/panelarrow-up-aero.png)
|
||||
skin/classic/aero/global/arrow/panelarrow-down.png (arrow/panelarrow-down-aero.png)
|
||||
skin/classic/aero/global/arrow/panelarrow-horiz.png (arrow/panelarrow-horiz-aero.png)
|
||||
skin/classic/aero/global/checkbox/cbox-check.gif (checkbox/cbox-check.gif)
|
||||
skin/classic/aero/global/checkbox/cbox-check-dis.gif (checkbox/cbox-check-dis.gif)
|
||||
* skin/classic/aero/global/console/console.css (console/console-aero.css)
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998-2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Hewitt (hewitt@netscape.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
|
||||
/* ::::: menupopup ::::: */
|
||||
|
||||
menupopup,
|
||||
panel {
|
||||
border: 3px solid transparent;
|
||||
-moz-border-top-colors : ThreeDLightShadow ThreeDHighlight ThreeDFace;
|
||||
-moz-border-left-colors : ThreeDLightShadow ThreeDHighlight ThreeDFace;
|
||||
-moz-border-right-colors : ThreeDDarkShadow ThreeDShadow ThreeDFace;
|
||||
-moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow ThreeDFace;
|
||||
padding: 0px;
|
||||
min-width: 1px;
|
||||
background: Menu;
|
||||
}
|
||||
|
||||
menupopup {
|
||||
-moz-appearance: menupopup;
|
||||
}
|
||||
|
||||
menupopup > menu > menupopup {
|
||||
/* align submenus */
|
||||
-moz-margin-start: -3px;
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
panel[type="arrow"] {
|
||||
-moz-appearance: none;
|
||||
background: transparent;
|
||||
border: none;
|
||||
-moz-transition: opacity 300ms;
|
||||
}
|
||||
|
||||
.panel-arrowcontent {
|
||||
border-radius: 6px;
|
||||
background-color: rgba(179,230,255,.35);
|
||||
background-image: -moz-linear-gradient(rgba(250,253,255,.9), rgba(250,253,255,.75) 20px, rgba(250,253,255,.70) 39px, rgba(250,253,255,0) 41px, rgba(250,253,255,0));
|
||||
margin: 5px;
|
||||
box-shadow: 0 0 0 1px rgba(255,255,255,.65) inset,
|
||||
0 1px 0 rgba(255,255,255,.3) inset,
|
||||
0 0 0 1px rgba(0,0,0,.75),
|
||||
0 1px 3px 2px rgba(0,0,0,.65);
|
||||
}
|
||||
|
||||
.panel-inner-arrowcontent {
|
||||
background-color: rgba(250,250,250,.95);
|
||||
background-clip: padding-box;
|
||||
margin: 4px;
|
||||
border: 2px solid;
|
||||
-moz-border-radius: 2px;
|
||||
-moz-border-top-colors: rgba(255,255,255,.6) rgba(0,0,0,.7);
|
||||
-moz-border-left-colors: rgba(255,255,255,.6) rgba(0,0,0,.7);
|
||||
-moz-border-bottom-colors: rgba(255,255,255,.6) rgba(0,0,0,.7);
|
||||
-moz-border-right-colors: rgba(255,255,255,.6) rgba(0,0,0,.7);
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.panel-arrow[side="top"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-up.png");
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
.panel-arrow[side="bottom"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-down.png");
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.panel-arrow[side="left"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-horiz.png");
|
||||
margin-right: -5px;
|
||||
}
|
||||
|
||||
.panel-arrow[side="right"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-horiz.png");
|
||||
-moz-transform: scaleX(-1);
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
/* ::::: tooltip ::::: */
|
||||
|
||||
tooltip {
|
||||
-moz-appearance: tooltip;
|
||||
margin-top: 21px;
|
||||
border: 1px solid InfoText;
|
||||
padding: 2px 3px;
|
||||
max-width: 40em;
|
||||
background-color: InfoBackground;
|
||||
color: InfoText;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
tooltip[titletip="true"] {
|
||||
/* See bug 32157 comment 128
|
||||
* margin: -2px 0px 0px -3px;
|
||||
*/
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
/* rules for popups associated with menulists */
|
||||
|
||||
menulist > menupopup,
|
||||
.menulist-menupopup {
|
||||
-moz-appearance: none;
|
||||
border-width: 1px;
|
||||
-moz-border-top-colors: -moz-FieldText;
|
||||
-moz-border-right-colors: -moz-FieldText;
|
||||
-moz-border-bottom-colors: -moz-FieldText;
|
||||
-moz-border-left-colors: -moz-FieldText;
|
||||
padding: 0px;
|
||||
min-width: 0px;
|
||||
background-color: -moz-Field;
|
||||
}
|
|
@ -62,6 +62,52 @@ menupopup > menu > menupopup {
|
|||
margin-top: -3px;
|
||||
}
|
||||
|
||||
panel[type="arrow"] {
|
||||
-moz-appearance: none;
|
||||
background: transparent;
|
||||
border: none;
|
||||
-moz-transition: opacity 300ms;
|
||||
}
|
||||
|
||||
.panel-arrowcontent {
|
||||
border-radius: 6px;
|
||||
background: -moz-linear-gradient(rgba(248,250,253,1), rgba(248,250,253,1) 20px, rgba(248,250,253,.97));
|
||||
padding: 6px;
|
||||
margin: 3px;
|
||||
box-shadow: 0 0 5px 1px rgba(184,205,232,1) inset,
|
||||
0 0 0 1px rgba(0,0,0,.25),
|
||||
0 1px 5px rgba(0,0,0,.5);
|
||||
}
|
||||
|
||||
.panel-arrow[side="top"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-up.png");
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
margin-bottom: -13px;
|
||||
}
|
||||
|
||||
.panel-arrow[side="bottom"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-down.png");
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
margin-top: -12px;
|
||||
}
|
||||
|
||||
.panel-arrow[side="left"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-horiz.png");
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
margin-right: -12px;
|
||||
}
|
||||
|
||||
.panel-arrow[side="right"] {
|
||||
list-style-image: url("chrome://global/skin/arrow/panelarrow-horiz.png");
|
||||
-moz-transform: scaleX(-1);
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
margin-left: -12px;
|
||||
}
|
||||
|
||||
/* ::::: tooltip ::::: */
|
||||
|
||||
tooltip {
|
||||
|
|