зеркало из https://github.com/mozilla/gecko-dev.git
Bug 250091, support page up and page down in menulists, r=neil
This commit is contained in:
Родитель
8d27a0b354
Коммит
4818484538
|
@ -1635,6 +1635,87 @@ void nsMenuPopupFrame::EnsureMenuItemIsVisible(nsMenuFrame* aMenuItem)
|
|||
}
|
||||
}
|
||||
|
||||
void nsMenuPopupFrame::ChangeByPage(bool aIsUp)
|
||||
{
|
||||
nsIFrame* parentMenu = GetParent();
|
||||
if (parentMenu) {
|
||||
// Only scroll by page within menulists.
|
||||
nsCOMPtr<nsIDOMXULMenuListElement> menulist = do_QueryInterface(parentMenu->GetContent());
|
||||
if (!menulist) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsMenuFrame* newMenu = nullptr;
|
||||
nsIFrame* currentMenu = mCurrentMenu;
|
||||
if (!currentMenu) {
|
||||
// If there is no current menu item, get the first item. When moving up,
|
||||
// just use this as the newMenu and leave currentMenu null so that no
|
||||
// check for a later element is performed. When moving down, set currentMenu
|
||||
// so that we look for one page down from the first item.
|
||||
newMenu = nsXULPopupManager::GetNextMenuItem(this, nullptr, true);
|
||||
if (!aIsUp) {
|
||||
currentMenu = newMenu;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMenu) {
|
||||
nscoord scrollHeight = mRect.height;
|
||||
nsIScrollableFrame *scrollframe = GetScrollFrame(this);
|
||||
if (scrollframe) {
|
||||
scrollHeight = scrollframe->GetScrollPortRect().height;
|
||||
}
|
||||
|
||||
// Get the position of the current item and add or subtract one popup's
|
||||
// height to or from it.
|
||||
nscoord targetPosition = aIsUp ? currentMenu->GetRect().YMost() - scrollHeight :
|
||||
currentMenu->GetRect().y + scrollHeight;
|
||||
|
||||
// Indicates that the last visible child was a valid menuitem.
|
||||
bool lastWasValid = false;
|
||||
|
||||
// Look for the next child which is just past the target position. This child
|
||||
// will need to be selected.
|
||||
while (currentMenu) {
|
||||
// Only consider menu frames.
|
||||
nsMenuFrame* menuFrame = do_QueryFrame(currentMenu);
|
||||
if (menuFrame &&
|
||||
nsXULPopupManager::IsValidMenuItem(PresContext(), menuFrame->GetContent(), true)) {
|
||||
|
||||
// If the right position was found, break out. Otherwise, look for another item.
|
||||
if ((!aIsUp && currentMenu->GetRect().YMost() > targetPosition) ||
|
||||
(aIsUp && currentMenu->GetRect().y < targetPosition)) {
|
||||
|
||||
// If the last visible child was not a valid menuitem or was disabled,
|
||||
// use this as the menu to select, skipping over any non-valid items at
|
||||
// the edge of the page.
|
||||
if (!lastWasValid) {
|
||||
newMenu = menuFrame;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Assign this item to newMenu. This item will be selected in case we
|
||||
// don't find any more.
|
||||
lastWasValid = true;
|
||||
newMenu = menuFrame;
|
||||
}
|
||||
else {
|
||||
lastWasValid = false;
|
||||
}
|
||||
|
||||
currentMenu = aIsUp ? currentMenu->GetPrevSibling() :
|
||||
currentMenu->GetNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
// Select the new menuitem.
|
||||
if (newMenu) {
|
||||
ChangeMenuItem(newMenu, false);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMenuPopupFrame::SetCurrentMenuItem(nsMenuFrame* aMenuItem)
|
||||
{
|
||||
if (mCurrentMenu == aMenuItem)
|
||||
|
|
|
@ -326,6 +326,8 @@ public:
|
|||
|
||||
void EnsureMenuItemIsVisible(nsMenuFrame* aMenuFrame);
|
||||
|
||||
void ChangeByPage(bool aIsUp);
|
||||
|
||||
// Move the popup to the screen coordinate (aLeft, aTop) in CSS pixels.
|
||||
// If aUpdateAttrs is true, and the popup already has left or top attributes,
|
||||
// then those attributes are updated to the new location.
|
||||
|
|
|
@ -2172,6 +2172,13 @@ nsXULPopupManager::HandleKeyboardEventWithKeyCode(
|
|||
HandleKeyboardNavigation(keyCode);
|
||||
break;
|
||||
|
||||
case nsIDOMKeyEvent::DOM_VK_PAGE_DOWN:
|
||||
case nsIDOMKeyEvent::DOM_VK_PAGE_UP:
|
||||
if (aTopVisibleMenuItem) {
|
||||
aTopVisibleMenuItem->Frame()->ChangeByPage(keyCode == nsIDOMKeyEvent::DOM_VK_PAGE_UP);
|
||||
}
|
||||
break;
|
||||
|
||||
case nsIDOMKeyEvent::DOM_VK_ESCAPE:
|
||||
// Pressing Escape hides one level of menus only. If no menu is open,
|
||||
// check if a menubar is active and inform it that a menu closed. Even
|
||||
|
|
|
@ -116,6 +116,7 @@ skip-if = buildapp == 'mulet'
|
|||
skip-if = buildapp == 'mulet'
|
||||
[test_menulist_keynav.xul]
|
||||
[test_menulist_null_value.xul]
|
||||
[test_menulist_paging.xul]
|
||||
[test_mousecapture.xul]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_mousescroll.xul]
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window title="Menulist Tests"
|
||||
onload="setTimeout(startTest, 0);"
|
||||
onpopupshown="menulistShown()" onpopuphidden="runTest()"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<menulist id="menulist1">
|
||||
<menupopup id="menulist-popup1">
|
||||
<menuitem label="One"/>
|
||||
<menuitem label="Two"/>
|
||||
<menuitem label="Three"/>
|
||||
<menuitem label="Four"/>
|
||||
<menuitem label="Five"/>
|
||||
<menuitem label="Six"/>
|
||||
<menuitem label="Seven"/>
|
||||
<menuitem label="Eight"/>
|
||||
<menuitem label="Nine"/>
|
||||
<menuitem label="Ten"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
|
||||
<menulist id="menulist2">
|
||||
<menupopup id="menulist-popup2">
|
||||
<menuitem label="One" disabled="true"/>
|
||||
<menuitem label="Two" selected="true"/>
|
||||
<menuitem label="Three"/>
|
||||
<menuitem label="Four"/>
|
||||
<menuitem label="Five"/>
|
||||
<menuitem label="Six"/>
|
||||
<menuitem label="Seven"/>
|
||||
<menuitem label="Eight"/>
|
||||
<menuitem label="Nine"/>
|
||||
<menuitem label="Ten" disabled="true"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
|
||||
<menulist id="menulist3">
|
||||
<menupopup id="menulist-popup3">
|
||||
<label value="One"/>
|
||||
<menuitem label="Two" selected="true"/>
|
||||
<menuitem label="Three"/>
|
||||
<menuitem label="Four"/>
|
||||
<menuitem label="Five" disabled="true"/>
|
||||
<menuitem label="Six" disabled="true"/>
|
||||
<menuitem label="Seven"/>
|
||||
<menuitem label="Eight"/>
|
||||
<menuitem label="Nine"/>
|
||||
<label value="Ten"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let test;
|
||||
|
||||
// Windows allows disabled items to be selected.
|
||||
let isWindows = navigator.platform.indexOf("Win") >= 0;
|
||||
|
||||
let tests = [
|
||||
{ list: "menulist1", initial: 0, downs: [3, 6, 9, 9],
|
||||
ups: [6, 3, 0, 0] },
|
||||
{ list: "menulist2", initial: 1, downs: [4, 7, isWindows ? 9 : 8, isWindows ? 9 : 8],
|
||||
ups: [isWindows ? 6 : 5, isWindows ? 3 : 2, isWindows ? 0 : 1] },
|
||||
{ list: "menulist3", initial: 1, downs: [isWindows ? 4 : 6, isWindows ? 7 : 8, 8],
|
||||
ups: [isWindows ? 5 : 3, isWindows ? 2 : 1, 1] }
|
||||
];
|
||||
|
||||
function startTest()
|
||||
{
|
||||
let popup = document.getElementById("menulist-popup1");
|
||||
let menupopupHeight = popup.getBoundingClientRect().height;
|
||||
let menuitemHeight = popup.firstChild.getBoundingClientRect().height;
|
||||
|
||||
// First, set the height of each popup to the height of four menuitems plus
|
||||
// any padding and border on the menupopup.
|
||||
let height = menuitemHeight * 4 + (menupopupHeight - menuitemHeight * 10);
|
||||
popup.height = height;
|
||||
document.getElementById("menulist-popup2").height = height;
|
||||
document.getElementById("menulist-popup3").height = height;
|
||||
|
||||
runTest();
|
||||
}
|
||||
|
||||
function runTest()
|
||||
{
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
test = tests.shift();
|
||||
document.getElementById(test.list).open = true;
|
||||
}
|
||||
|
||||
function menulistShown()
|
||||
{
|
||||
let menulist = document.getElementById(test.list);
|
||||
is(menulist.menuBoxObject.activeChild.label, menulist.getItemAtIndex(test.initial).label, test.list + " initial selection");
|
||||
|
||||
for (let i = 0; i < test.downs.length; i++) {
|
||||
sendKey("PAGE_DOWN");
|
||||
is(menulist.menuBoxObject.activeChild.label, menulist.getItemAtIndex(test.downs[i]).label, test.list + " page down " + i);
|
||||
}
|
||||
|
||||
for (let i = 0; i < test.ups.length; i++) {
|
||||
sendKey("PAGE_UP");
|
||||
is(menulist.menuBoxObject.activeChild.label, menulist.getItemAtIndex(test.ups[i]).label, test.list + " page up " + i);
|
||||
}
|
||||
|
||||
menulist.open = false;
|
||||
}
|
||||
]]>
|
||||
</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>
|
Загрузка…
Ссылка в новой задаче