Skip to content

Instantly share code, notes, and snippets.

@AutomatedTester
Last active December 19, 2015 04:49
Show Gist options
  • Select an option

  • Save AutomatedTester/5899994 to your computer and use it in GitHub Desktop.

Select an option

Save AutomatedTester/5899994 to your computer and use it in GitHub Desktop.
# HG changeset patch
# User David Burns <dburns@mozilla.com>
# Date 1373315218 -3600
# Node ID aaee2e4f1abc62939b8a294f18351062951df032
# Parent 1639af60732e914cdd593f92f7a6874c5bcfa25f
imported patch bug859264
diff --git a/testing/marionette/client/marionette/tests/unit/test_click_scrolling.py b/testing/marionette/client/marionette/tests/unit/test_click_scrolling.py
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/tests/unit/test_click_scrolling.py
@@ -0,0 +1,75 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import time
+from marionette_test import MarionetteTestCase
+from errors import *
+
+
+class TestClick(MarionetteTestCase):
+ def test_click(self):
+ test_html = self.marionette.absolute_url("test.html")
+ self.marionette.navigate(test_html)
+ link = self.marionette.find_element("id", "mozLink")
+ link.click()
+ self.assertEqual("Clicked", self.marionette.execute_script("return document.getElementById('mozLink').innerHTML;"))
+
+ def testClickingALinkMadeUpOfNumbersIsHandledCorrectly(self):
+ test_html = self.marionette.absolute_url("clicks.html")
+ self.marionette.navigate(test_html)
+ self.marionette.find_element("link text", "333333").click()
+ count = 0
+ while len(self.marionette.find_elements("id", "username")) == 0:
+ count += 1
+ time.sleep(1)
+ if count == 30:
+ self.fail("Element id=username not found after 30 seconds")
+
+ self.assertEqual(self.marionette.title, "XHTML Test Page")
+ def testShouldScrollToClickOnAnElementHiddenByOverflow(self):
+ test_html = self.marionette.absolute_url("click_out_of_bounds_overflow.html")
+ self.marionette.navigate(test_html)
+ link = self.marionette.find_element("id", "link")
+ try:
+ link.click()
+ except MoveTargetOutOfBoundsException:
+ self.fail("Should not be out of bounds")
+
+ def testShouldBeAbleToClickOnAnElementHiddenByOverflow(self):
+ test_html = self.marionette.absolute_url("scroll.html")
+ self.marionette.navigate(test_html)
+ import pdb
+ pdb.set_trace()
+ link = self.marionette.find_element("id", "line8")
+ link.click()
+ self.assertEqual("line8", self.marionette.find_element("id", "clicked").text)
+
+ def testShouldNotScrollOverflowElementsWhichAreVisible(self):
+ test_html = self.marionette.absolute_url("scroll2.html")
+ self.marionette.navigate(test_html)
+ list = self.marionette.find_element("tag name", "ul")
+ item = list.find_element("id", "desired")
+ item.click()
+ yOffset = self.marionette.execute_script("return arguments[0].scrollTop;", list)
+ self.assertEqual(0, yOffset)
+
+ def testShouldNotScrollIfAlreadyScrolledAndElementIsInView(self):
+ test_html = self.marionette.absolute_url("scroll3.html")
+ self.marionette.navigate(test_html)
+ self.marionette.find_element("id", "button1").click()
+ scrollTop = self.marionette.execute_script("return document.body.scrollTop;")
+ self.marionette.find_element("id", "button2").click()
+ self.assertEqual(scrollTop, self.marionette.execute_script("return document.body.scrollTop;"))
+
+ def testShouldBeAbleToClickRadioButtonScrolledIntoView(self):
+ test_html = self.marionette.absolute_url("scroll4.html")
+ self.marionette.navigate(test_html)
+ self.marionette.find_element("id", "radio").click()
+ # If we dont throw we are good
+
+ def testShouldScrollOverflowElementsIfClickPointIsOutOfViewButElementIsInView(self):
+ test_html = self.marionette.absolute_url("scroll5.html")
+ self.marionette.navigate(test_html)
+ self.marionette.find_element("id", "inner").click()
+ self.assertEqual("clicked", self.marionette.find_element("id", "clicked").text)
diff --git a/testing/marionette/client/marionette/www/scroll.html b/testing/marionette/client/marionette/www/scroll.html
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/www/scroll.html
@@ -0,0 +1,27 @@
+<html>
+<head>
+</head>
+<body>
+<script>
+function dump(event) {
+ var elt = event.target || event.srcElement;
+ document.getElementById('clicked').innerHTML = elt.innerHTML;
+}
+</script>
+<div style='height: 150px'></div>
+<ul style='overflow: scroll; width: 150px; height: 80px; background-color: yellow' onclick="dump(event)">
+<li id='line1'>line1</li>
+<li id='line2'>line2</li>
+<li id='line3'>line3</li>
+<li id='line4'>line4</li>
+<li id='line5'>line5</li>
+<li id='line6'>line6</li>
+<li id='line7'>line7</li>
+<li id='line8'>line8</li>
+<li id='line9'>line9</li>
+</ul>
+<div>
+Clicked: <span id='clicked'></span>
+</div>
+</body>
+</html>
diff --git a/testing/marionette/client/marionette/www/scroll2.html b/testing/marionette/client/marionette/www/scroll2.html
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/www/scroll2.html
@@ -0,0 +1,21 @@
+<html>
+<head>
+</head>
+<body>
+<ul style='overflow: scroll; height: 100px;'>
+<li></li>
+<li></li>
+<li id="desired">Text</li>
+<li></li>
+<li></li>
+<li></li>
+<li></li>
+<li></li>
+<li></li>
+<li></li>
+<li></li>
+<li></li>
+<li></li>
+</ul>
+</body>
+</html>
diff --git a/testing/marionette/client/marionette/www/scroll3.html b/testing/marionette/client/marionette/www/scroll3.html
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/www/scroll3.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+<br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br />
+<button id="button1">Button1</button>
+<br /><br /><br /><br />
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button2">Button2</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+<br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br /><br /></br /><br />
\ No newline at end of file
diff --git a/testing/marionette/client/marionette/www/scroll4.html b/testing/marionette/client/marionette/www/scroll4.html
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/www/scroll4.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+ <input type="radio" id="radio" />
+ <br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
+</body>
+</html>
diff --git a/testing/marionette/client/marionette/www/scroll5.html b/testing/marionette/client/marionette/www/scroll5.html
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/www/scroll5.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+</head>
+<body>
+<script>
+function dump(text) {
+ document.getElementById('clicked').innerHTML = text;
+}
+</script>
+<div style='overflow: scroll; width: 150px; height: 200px; background-color: yellow' id="outer">
+ <div style="width: 150px; height: 5000px; background-color: red;" onclick="dump('clicked')" id="inner">
+ </div>
+</div>
+<div>
+Clicked: <span id='clicked'></span>
+</div>
+</body>
+</html>
diff --git a/testing/marionette/marionette-listener.js b/testing/marionette/marionette-listener.js
--- a/testing/marionette/marionette-listener.js
+++ b/testing/marionette/marionette-listener.js
@@ -625,17 +625,17 @@ function coordinates(target, x, y) {
*/
function elementInViewport(el) {
let rect = el.getBoundingClientRect();
return (/* Top left corner is in view */
(rect.top >= curWindow.pageYOffset &&
rect.top <= (curWindow.pageYOffset + curWindow.innerHeight) &&
rect.left >= curWindow.pageXOffset &&
rect.left <= (curWindow.pageXOffset + curWindow.innerWidth)) ||
- /* Top right corner is in view */
+ /* Top right corner is in view */
(rect.top >= curWindow.pageYOffset &&
rect.top <= (curWindow.pageYOffset + curWindow.innerHeight) &&
rect.right >= curWindow.pageXOffset &&
rect.right <= (curWindow.pageXOffset + curWindow.innerWidth)) ||
/* Bottom right corner is in view */
(rect.bottom >= curWindow.pageYOffset &&
rect.bottom <= (curWindow.pageYOffset + curWindow.innerHeight) &&
rect.right >= curWindow.pageXOffset &&
@@ -649,36 +649,249 @@ function elementInViewport(el) {
((rect.top + (rect.height/2)) <= curWindow.pageYOffset &&
(rect.top + (rect.height/2)) >= (curWindow.pageYOffset + curWindow.innerHeight) &&
(rect.left + (rect.width/2)) <= curWindow.pageXOffset &&
(rect.left + (rect.width/2)) >= (curWindow.pageXOffset + curWindow.innerWidth))
);
}
/**
+ * This function calculates the amount of scrolling necessary to bring the
+ * target location into view.
+ *
+ * @param targetLocation The target location relative to the current
+ * viewport.
+ * @param viewportDimension The size of the current viewport.
+ * @return Returns the scroll offset necessary to bring the given
+ * target location into view.
+ */
+function calculateViewportScrolling_(targetLocation, viewportDimension) {
+ if (targetLocation >= viewportDimension) {
+ // Scroll until the target location appears on the right/bottom side of
+ // the viewport.
+ return targetLocation - (viewportDimension - 1);
+ }
+
+ if (targetLocation < 0) {
+ // Scroll until the target location appears on the left/top side of the
+ // viewport.
+ return targetLocation;
+ }
+
+ // The location is already within the viewport. No scrolling necessary.
+ return 0;
+};
+
+/**
+ * This function takes a relative location according to the current viewport. If
+ * this location is not visible in the viewport, it scrolls the location into
+ * view. The function returns the new relative location after scrolling.
+ *
+ * @param targetLocation The target location relative
+ * to (0, 0) coordinate of the viewport.
+ * @param opt_currentWindow The current browser window.
+ * @return The target location within the viewport
+ * after scrolling.
+ */
+function getInViewLocation(targetLocation, opt_currentWindow){
+ let currentWindow = opt_currentWindow || curWindow;
+ let docEl = curWindow.document.documentElement;
+ let viewportSize = {"width": docEl.width, "height": docEl.height};
+
+ let xScrolling = calculateViewportScrolling_(
+ targetLocation.x,
+ viewportSize.width);
+
+ let yScrolling = calculateViewportScrolling_(
+ targetLocation.y,
+ viewportSize.height);
+
+ let scrollOffset = { "x": currentWindow.document.scrollLeft, "y": currentWindow.document.scrollTop};
+
+ if (xScrolling != 0 || yScrolling != 0) {
+ currentWindow.scrollBy(xScrolling, yScrolling);
+ }
+
+ // It is difficult to determine the size of the web page in some browsers.
+ // We check if the scrolling we intended to do really happened. If not we
+ // assume that the target location is not on the web page.
+ var newScrollOffset = { "x": currentWindow.document.scrollLeft, "y": currentWindow.document.scrollTop};
+
+ if ((scrollOffset.x + xScrolling != newScrollOffset.x) ||
+ (scrollOffset.y + yScrolling != newScrollOffset.y)) {
+ throw 'The target location (' + (targetLocation.x + scrollOffset.x) +
+ ', ' + (targetLocation.y + scrollOffset.y) + ') is not on the webpage.';
+ }
+
+ var inViewLocation = {
+ "x": targetLocation.x - xScrolling,
+ "y": targetLocation.y - yScrolling};
+
+ // The target location should be within the viewport after scrolling.
+ // This is assertion code. We do not expect them ever to become true.
+ if (0 > inViewLocation.x || inViewLocation.x >= viewportSize.width) {
+ throw 'The target location (' +
+ inViewLocation.x + ', ' + inViewLocation.y +
+ ') should be within the viewport (' +
+ viewportSize.width + ':' + viewportSize.height +
+ ') after scrolling.';
+ }
+ if (0 > inViewLocation.y || inViewLocation.y >= viewportSize.height) {
+ throw 'The target location (' +
+ inViewLocation.x + ', ' + inViewLocation.y +
+ ') should be within the viewport (' +
+ viewportSize.width + ':' + viewportSize.height +
+ ') after scrolling.';
+ }
+
+ return inViewLocation;
+}
+
+/**
+ * Scrolls the scrollable element so that the region is fully visible.
+ * If the region is too large, it will be aligned to the top-left of the
+ * scrollable element. The region should be relative to the scrollable
+ * element's current scroll position.
+ *
+ * @param region The region to use.
+ * @param scrollable The scrollable element to scroll.
+ */
+function scrollRegionIntoView_(region, scrollable) {
+ scrollable.scrollLeft += Math.min(
+ region.left, Math.max(region.left - region.width, 0));
+ scrollable.scrollTop += Math.min(
+ region.top, Math.max(region.top - region.height, 0));
+};
+
+/**
+ * Scrolls the region of an element into the container's view. If the
+ * region is too large to fit in the view, it will be aligned to the
+ * top-left of the container.
+ *
+ * The element and container should be attached to the current document.
+ *
+ * @param elem The element to use.
+ * @param elemRegion The region relative to the element to be
+ * scrolled into view.
+ * @param container A container of the given element.
+ */
+function scrollElementRegionIntoContainerView_(elem, elemRegion, container) {
+ let doc = curWindow.document;
+
+ let elRect = elem.getBoundingClientRect();
+ let elemPos = {"x": elRect.left + doc.scrollLeft, "y": elRect.top + doc.scrollTop};
+
+ let containerRect = container.getBoundingClientRect();
+ let containerPos = {"x": elRect.left + doc.scrollLeft, "y": elRect.top + doc.scrollTop};
+
+ let left = curWindow.getComputedStyle(container, null).getPropertyValue('borderLeftWidth');
+ let right = curWindow.getComputedStyle(container, null).getPropertyValue('borderRightWidth');;
+ let top = curWindow.getComputedStyle(container, null).getPropertyValue('borderTopWidth');;
+ let bottom = curWindow.getComputedStyle(container, null).getPropertyValue('borderBottomWidth');;
+ let containerBorder = {"top": top, "right": right, "bottom": bottom, "left": left};
+
+ // Relative pos. of the element's border box to the container's content box.
+ let relX = elemPos.x + elemRegion.left - containerPos.x - containerBorder.left;
+ let relY = elemPos.y + elemRegion.top - containerPos.y - containerBorder.top;
+
+ // How much the element can move in the container.
+ let spaceX = container.clientWidth - elemRegion.width;
+ let spaceY = container.clientHeight - elemRegion.height;
+
+ scrollRegionIntoView_({"left": relX, "top": relY, "width": spaceX, "height": spaceY},
+ container);
+};
+
+/**
+ * Scrolls the element into the client's view. If the element or region is
+ * too large to fit in the view, it will be aligned to the top-left of the
+ * container.
+ *
+ * The element should be attached to the current document.
+ *
+ * @param elem The element to use.
+ * @param elemRegion The region relative to the element to be
+ * scrolled into view.
+ */
+function scrollElementRegionIntoClientView(elem, elemRegion) {
+ let doc = curWindow.document;
+
+ // Scroll the containers.
+ for (var container = elem.parentNode;
+ container && container != doc.body && container != doc.documentElement;
+ container = container.parentNode) {
+ scrollElementRegionIntoContainerView_(elem, elemRegion, container);
+ }
+
+ // Scroll the actual window.
+ let elRect = elem.getBoundingClientRect();
+ var elemPageOffset = {"x": elRect.left + doc.scrollLeft, "y": elRect.top + doc.scrollTop};
+
+ let docEl = curWindow.document.documentElement;
+ let viewportSize = {"width": docEl.width, "height": docEl.height};
+
+ var region = {
+ "left": elemPageOffset.x + elemRegion.left - (doc.body ? doc.body.scrollLeft : 0),
+ "top": elemPageOffset.y + elemRegion.top - (doc.body ? doc.body.scrollTop : 0),
+ "width": viewportSize.width - elemRegion.width,
+ "height": viewportSize.height - elemRegion.height};
+
+ scrollRegionIntoView_(region, doc.body || doc.documentElement);
+};
+
+/**
+ * Scrolls the element into the client's view and returns its position
+ * relative to the client viewport. If the element or region is too
+ * large to fit in the view, it will be aligned to the top-left of the
+ * container.
+ *
+ * The element should be attached to the current document.
+ *
+ * @param elem The element to use.
+ * @param opt_elemRegion The region relative to the element
+ * to be scrolled into view.
+ * @return The coordinate of the element in client
+ * space.
+ */
+function getLocationInView(elem, opt_elemRegion) {
+ var elemRegion;
+ if (opt_elemRegion) {
+ elemRegion = {
+ "left": opt_elemRegion.left, "top": opt_elemRegion.top,
+ "width": opt_elemRegion.width, "height": opt_elemRegion.height};
+ } else {
+ elemRegion = {"left": 0, "top": 0, "width": elem.offsetWidth, "height": elem.offsetHeight};
+ }
+ scrollElementRegionIntoClientView(elem, elemRegion);
+
+ // This is needed for elements that are split across multiple lines.
+ var rect = elem.getClientRects ? elem.getClientRects()[0] : null;
+ var elemClientPos = rect ?
+ {"x": rect.left, "y": rect.top} :
+ elem.getBoundingClientRect();
+ return {"x": elemClientPos.x + elemRegion.left,
+ "y": elemClientPos.y + elemRegion.top};
+};
+
+/**
* This function throws the visibility of the element error
*/
function checkVisible(el) {
//check if the element is visible
let visible = utils.isElementDisplayed(el);
if (!visible) {
return false;
}
if (el.tagName.toLowerCase() === 'body') {
return true;
}
if (!elementInViewport(el)) {
//check if scroll function exist. If so, call it.
- if (el.scrollIntoView) {
- el.scrollIntoView(true);
- if (!elementInViewport(el)) {
- return false;
- }
- }
- else {
+ getLocationInView(el);
+ if (!elementInViewport(el)) {
return false;
}
}
return true;
}
//x and y are coordinates relative to the viewport
function generateEvents(type, x, y, touchId, target) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment