| // 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.editor.BubbleTest'); |
| goog.setTestOnly('goog.ui.editor.BubbleTest'); |
| |
| goog.require('goog.dom'); |
| goog.require('goog.dom.TagName'); |
| goog.require('goog.events'); |
| goog.require('goog.events.EventType'); |
| goog.require('goog.positioning.Corner'); |
| goog.require('goog.positioning.OverflowStatus'); |
| goog.require('goog.string'); |
| goog.require('goog.style'); |
| goog.require('goog.testing.editor.TestHelper'); |
| goog.require('goog.testing.events'); |
| goog.require('goog.testing.jsunit'); |
| goog.require('goog.ui.Component'); |
| goog.require('goog.ui.editor.Bubble'); |
| |
| var testHelper; |
| var fieldDiv; |
| var bubble; |
| var link; |
| var link2; |
| var panelId; |
| |
| function setUpPage() { |
| fieldDiv = goog.dom.getElement('field'); |
| var viewportSize = goog.dom.getViewportSize(); |
| // Some tests depends on enough size of viewport. |
| if (viewportSize.width < 600 || viewportSize.height < 440) { |
| window.moveTo(0, 0); |
| window.resizeTo(640, 480); |
| } |
| } |
| |
| function setUp() { |
| testHelper = new goog.testing.editor.TestHelper(fieldDiv); |
| testHelper.setUpEditableElement(); |
| |
| bubble = new goog.ui.editor.Bubble(document.body, 999); |
| |
| fieldDiv.innerHTML = '<a href="http://www.google.com">Google</a>' + |
| '<a href="http://www.google.com">Google2</a>'; |
| link = fieldDiv.firstChild; |
| link2 = fieldDiv.lastChild; |
| |
| window.scrollTo(0, 0); |
| goog.style.setStyle(document.body, 'direction', 'ltr'); |
| goog.style.setStyle(document.getElementById('field'), 'position', 'static'); |
| } |
| |
| function tearDown() { |
| if (panelId) { |
| bubble.removePanel(panelId); |
| } |
| testHelper.tearDownEditableElement(); |
| } |
| |
| |
| /** |
| * This is a helper function for setting up the target element with a |
| * given direction. |
| * |
| * @param {string} dir The direction of the target element, 'ltr' or 'rtl'. |
| * @param {boolean=} opt_preferTopPosition Whether to prefer placing the bubble |
| * above the element instead of below it. Defaults to preferring below. |
| */ |
| function prepareTargetWithGivenDirection(dir, opt_preferTopPosition) { |
| goog.style.setStyle(document.body, 'direction', dir); |
| |
| fieldDiv.style.direction = dir; |
| fieldDiv.innerHTML = '<a href="http://www.google.com">Google</a>'; |
| link = fieldDiv.firstChild; |
| |
| panelId = bubble.addPanel('A', 'Link', link, function(el) { |
| el.innerHTML = '<div style="border:1px solid blue;">B</div>'; |
| }, opt_preferTopPosition); |
| } |
| |
| |
| /** |
| * This is a helper function for getting the expected position of the bubble. |
| * (align to the right or the left of the target element). Align left by |
| * default and align right if opt_alignRight is true. The expected Y is |
| * unaffected by alignment. |
| * |
| * @param {boolean=} opt_alignRight Sets the expected alignment to be right. |
| */ |
| function getExpectedBubblePositionWithGivenAlignment(opt_alignRight) { |
| var targetPosition = goog.style.getFramedPageOffset(link, window); |
| var targetWidth = link.offsetWidth; |
| var bubbleSize = goog.style.getSize(bubble.bubbleContainer_); |
| var expectedBubbleX = opt_alignRight ? |
| targetPosition.x + targetWidth - bubbleSize.width : targetPosition.x; |
| var expectedBubbleY = link.offsetHeight + targetPosition.y + |
| goog.ui.editor.Bubble.VERTICAL_CLEARANCE_; |
| |
| return { |
| x: expectedBubbleX, |
| y: expectedBubbleY |
| }; |
| } |
| |
| function testCreateBubbleWithLinkPanel() { |
| var id = goog.string.createUniqueString(); |
| panelId = bubble.addPanel('A', 'Link', link, function(container) { |
| container.innerHTML = '<span id="' + id + '">Test</span>'; |
| }); |
| assertNotNull('Bubble should be created', bubble.bubbleContents_); |
| assertNotNull('Added element should be present', goog.dom.getElement(id)); |
| assertTrue('Bubble should be visible', bubble.isVisible()); |
| } |
| |
| function testCloseBubble() { |
| testCreateBubbleWithLinkPanel(); |
| |
| var count = 0; |
| goog.events.listen(bubble, goog.ui.Component.EventType.HIDE, function() { |
| count++; |
| }); |
| |
| bubble.removePanel(panelId); |
| panelId = null; |
| |
| assertFalse('Bubble should not be visible', bubble.isVisible()); |
| assertEquals('Hide event should be dispatched', 1, count); |
| } |
| |
| function testCloseBox() { |
| testCreateBubbleWithLinkPanel(); |
| |
| var count = 0; |
| goog.events.listen(bubble, goog.ui.Component.EventType.HIDE, function() { |
| count++; |
| }); |
| |
| var closeBox = goog.dom.getElementsByTagNameAndClass( |
| goog.dom.TagName.DIV, 'tr_bubble_closebox', bubble.bubbleContainer_)[0]; |
| goog.testing.events.fireClickSequence(closeBox); |
| panelId = null; |
| |
| assertFalse('Bubble should not be visible', bubble.isVisible()); |
| assertEquals('Hide event should be dispatched', 1, count); |
| } |
| |
| function testViewPortSizeMonitorEvent() { |
| testCreateBubbleWithLinkPanel(); |
| |
| var numCalled = 0; |
| bubble.reposition = function() { |
| numCalled++; |
| }; |
| |
| assertNotUndefined('viewPortSizeMonitor_ should not be undefined', |
| bubble.viewPortSizeMonitor_); |
| bubble.viewPortSizeMonitor_.dispatchEvent(goog.events.EventType.RESIZE); |
| |
| assertEquals('reposition not called', 1, numCalled); |
| } |
| |
| function testBubblePositionPreferTop() { |
| called = false; |
| bubble.positionAtAnchor_ = function(targetCorner, bubbleCorner, overflow) { |
| called = true; |
| |
| // Assert that the bubble is positioned below the target. |
| assertEquals(goog.positioning.Corner.TOP_START, targetCorner); |
| assertEquals(goog.positioning.Corner.BOTTOM_START, bubbleCorner); |
| |
| return goog.positioning.OverflowStatus.NONE; |
| }; |
| prepareTargetWithGivenDirection('ltr', true); |
| assertTrue(called); |
| } |
| |
| function testBubblePosition() { |
| panelId = bubble.addPanel('A', 'Link', link, goog.nullFunction); |
| var CLEARANCE = goog.ui.editor.Bubble.VERTICAL_CLEARANCE_; |
| var bubbleContainer = bubble.bubbleContainer_; |
| |
| // The field is at a normal place, alomost the top of the viewport, and |
| // there is enough space at the bottom of the field. |
| var targetPos = goog.style.getFramedPageOffset(link, window); |
| var targetSize = goog.style.getSize(link); |
| var pos = goog.style.getFramedPageOffset(bubbleContainer); |
| assertEquals(targetPos.y + targetSize.height + CLEARANCE, pos.y); |
| assertEquals(targetPos.x, pos.x); |
| |
| // Move the target to the bottom of the viewport. |
| var field = document.getElementById('field'); |
| var fieldPos = goog.style.getFramedPageOffset(field, window); |
| fieldPos.y += bubble.dom_.getViewportSize().height - |
| (targetPos.y + targetSize.height); |
| goog.style.setStyle(field, 'position', 'absolute'); |
| goog.style.setPosition(field, fieldPos); |
| bubble.reposition(); |
| var bubbleSize = goog.style.getSize(bubbleContainer); |
| targetPosition = goog.style.getFramedPageOffset(link, window); |
| pos = goog.style.getFramedPageOffset(bubbleContainer); |
| assertEquals(targetPosition.y - CLEARANCE - bubbleSize.height, pos.y); |
| } |
| |
| function testBubblePositionRightAligned() { |
| prepareTargetWithGivenDirection('rtl'); |
| |
| var expectedPos = getExpectedBubblePositionWithGivenAlignment(true); |
| var pos = goog.style.getFramedPageOffset(bubble.bubbleContainer_); |
| assertRoughlyEquals(expectedPos.x, pos.x, 0.1); |
| assertRoughlyEquals(expectedPos.y, pos.y, 0.1); |
| } |
| |
| |
| /** |
| * Test for bug 1955511, the bubble should align to the right side |
| * of the target element when the bubble is RTL, regardless of the |
| * target element's directionality. |
| */ |
| function testBubblePositionLeftToRight() { |
| goog.style.setStyle(bubble.bubbleContainer_, 'direction', 'ltr'); |
| prepareTargetWithGivenDirection('rtl'); |
| |
| var expectedPos = getExpectedBubblePositionWithGivenAlignment(); |
| var pos = goog.style.getFramedPageOffset(bubble.bubbleContainer_); |
| assertRoughlyEquals(expectedPos.x, pos.x, 0.1); |
| assertRoughlyEquals(expectedPos.y, pos.y, 0.1); |
| } |
| |
| |
| /** |
| * Test for bug 1955511, the bubble should align to the left side |
| * of the target element when the bubble is LTR, regardless of the |
| * target element's directionality. |
| */ |
| function testBubblePositionRightToLeft() { |
| goog.style.setStyle(bubble.bubbleContainer_, 'direction', 'rtl'); |
| prepareTargetWithGivenDirection('ltr'); |
| |
| var expectedPos = getExpectedBubblePositionWithGivenAlignment(true); |
| var pos = goog.style.getFramedPageOffset(bubble.bubbleContainer_); |
| assertEquals(expectedPos.x, pos.x); |
| assertEquals(expectedPos.y, pos.y); |
| } |