diff --git a/src/get-bounding-client-rect.js b/src/get-bounding-client-rect.js new file mode 100644 index 000000000000..15ccd15fa0a7 --- /dev/null +++ b/src/get-bounding-client-rect.js @@ -0,0 +1,72 @@ +/** + * Copyright 2016 The AMP HTML 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. + */ + +/** + * @fileoverview + * IE 10 throws "Unspecified error" when calling getBoundingClientRect() on a + * disconnected node. + * @see https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/106812/ + */ + +import { + LayoutRectDef, + layoutRectLtwh, +} from './layout-rect'; +import {isConnectedNode} from './dom'; + +const nativeClientRect = Element.prototype.getBoundingClientRect; + +/** + * Polyfill for Node.getBoundingClientRect API. + * @param {!Element} el + * @return {!ClientRect|!LayoutRectDef} + */ +function getBoundingClientRect(el) { + if (isConnectedNode(el)) { + return nativeClientRect.call(el); + } + + return layoutRectLtwh(0, 0, 0, 0); +} + +/** + * Determines if this polyfill should be installed. + * @param {!Window} win + * @return {boolean} + */ +function shouldInstall(win) { + try { + const div = win.document.createElement('div'); + const rect = div./*OK*/getBoundingClientRect(); + return rect.top !== 0; + } catch (e) { + // IE 10 or less + return true; + } +} + +/** + * Sets the getBoundingClientRect polyfill if using IE 10 or an + * earlier version. + * @param {!Window} win + */ +export function install(win) { + if (shouldInstall(win)) { + win.Object.defineProperty(win.Element.prototype, 'getBoundingClientRect', { + value: getBoundingClientRect, + }); + } +} diff --git a/src/polyfills.js b/src/polyfills.js index 29d471f02ec6..c939d9abe49d 100644 --- a/src/polyfills.js +++ b/src/polyfills.js @@ -22,6 +22,9 @@ import { } from './polyfills/domtokenlist-toggle'; import {install as installDocContains} from './polyfills/document-contains'; import {install as installFetch} from './polyfills/fetch'; +import { + install as installGetBoundingClientRect, +} from './get-bounding-client-rect'; import {install as installMathSign} from './polyfills/math-sign'; import {install as installObjectAssign} from './polyfills/object-assign'; import {install as installObjectValues} from './polyfills/object-values'; @@ -38,6 +41,7 @@ installObjectValues(self); installPromise(self); installDocContains(self); installArrayIncludes(self); +installGetBoundingClientRect(self); // isExperimentOn() must be called after Object.assign polyfill is installed. // TODO(jridgewell): Ship custom-elements-v1. For now, we use this hack so it // is DCE'd from production builds.