|  | <!doctype html> | 
|  | <title>Navigating to a text fragment anchor</title> | 
|  | <script src="stash.js"></script> | 
|  | <script> | 
|  | function isInView(element) { | 
|  | let rect = element.getBoundingClientRect(); | 
|  | return rect.top >= 0 && rect.top <= window.innerHeight | 
|  | && rect.left >= 0 && rect.left <= window.innerWidth; | 
|  | } | 
|  |  | 
|  | function checkScroll() { | 
|  | let position = 'unknown'; | 
|  | if (window.scrollY == 0) | 
|  | position = 'top'; | 
|  | else if (isInView(document.getElementById('element'))) | 
|  | position = 'element'; | 
|  | else if (isInView(document.getElementById('text'))) | 
|  | position = 'text'; | 
|  | else if (isInView(document.getElementById('more-text'))) | 
|  | position = 'more-text'; | 
|  | else if (isInView(document.getElementById('cross-node-context'))) | 
|  | position = 'cross-node-context'; | 
|  | else if (isInView(document.getElementById('text-directive-parameters'))) | 
|  | position = 'text-directive-parameters'; | 
|  | else if (isInView(document.getElementById('shadow-parent'))) | 
|  | position = 'shadow-parent'; | 
|  | else if (isInView(document.getElementById('hidden'))) | 
|  | position = 'hidden'; | 
|  | else if (isInView(document.getElementById('horizontal-scroll')) && window.scrollX > 0) | 
|  | position = 'horizontal-scroll'; | 
|  |  | 
|  | let target = document.querySelector(":target"); | 
|  |  | 
|  | if (!target && position == 'shadow-parent') { | 
|  | let shadow = document.getElementById("shadow-parent").shadowRoot.firstElementChild; | 
|  | if (shadow.matches(":target")) { | 
|  | target = shadow; | 
|  | position = 'shadow'; | 
|  | } | 
|  | } | 
|  |  | 
|  | let results = { | 
|  | scrollPosition: position, | 
|  | href: window.location.href, | 
|  | target: target ? target.id : 'undefined' | 
|  | }; | 
|  |  | 
|  | let key = (new URL(document.location)).searchParams.get("key"); | 
|  | stashResultsThenClose(key, results); | 
|  | } | 
|  |  | 
|  | // Ensure two animation frames on load to test the fallback to element anchor, | 
|  | // which gets queued for the next frame if the text fragment is not found. | 
|  | window.onload = function() { | 
|  | window.requestAnimationFrame(function() { | 
|  | window.requestAnimationFrame(checkScroll); | 
|  | }) | 
|  | } | 
|  | </script> | 
|  | <style> | 
|  | .scroll-section { | 
|  | /* 1000px margin on top and bottom so only one section can be in view. */ | 
|  | margin: 1000px 0px; | 
|  | } | 
|  | #hidden { | 
|  | visibility: hidden; | 
|  | } | 
|  | #horizontal-scroll { | 
|  | margin-left: 2000px; | 
|  | } | 
|  | #display-none { | 
|  | display: none; | 
|  | } | 
|  | </style> | 
|  | <body> | 
|  | <div id="element" class="scroll-section">Element</div> | 
|  | <p id="text" class="scroll-section"> | 
|  | This is a test page !$'()*+./:;=?@_~ &,- ネコ | 
|  | <br> | 
|  | foo foo foo bar bar bar | 
|  | </p> | 
|  | <p id="more-text" class="scroll-section">More test page text</p> | 
|  | <div class="scroll-section"> | 
|  | <div> | 
|  | <p>prefix</p> | 
|  | <p id="cross-node-context">test page</p> | 
|  | </div> | 
|  | <div><p>suffix</p></div> | 
|  | </div> | 
|  | <p id="text-directive-parameters" class="scroll-section">this,is,test,page</p> | 
|  | <div id="shadow-parent" class="scroll-section"></div> | 
|  | <script> | 
|  | let shadow = document.getElementById("shadow-parent").attachShadow({mode: 'open'}); | 
|  | shadow.innerHTML = '<p id="shadow">shadow text</p>'; | 
|  | </script> | 
|  | <p id="hidden" class="scroll-section">hidden text</p> | 
|  | <p id="horizontal-scroll" class="scroll-section">horizontally scrolled text</p> | 
|  | <p id="display-none" class="scroll-section">display none</p> | 
|  | </body> |