blob: dc2d2246812bf6a2abbcd94f22008e8b83c73736 [file] [log] [blame]
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide('goog.ui.PopupMenuTest');
goog.setTestOnly('goog.ui.PopupMenuTest');
goog.require('goog.dom');
goog.require('goog.events.EventHandler');
goog.require('goog.events.EventType');
goog.require('goog.math.Box');
goog.require('goog.math.Coordinate');
goog.require('goog.positioning.Corner');
goog.require('goog.style');
goog.require('goog.testing.jsunit');
goog.require('goog.ui.Menu');
goog.require('goog.ui.MenuItem');
goog.require('goog.ui.PopupMenu');
var anchor;
// Event handler
var handler;
var showPopup;
var beforeShowPopupCalled;
var popup;
function setUp() {
anchor = goog.dom.getElement('popup-anchor');
handler = new goog.events.EventHandler();
popup = new goog.ui.PopupMenu();
popup.render();
}
function tearDown() {
handler.dispose();
popup.dispose();
}
/**
* Asserts properties of {@code target} matches the expected value.
*
* @param {Object} target The target specifying how the popup menu should be
* attached to an anchor.
* @param {Element} expectedElement The expected anchoring element.
* @param {goog.positioning.Corner} expectedTargetCorner The expected value of
* the {@code target.targetCorner_} property.
* @param {goog.positioning.Corner} expectedMenuCorner The expected value of
* the {@code target.menuCorner_} property.
* @param {goog.events.EventType} expectedEventType The expected value of the
* {@code target.eventType_} property.
* @param {goog.math.Box} expectedMargin The expected value of the
* {@code target.margin_} property.
*/
function assertTarget(target, expectedElement, expectedTargetCorner,
expectedMenuCorner, expectedEventType, expectedMargin) {
var expectedTarget = {
element_: expectedElement,
targetCorner_: expectedTargetCorner,
menuCorner_: expectedMenuCorner,
eventType_: expectedEventType,
margin_: expectedMargin
};
assertObjectEquals('Target does not match.', expectedTarget, target);
}
/**
* Test menu receives BEFORE_SHOW event before it's displayed.
*/
function testBeforeShowEvent() {
var target = popup.createAttachTarget(anchor);
popup.attach(anchor);
function beforeShowPopup(e) {
// Ensure that the element is not yet visible.
assertFalse('The element should not be shown when BEFORE_SHOW event is ' +
'being handled',
goog.style.isElementShown(popup.getElement()));
// Verify that current anchor is set before dispatching BEFORE_SHOW.
assertNotNullNorUndefined(popup.getAttachedElement());
assertEquals('The attached anchor element is incorrect',
target.element_, popup.getAttachedElement());
beforeShowPopupCalled = true;
return showPopup;
};
function onShowPopup(e) {
assertEquals('The attached anchor element is incorrect',
target.element_, popup.getAttachedElement());
};
handler.listen(popup,
goog.ui.Menu.EventType.BEFORE_SHOW,
beforeShowPopup);
handler.listen(popup,
goog.ui.Menu.EventType.SHOW,
onShowPopup);
beforeShowPopupCalled = false;
showPopup = false;
popup.showMenu(target, 0, 0);
assertTrue('BEFORE_SHOW event handler should be called on #showMenu',
beforeShowPopupCalled);
assertFalse('The element should not be shown when BEFORE_SHOW handler ' +
'returned false',
goog.style.isElementShown(popup.getElement()));
beforeShowPopupCalled = false;
showPopup = true;
popup.showMenu(target, 0, 0);
assertTrue('The element should be shown when BEFORE_SHOW handler ' +
'returned true',
goog.style.isElementShown(popup.getElement()));
}
/**
* Test the behavior of {@link PopupMenu.isAttachTarget}.
*/
function testIsAttachTarget() {
// Before 'attach' is called.
assertFalse('Menu should not be attached to the element',
popup.isAttachTarget(anchor));
popup.attach(anchor);
assertTrue('Menu should be attached to the anchor',
popup.isAttachTarget(anchor));
popup.detach(anchor);
assertFalse('Menu is expected to be detached from the element',
popup.isAttachTarget(anchor));
}
/**
* Tests the behavior of {@link PopupMenu.createAttachTarget}.
*/
function testCreateAttachTarget() {
// Randomly picking parameters.
var targetCorner = goog.positioning.Corner.TOP_END;
var menuCorner = goog.positioning.Corner.BOTTOM_LEFT;
var contextMenu = false; // Show menu on mouse down event.
var margin = new goog.math.Box(0, 10, 5, 25);
// Simply setting the required parameters.
var target = popup.createAttachTarget(anchor);
assertTrue(popup.isAttachTarget(anchor));
assertTarget(target, anchor, undefined, undefined,
goog.events.EventType.MOUSEDOWN, undefined);
// Creating another target with all the parameters.
target = popup.createAttachTarget(anchor, targetCorner, menuCorner,
contextMenu, margin);
assertTrue(popup.isAttachTarget(anchor));
assertTarget(target, anchor, targetCorner, menuCorner,
goog.events.EventType.MOUSEDOWN, margin);
// Finally, switch up the 'contextMenu'
target = popup.createAttachTarget(anchor, undefined, undefined,
true /*opt_contextMenu*/, undefined);
assertTarget(target, anchor, undefined, undefined,
goog.events.EventType.CONTEXTMENU, undefined);
}
/**
* Tests the behavior of {@link PopupMenu.getAttachTarget}.
*/
function testGetAttachTarget() {
// Before the menu is attached to the anchor.
var target = popup.getAttachTarget(anchor);
assertTrue('Not expecting a target before the element is attach to the menu',
target == null);
// Randomly picking parameters.
var targetCorner = goog.positioning.Corner.TOP_END;
var menuCorner = goog.positioning.Corner.BOTTOM_LEFT;
var contextMenu = false; // Show menu on mouse down event.
var margin = new goog.math.Box(0, 10, 5, 25);
popup.attach(anchor, targetCorner, menuCorner, contextMenu, margin);
target = popup.getAttachTarget(anchor);
assertTrue('Failed to get target after attaching element to menu',
target != null);
// Make sure we got the right target back.
assertTarget(target, anchor, targetCorner, menuCorner,
goog.events.EventType.MOUSEDOWN, margin);
}
function testSmallViewportSliding() {
popup.getElement().style.position = 'absolute';
popup.getElement().style.outline = '1px solid blue';
var item = new goog.ui.MenuItem('Test Item');
popup.addChild(item, true);
item.getElement().style.overflow = 'hidden';
var viewport = goog.style.getClientViewportElement();
var viewportRect = goog.style.getVisibleRectForElement(viewport);
var middlePos = Math.floor((viewportRect.right - viewportRect.left) / 2);
var leftwardPos = Math.floor((viewportRect.right - viewportRect.left) / 3);
var rightwardPos =
Math.floor((viewportRect.right - viewportRect.left) / 3 * 2);
// Can interpret these positions as widths relative to the viewport as well.
var smallWidth = leftwardPos;
var mediumWidth = middlePos;
var largeWidth = rightwardPos;
// Test small menu first. This should be small enough that it will display
// its upper left corner where we tell it to in all three positions.
popup.getElement().style.width = smallWidth + 'px';
var target = popup.createAttachTarget(anchor);
popup.attach(anchor);
popup.showMenu(target, leftwardPos, 0);
assertObjectEquals(
'Popup in wrong position: small size, leftward pos',
new goog.math.Coordinate(leftwardPos, 0),
goog.style.getPosition(popup.getElement()));
popup.showMenu(target, middlePos, 0);
assertObjectEquals(
'Popup in wrong position: small size, middle pos',
new goog.math.Coordinate(middlePos, 0),
goog.style.getPosition(popup.getElement()));
popup.showMenu(target, rightwardPos, 0);
assertObjectEquals(
'Popup in wrong position: small size, rightward pos',
new goog.math.Coordinate(rightwardPos, 0),
goog.style.getPosition(popup.getElement()));
// Test medium menu next. This should display with its upper left corner
// at the target when leftward and middle, but on the right it should
// position its upper right corner at the target instead.
popup.getElement().style.width = mediumWidth + 'px';
popup.showMenu(target, leftwardPos, 0);
assertObjectEquals(
'Popup in wrong position: medium size, leftward pos',
new goog.math.Coordinate(leftwardPos, 0),
goog.style.getPosition(popup.getElement()));
popup.showMenu(target, middlePos, 0);
assertObjectEquals(
'Popup in wrong position: medium size, middle pos',
new goog.math.Coordinate(middlePos, 0),
goog.style.getPosition(popup.getElement()));
popup.showMenu(target, rightwardPos, 0);
assertObjectEquals(
'Popup in wrong position: medium size, rightward pos',
new goog.math.Coordinate(rightwardPos - mediumWidth, 0),
goog.style.getPosition(popup.getElement()));
// Test large menu next. This should display with its upper left corner at
// the target when leftward, and its upper right corner at the target when
// rightward, but right in the middle neither corner can be at the target and
// keep the entire menu onscreen, so it should place its upper right corner
// at the very right edge of the viewport.
popup.getElement().style.width = largeWidth + 'px';
popup.showMenu(target, leftwardPos, 0);
assertObjectEquals(
'Popup in wrong position: large size, leftward pos',
new goog.math.Coordinate(leftwardPos, 0),
goog.style.getPosition(popup.getElement()));
popup.showMenu(target, middlePos, 0);
assertObjectEquals(
'Popup in wrong position: large size, middle pos',
new goog.math.Coordinate(
viewportRect.right - viewportRect.left - largeWidth, 0),
goog.style.getPosition(popup.getElement()));
popup.showMenu(target, rightwardPos, 0);
assertObjectEquals(
'Popup in wrong position: large size, rightward pos',
new goog.math.Coordinate(rightwardPos - largeWidth, 0),
goog.style.getPosition(popup.getElement()));
// Make sure that the menu still displays correctly if we give the target
// a target corner. We can't set the overflow policy in that case, but it
// should still display.
popup.detach(anchor);
anchor.style.position = 'absolute';
anchor.style.left = '24px';
anchor.style.top = '24px';
var targetCorner = goog.positioning.Corner.TOP_END;
target = popup.createAttachTarget(anchor, targetCorner);
popup.attach(anchor, targetCorner);
popup.getElement().style.width = smallWidth + 'px';
popup.showMenu(target, leftwardPos, 0);
assertObjectEquals(
'Popup in wrong position: small size, leftward pos, with target corner',
new goog.math.Coordinate(24, 24),
goog.style.getPosition(popup.getElement()));
}