| <!DOCTYPE html> | |
| <div style="height: 200px; width: 100px;"></div> | |
| <div id="target" style="background-color: green; width:100px; height:100px"></div> | |
| <div id="empty-target" style="width: 100px"></div> | |
| <div style="height: 200px; width: 100px;"></div> | |
| <script> | |
| var port; | |
| var entries = []; | |
| var target = document.getElementById("target"); | |
| var emptyTarget = document.getElementById("empty-target"); | |
| var scroller = document.scrollingElement; | |
| var nextStep; | |
| function clientRectToJson(rect) { | |
| if (!rect) | |
| return "null"; | |
| return { | |
| top: rect.top, | |
| right: rect.right, | |
| bottom: rect.bottom, | |
| left: rect.left | |
| }; | |
| } | |
| function entryToJson(entry) { | |
| return { | |
| boundingClientRect: clientRectToJson(entry.boundingClientRect), | |
| intersectionRect: clientRectToJson(entry.intersectionRect), | |
| rootBounds: clientRectToJson(entry.rootBounds), | |
| isIntersecting: entry.isIntersecting, | |
| target: entry.target === document.documentElement ? "html" : entry.target.id | |
| }; | |
| } | |
| function boundingClientRectToJson(element) { | |
| let r = element.getBoundingClientRect(); | |
| return [r.left, r.right, r.top, r.bottom]; | |
| } | |
| // Note that we never use RAF in this code, because this frame might get render-throttled. | |
| // Instead of RAF-ing, we just post an empty message to the parent window, which will | |
| // RAF when it is received, and then send us a message to cause the next step to run. | |
| // Use a rootMargin here, and verify it does NOT get applied for the cross-origin case. | |
| var observer = new IntersectionObserver(function(changes) { | |
| entries = entries.concat(changes) | |
| }, { rootMargin: "7px" }); | |
| observer.observe(target); | |
| observer.observe(emptyTarget); | |
| observer.observe(document.documentElement); | |
| function step0() { | |
| entries = entries.concat(observer.takeRecords()); | |
| nextStep = step1; | |
| var expected = [{ | |
| boundingClientRect: [8, 108, 208, 308], | |
| intersectionRect: [0, 0, 0, 0], | |
| rootBounds: "null", | |
| isIntersecting: false, | |
| target: target.id | |
| }, { | |
| boundingClientRect: [8, 108, 308, 308], | |
| intersectionRect: [0, 0, 0, 0], | |
| rootBounds: "null", | |
| isIntersecting: false, | |
| target: emptyTarget.id | |
| }, { | |
| boundingClientRect: boundingClientRectToJson(document.documentElement), | |
| intersectionRect: [0, 0, 0, 0], | |
| rootBounds: "null", | |
| isIntersecting: false, | |
| target: "html" | |
| }]; | |
| port.postMessage({ | |
| actual: entries.map(entryToJson), | |
| expected: expected, | |
| description: "First rAF" | |
| }, "*"); | |
| entries = []; | |
| port.postMessage({scrollTo: 200}, "*"); | |
| } | |
| function step1() { | |
| entries = entries.concat(observer.takeRecords()); | |
| var client_rect = boundingClientRectToJson(document.documentElement); | |
| // When the top document is scrolled all the way up, the iframe element is | |
| // 108px below the scrolling viewport, and the iframe has a 2px border. When | |
| // the top document is scrolled to y=200, the top 90px of the iframe's content | |
| // is visible. | |
| var expected = [{ | |
| boundingClientRect: client_rect, | |
| intersectionRect: client_rect.slice(0, 3).concat(90), | |
| rootBounds: "null", | |
| isIntersecting: true, | |
| target: "html" | |
| }]; | |
| port.postMessage({ | |
| actual: entries.map(entryToJson), | |
| expected: expected, | |
| description: "topDocument.scrollingElement.scrollTop = 200" | |
| }, "*"); | |
| entries = []; | |
| scroller.scrollTop = 250; | |
| nextStep = step2; | |
| port.postMessage({}, "*"); | |
| } | |
| function step2() { | |
| entries = entries.concat(observer.takeRecords()); | |
| var expected = [{ | |
| boundingClientRect: [8, 108, -42, 58], | |
| intersectionRect: [8, 108, 0, 58], | |
| rootBounds: "null", | |
| isIntersecting: true, | |
| target: target.id | |
| }, { | |
| boundingClientRect: [8, 108, 58, 58], | |
| intersectionRect: [8, 108, 58, 58], | |
| rootBounds: "null", | |
| isIntersecting: true, | |
| target: emptyTarget.id | |
| }]; | |
| port.postMessage({ | |
| actual: entries.map(entryToJson), | |
| expected: expected, | |
| description: "iframeDocument.scrollingElement.scrollTop = 250" | |
| }, "*"); | |
| entries = []; | |
| nextStep = step3; | |
| port.postMessage({scrollTo: 100}, "*"); | |
| } | |
| function step3() { | |
| entries = entries.concat(observer.takeRecords()); | |
| var expected = [{ | |
| boundingClientRect: [8, 108, -42, 58], | |
| intersectionRect: [0, 0, 0, 0], | |
| rootBounds: "null", | |
| isIntersecting: false, | |
| target: target.id | |
| }, { | |
| boundingClientRect: [8, 108, 58, 58], | |
| intersectionRect: [0, 0, 0, 0], | |
| rootBounds: "null", | |
| isIntersecting: false, | |
| target: emptyTarget.id | |
| }, { | |
| boundingClientRect: boundingClientRectToJson(document.documentElement), | |
| intersectionRect: [0, 0, 0, 0], | |
| rootBounds: "null", | |
| isIntersecting: false, | |
| target: "html" | |
| }]; | |
| port.postMessage({ | |
| actual: entries.map(entryToJson), | |
| expected: expected, | |
| description: "topDocument.scrollingElement.scrollTop = 100" | |
| }, "*"); | |
| port.postMessage({DONE: 1}, "*"); | |
| } | |
| function handleMessage(event) | |
| { | |
| port = event.source; | |
| nextStep(); | |
| } | |
| nextStep = step0; | |
| window.addEventListener("message", handleMessage); | |
| </script> |