// 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())); }