From 7ecd72e72483869170ba8022dadcec00fe0d8082 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 30 Oct 2013 16:47:44 -0700 Subject: [PATCH] Forward Compatibility w/ WebKit & Blink Newer versions of WebKit and Blink will support both `document.body.scrollTop` and `document.documentElement.scrollTop`. Therefore, implementing cross-browser compatibility by summing the two will no longer work. This changes React to use `getUnboundedScrollPosition` so we get the fix and consistency in one change! See: https://rniwa.com/2013-10-29/web-compatibility-story-of-scrolltop-and-scrollleft/ --- src/dom/ViewportMetrics.js | 9 +++--- .../core/dom/getDocumentScrollElement.js | 27 +++++++++++++++++ .../core/dom/getUnboundedScrollPosition.js | 30 +++++++++++++++++++ 3 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 src/vendor/core/dom/getDocumentScrollElement.js create mode 100644 src/vendor/core/dom/getUnboundedScrollPosition.js diff --git a/src/dom/ViewportMetrics.js b/src/dom/ViewportMetrics.js index e9f2d3d1e0..2ccf59795e 100644 --- a/src/dom/ViewportMetrics.js +++ b/src/dom/ViewportMetrics.js @@ -18,6 +18,8 @@ "use strict"; +var getUnboundedScrollPosition = require('getUnboundedScrollPosition'); + var ViewportMetrics = { currentScrollLeft: 0, @@ -25,10 +27,9 @@ var ViewportMetrics = { currentScrollTop: 0, refreshScrollValues: function() { - ViewportMetrics.currentScrollLeft = - document.body.scrollLeft + document.documentElement.scrollLeft; - ViewportMetrics.currentScrollTop = - document.body.scrollTop + document.documentElement.scrollTop; + var scrollPosition = getUnboundedScrollPosition(window); + ViewportMetrics.currentScrollLeft = scrollPosition.x; + ViewportMetrics.currentScrollTop = scrollPosition.y; } }; diff --git a/src/vendor/core/dom/getDocumentScrollElement.js b/src/vendor/core/dom/getDocumentScrollElement.js new file mode 100644 index 0000000000..ec289c3ba6 --- /dev/null +++ b/src/vendor/core/dom/getDocumentScrollElement.js @@ -0,0 +1,27 @@ +/** + * @providesModule getDocumentScrollElement + * @typechecks + */ + +"use strict"; + +// TODO: Replace this with a UserAgent module. +var isWebkit = navigator.userAgent.indexOf('AppleWebKit') > -1; + +/** + * Gets the element with the document scroll properties such as `scrollLeft` and + * `scrollHeight`. This may differ across different browsers. + * + * NOTE: The return value can be null if the DOM is not yet ready. + * + * @param {?DOMDocument} doc Defaults to current document. + * @return {?DOMElement} + */ +function getDocumentScrollElement(doc) { + doc = doc || document; + return !isWebkit && doc.compatMode === 'CSS1Compat' ? + doc.documentElement : + doc.body; +} + +module.exports = getDocumentScrollElement; diff --git a/src/vendor/core/dom/getUnboundedScrollPosition.js b/src/vendor/core/dom/getUnboundedScrollPosition.js new file mode 100644 index 0000000000..b0e32bd53a --- /dev/null +++ b/src/vendor/core/dom/getUnboundedScrollPosition.js @@ -0,0 +1,30 @@ +/** + * @providesModule getUnboundedScrollPosition + * @typechecks + */ + +"use strict"; + +var getDocumentScrollElement = require('getDocumentScrollElement'); + +/** + * Gets the scroll position of the supplied element or window. + * + * The return values are unbounded, unlike `getScrollPosition`. This means they + * may be negative or exceed the element boundaries (which is possible using + * inertial scrolling). + * + * @param {DOMWindow|DOMElement} scrollable + * @return {object} Map with `x` and `y` keys. + */ +function getUnboundedScrollPosition(scrollable) { + if (scrollable === window) { + return getUnboundedScrollPosition(getDocumentScrollElement()); + } + return { + x: scrollable.scrollLeft, + y: scrollable.scrollTop + }; +} + +module.exports = getUnboundedScrollPosition;