diff --git a/src/browser/client-scripts/index.js b/src/browser/client-scripts/index.js index 4106d69d2..3673adc8d 100644 --- a/src/browser/client-scripts/index.js +++ b/src/browser/client-scripts/index.js @@ -70,10 +70,11 @@ function prepareScreenshotUnsafe(areas, opts) { } } - var viewportWidth = document.documentElement.clientWidth, - viewportHeight = document.documentElement.clientHeight, - documentWidth = document.documentElement.scrollWidth, - documentHeight = document.documentElement.scrollHeight, + var mainDocumentElem = util.getMainDocumentElem(), + viewportWidth = mainDocumentElem.clientWidth, + viewportHeight = mainDocumentElem.clientHeight, + documentWidth = mainDocumentElem.scrollWidth, + documentHeight = mainDocumentElem.scrollHeight, viewPort = new Rect({ left: util.getScrollLeft(scrollElem), top: util.getScrollTop(scrollElem), @@ -381,8 +382,9 @@ function isEditable(element) { } function scrollToCaptureAreaInSafari(viewportCurr, captureArea, scrollElem) { - var documentHeight = Math.round(document.documentElement.scrollHeight); - var viewportHeight = Math.round(document.documentElement.clientHeight); + var mainDocumentElem = util.getMainDocumentElem(); + var documentHeight = Math.round(mainDocumentElem.scrollHeight); + var viewportHeight = Math.round(mainDocumentElem.clientHeight); var maxScrollByY = documentHeight - viewportHeight; scrollElem.scrollTo(viewportCurr.left, Math.min(captureArea.top, maxScrollByY)); diff --git a/src/browser/client-scripts/rect.js b/src/browser/client-scripts/rect.js index 9f235fba1..a9679de34 100644 --- a/src/browser/client-scripts/rect.js +++ b/src/browser/client-scripts/rect.js @@ -150,7 +150,7 @@ Rect.prototype = { exports.Rect = Rect; exports.getAbsoluteClientRect = function getAbsoluteClientRect(element, opts) { - var coords = element.getBoundingClientRect(); + var coords = getNestedBoundingClientRect(element, window); var widthRatio = coords.width % opts.viewportWidth; var heightRatio = coords.height % opts.documentHeight; @@ -164,3 +164,76 @@ exports.getAbsoluteClientRect = function getAbsoluteClientRect(element, opts) { return clientRect.translate(util.getScrollLeft(opts.scrollElem), util.getScrollTop(opts.scrollElem)); }; + +function getNestedBoundingClientRect(node, boundaryWindow) { + var ownerIframe = util.getOwnerIframe(node); + if (ownerIframe === null || util.getOwnerWindow(ownerIframe) === boundaryWindow) { + return node.getBoundingClientRect(); + } + + var rects = [node.getBoundingClientRect()]; + var currentIframe = ownerIframe; + + while (currentIframe) { + var rect = getBoundingClientRectWithBorderOffset(currentIframe); + rects.push(rect); + + currentIframe = util.getOwnerIframe(currentIframe); + if (currentIframe && util.getOwnerWindow(currentIframe) === boundaryWindow) { + rect = getBoundingClientRectWithBorderOffset(currentIframe); + rects.push(rect); + break; + } + } + + return mergeRectOffsets(rects); +} + +function getBoundingClientRectWithBorderOffset(node) { + var dimensions = getElementDimensions(node); + + return mergeRectOffsets([ + node.getBoundingClientRect(), + { + top: dimensions.borderTop, + left: dimensions.borderLeft, + bottom: dimensions.borderBottom, + right: dimensions.borderRight, + x: dimensions.borderLeft, + y: dimensions.borderTop + } + ]); +} + +function getElementDimensions(element) { + var calculatedStyle = util.getOwnerWindow(element).getComputedStyle(element); + + return { + borderLeft: parseFloat(calculatedStyle.borderLeftWidth), + borderRight: parseFloat(calculatedStyle.borderRightWidth), + borderTop: parseFloat(calculatedStyle.borderTopWidth), + borderBottom: parseFloat(calculatedStyle.borderBottomWidth) + }; +} + +function mergeRectOffsets(rects) { + return rects.reduce(function (previousRect, rect) { + if (previousRect === null) { + return rect; + } + + var nextTop = previousRect.top + rect.top; + var nextLeft = previousRect.left + rect.left; + + return { + top: nextTop, + left: nextLeft, + width: previousRect.width, + height: previousRect.height, + bottom: nextTop + previousRect.height, + right: nextLeft + previousRect.width, + x: nextLeft, + y: nextTop + }; + }); +} diff --git a/src/browser/client-scripts/util.js b/src/browser/client-scripts/util.js index e6438101a..d34de4560 100644 --- a/src/browser/client-scripts/util.js +++ b/src/browser/client-scripts/util.js @@ -105,3 +105,38 @@ exports.forEachRoot = function (cb) { traverseRoots(document.documentElement); }; + +exports.getOwnerWindow = function (node) { + if (!node.ownerDocument) { + return null; + } + + return node.ownerDocument.defaultView; +}; + +exports.getOwnerIframe = function (node) { + var nodeWindow = exports.getOwnerWindow(node); + if (nodeWindow) { + return nodeWindow.frameElement; + } + + return null; +}; + +exports.getMainDocumentElem = function (currDocumentElem) { + if (!currDocumentElem) { + currDocumentElem = document.documentElement; + } + + var currIframe = exports.getOwnerIframe(currDocumentElem); + if (!currIframe) { + return currDocumentElem; + } + + var currWindow = exports.getOwnerWindow(currIframe); + if (!currWindow) { + return currDocumentElem; + } + + return exports.getMainDocumentElem(currWindow.document.documentElement); +};