1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
import { contentTop } from './common_utils';
const interactionEvents = ['mousedown', 'touchstart', 'keydown', 'wheel'];
export function createResizeObserver() {
return new ResizeObserver((entries) => {
entries.forEach((entry) => {
entry.target.dispatchEvent(new CustomEvent(`ResizeUpdate`, { detail: { entry } }));
});
});
}
/**
* Watches for change in size of a container element (e.g. for lazy-loaded images)
* and scrolls the target note to the top of the content area.
* Stops watching after any user input. So if user opens sidebar or manually
* scrolls the page we don't hijack their scroll position
*
* @param {Object} options
* @param {string} options.targetId - id of element to scroll to
* @param {string} options.container - Selector of element containing target
* @param {Element} options.component - Element containing target
*
* @return {ResizeObserver|null} - ResizeObserver instance if target looks like a note DOM ID
*/
export function scrollToTargetOnResize({
targetId = window.location.hash.slice(1),
container = '#content-body',
containerId,
} = {}) {
if (!targetId) return null;
const ro = createResizeObserver();
const containerEl =
document.querySelector(`#${containerId}`) || document.querySelector(container);
let interactionListenersAdded = false;
function keepTargetAtTop(evt) {
const anchorEl = document.getElementById(targetId);
const scrollContainer = containerId ? evt.target : document.documentElement;
if (!anchorEl) return;
const anchorTop = anchorEl.getBoundingClientRect().top + window.scrollY;
const top = anchorTop - contentTop();
scrollContainer.scrollTo({
top,
});
if (!interactionListenersAdded) {
interactionEvents.forEach((event) =>
// eslint-disable-next-line no-use-before-define
document.addEventListener(event, removeListeners),
);
interactionListenersAdded = true;
}
}
function removeListeners() {
interactionEvents.forEach((event) => document.removeEventListener(event, removeListeners));
ro.unobserve(containerEl);
containerEl.removeEventListener('ResizeUpdate', keepTargetAtTop);
}
containerEl.addEventListener('ResizeUpdate', keepTargetAtTop);
ro.observe(containerEl);
return ro;
}
|