aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Utility/html.ts
blob: 10d52971783ba720d524aae9625299735bb07e9d (plain) (blame)
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import settings from "$stores/settings";
import { get } from "svelte/store";

export const nbsp = (str: string) => str.replace(/ /g, " ");

export const createHeightObserver = (details = true) => {
	const observedElements = new Set<HTMLElement>();
	const resizeObservers = new Map<HTMLElement, ResizeObserver>();
	const detailObservers = new Map<HTMLElement, MutationObserver>();

	const applyHeightLimit = (target: HTMLElement) => {
		if (!get(settings).displayLimitListHeight) {
			target.style.height = "auto";

			return;
		}

		target.style.height = "auto";

		const elementBound = target.getBoundingClientRect();
		const height = window.innerHeight - elementBound.top - 2.5 * 16;

		if (elementBound.height > height) target.style.height = `${height}px`;
	};

	const observeElement = (element: HTMLElement) => {
		if (element.dataset.observed) return;

		const resizeObserver = new ResizeObserver((entries) => {
			entries.forEach((entry) => {
				const target = entry.target as HTMLElement;

				applyHeightLimit(target);
			});
		});

		resizeObserver.observe(element);
		resizeObservers.set(element, resizeObserver);

		if (details) {
			const detailsObserver = new MutationObserver((mutations) => {
				mutations.forEach((mutation) => {
					const target = mutation.target as HTMLDetailsElement;

					if (target.tagName === "DETAILS" && !target.open)
						target.style.height = "auto";
				});
			});

			detailsObserver.observe(element, { attributes: true });
			detailObservers.set(element, detailsObserver);
		}

		element.dataset.observed = "true";

		observedElements.add(element);
		applyHeightLimit(element);
	};

	document.querySelectorAll<HTMLElement>(".list").forEach(observeElement);

	const mutationObserver = new MutationObserver((mutations) => {
		mutations.forEach((mutation) => {
			mutation.addedNodes.forEach((node) => {
				if (!(node instanceof HTMLElement)) return;

				if (node.matches(".list")) observeElement(node);

				node.querySelectorAll<HTMLElement>(".list").forEach(observeElement);
			});
		});
	});

	mutationObserver.observe(document.body, { childList: true, subtree: true });

	const unsubscribeSettings = settings.subscribe(() => {
		observedElements.forEach((element) => {
			applyHeightLimit(element);
		});
	});

	return () => {
		unsubscribeSettings();
		mutationObserver.disconnect();
		resizeObservers.forEach((observer) => {
			observer.disconnect();
		});
		detailObservers.forEach((observer) => {
			observer.disconnect();
		});

		observedElements.forEach((element) => {
			element.style.height = "auto";

			delete element.dataset.observed;
		});
	};
};