PageSourceSearch

https://www.ohne-makler.at/static/dialog/dialog-main/js/dialog.a3ab654b43b1.js

js ohne-makler.at collected 2026-10-09 17:15:38 UTC 3,292 bytes, 119 lines download raw bytes

1// Custom Web Component Dialog Element
2// from: https://github.com/argyleink/gui-challenges/blob/main/dialog/dialog.js
3
4// custom events to be added to <dialog>
5// Events must be created per dispatch: htmx marks handled event objects
6// (htmx-internal-data.handledFor), so a reused singleton would only ever
7// trigger an hx-trigger listener once.
8const dialogClosingEvent = () => new Event('closing')
9const dialogClosedEvent  = () => new Event('closed')
10const dialogOpeningEvent = () => new Event('opening')
11const dialogOpenedEvent  = () => new Event('opened')
12const dialogRemovedEvent = () => new Event('removed')
13
14// Track all dialogs on the page
15const dialogs = {};
16
17// track opening
18const dialogAttrObserver = new MutationObserver((mutations, _observer) => {
19	mutations.forEach(async mutation => {
20		if (mutation.attributeName === 'open') {
21			const dialog = mutation.target
22
23			const isOpen = dialog.hasAttribute('open')
24			if (!isOpen) return
25
26			dialog.removeAttribute('inert')
27			document.body.style.overflow = 'hidden';
28
29			// set focus
30			const focusTarget = dialog.querySelector('[autofocus]')
31			focusTarget
32				? focusTarget.focus()
33				: dialog.querySelector('button').focus()
34
35			dialog.dispatchEvent(dialogOpeningEvent())
36			await animationsComplete(dialog)
37			dialog.dispatchEvent(dialogOpenedEvent())
38		}
39	})
40})
41
42// track deletion
43const dialogDeleteObserver = new MutationObserver((mutations, _observer) => {
44	mutations.forEach(mutation => {
45		mutation.removedNodes.forEach(removedNode => {
46			if (removedNode.nodeName === 'DIALOG') {
47				removedNode.removeEventListener('click', lightDismiss)
48				removedNode.removeEventListener('close', dialogClose)
49				removedNode.dispatchEvent(dialogRemovedEvent())
50			}
51		})
52	})
53})
54
55// wait for all dialog animations to complete their promises
56const animationsComplete = element => {
57	// Return early if getAnimations doesn't exist, as to not error
58	if (typeof element.getAnimations !== "function") {
59		return;
60	}
61
62	return Promise.allSettled(
63		element.getAnimations().map(animation =>
64			animation.finished))
65}
66
67// Open Dialog by Dialog ID or Target Element
68window.dialogOpen = (dialogIdOrElement) => {
69	const dialog = typeof dialogIdOrElement === 'string'
70		? dialogs[dialogIdOrElement]
71		: dialogIdOrElement;
72
73	dialog.showModal();
74
75	return dialog;
76};
77
78
79// click outside the dialog handler
80const lightDismiss = ({target:dialog}) => {
81	if (dialog.nodeName === 'DIALOG')
82		dialog.close('dismiss')
83}
84
85// Extend dialog.close() to add custom events
86const dialogClose = async ({target:dialog}) => {
87	document.body.style.overflow = 'auto';
88	dialog.setAttribute('inert', '')
89	dialog.dispatchEvent(dialogClosingEvent())
90
91	await animationsComplete(dialog)
92
93	dialog.dispatchEvent(dialogClosedEvent())
94}
95
96// page load dialogs setup
97async function SetupDialog(dialog) {
98	dialog.addEventListener('click', lightDismiss)
99	dialog.addEventListener('close', dialogClose)
100
101	dialogs[dialog.id] = dialog;
102
103	dialogAttrObserver.observe(dialog, {
104		attributes: true,
105	})
106
107	dialogDeleteObserver.observe(document.body, {
108		attributes: false,
109		subtree: false,
110		childList: true,
111	})
112
113	// remove loading attribute
114	// prevent page load @keyframes playing
115	await animationsComplete(dialog)
116	dialog.removeAttribute('loading')
117}
118
119window.SetupDialog = SetupDialog

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.