|
1 | 1 | import React, { PropTypes } from 'react';
|
2 | 2 | import { Link } from 'react-router-dom';
|
3 | 3 |
|
4 |
| -function hashLinkScroll(hashFragment) { |
| 4 | +let hashFragment = ''; |
| 5 | +let observer = null; |
| 6 | +let asyncTimer = null; |
| 7 | + |
| 8 | +function reset() { |
| 9 | + hashFragment = ''; |
| 10 | + if (observer !== null) observer.disconnect(); |
| 11 | + if (asyncTimer !== null) { |
| 12 | + window.clearTimeout(asyncTimer); |
| 13 | + asyncTimer = null; |
| 14 | + } |
| 15 | +} |
| 16 | + |
| 17 | +function getElAndScroll() { |
| 18 | + const element = document.getElementById(hashFragment); |
| 19 | + if (element !== null) { |
| 20 | + element.scrollIntoView(); |
| 21 | + reset(); |
| 22 | + return true; |
| 23 | + } |
| 24 | + return false; |
| 25 | +} |
| 26 | + |
| 27 | +function setupMutationObserver() { |
| 28 | + observer = new MutationObserver(getElAndScroll); |
| 29 | +} |
| 30 | + |
| 31 | +function hashLinkScroll() { |
5 | 32 | // Push onto callback queue so it runs after the DOM is updated
|
6 | 33 | setTimeout(() => {
|
7 |
| - const element = document.getElementById(hashFragment); |
8 |
| - if (element !== null) element.scrollIntoView(); |
| 34 | + if (getElAndScroll() === false) { |
| 35 | + if (observer === null) setupMutationObserver(); |
| 36 | + observer.observe(document, { attributes: true, childList: true, subtree: true }); |
| 37 | + if (asyncTimer !== null) window.clearTimeout(asyncTimer); |
| 38 | + // if the element doesn't show up in 10 seconds, stop checking |
| 39 | + asyncTimer = window.setTimeout(() => { |
| 40 | + reset(); |
| 41 | + }, 10000); |
| 42 | + } |
9 | 43 | }, 0);
|
10 | 44 | }
|
11 | 45 |
|
12 | 46 | export function HashLink(props) {
|
13 | 47 | function handleClick(e) {
|
14 | 48 | if (props.onClick) props.onClick(e);
|
15 |
| - let hashFragment = ''; |
| 49 | + let hash = ''; |
16 | 50 | if (typeof props.to === 'string') {
|
17 |
| - hashFragment = props.to.split('#').slice(1).join('#'); |
| 51 | + hash = props.to.split('#').slice(1).join('#'); |
18 | 52 | } else if (typeof props.to === 'object' && typeof props.to.hash === 'string') {
|
19 |
| - hashFragment = props.to.hash.replace('#', ''); |
| 53 | + hash = props.to.hash.replace('#', ''); |
| 54 | + } |
| 55 | + if (hash !== '') { |
| 56 | + hashFragment = hash; |
| 57 | + hashLinkScroll(); |
20 | 58 | }
|
21 |
| - if (hashFragment !== '') hashLinkScroll(hashFragment); |
22 | 59 | }
|
23 | 60 | return <Link {...props} onClick={handleClick}>{props.children}</Link>;
|
24 | 61 | }
|
|
0 commit comments