PageSourceSearch

https://redaktion.steuergo.de/wp-content/plugins/eu-ai-label/assets/js/layout-guard.js?ver=0.8.0

js steuergo.de collected 2026-09-24 12:45:11 UTC 3,197 bytes, 120 lines download raw bytes

1/**
2 * EU AI Label — badge wrapper layout guard.
3 *
4 * Themes commonly render cards at a fixed aspect ratio: a container gets a
5 * `padding-top` ratio box and the image is absolutely positioned to fill it.
6 * Our badge wrapper then becomes that image's containing block while holding
7 * no in-flow content, so it collapses to zero size and the image — resolving
8 * `inset: 0` / `height: 100%` against nothing — disappears.
9 *
10 * Stretching the wrapper over the same box restores the original geometry: an
11 * absolutely positioned wrapper resolves against the exact ancestor the image
12 * used before, so the image keeps its dimensions and the badge still overlays
13 * it. badge.css hard-codes this for the layouts we know by name (Flatsome,
14 * Elementor); this guard catches every other theme that does the same thing.
15 */
16( function () {
17	'use strict';
18
19	var WRAP_SELECTOR = '.eu-ai-label-wrap';
20	var STRETCH_CLASS = 'eu-ai-label-wrap--stretch';
21
22	/**
23	 * Return the wrapped image, ignoring the badge and tooltip siblings.
24	 *
25	 * @param {Element} wrap Badge wrapper.
26	 * @return {Element|null} Image element.
27	 */
28	function wrappedImage( wrap ) {
29		for ( var child = wrap.firstElementChild; child; child = child.nextElementSibling ) {
30			if ( 'IMG' === child.tagName ) {
31				return child;
32			}
33		}
34
35		return null;
36	}
37
38	/**
39	 * Stretch a wrapper whose image the theme takes out of flow.
40	 *
41	 * @param {Element} wrap Badge wrapper.
42	 * @return {void}
43	 */
44	function guard( wrap ) {
45		if ( wrap.classList.contains( STRETCH_CLASS ) ) {
46			return;
47		}
48
49		var image = wrappedImage( wrap );
50		if ( ! image ) {
51			return;
52		}
53
54		var position = window.getComputedStyle( image ).position;
55		if ( 'absolute' === position || 'fixed' === position ) {
56			wrap.classList.add( STRETCH_CLASS );
57		}
58	}
59
60	/**
61	 * Check a subtree, including the root itself.
62	 *
63	 * @param {Node} root Element or document to scan.
64	 * @return {void}
65	 */
66	function scan( root ) {
67		if ( ! root || ! root.querySelectorAll ) {
68			return;
69		}
70
71		if ( root.matches && root.matches( WRAP_SELECTOR ) ) {
72			guard( root );
73		}
74
75		Array.prototype.forEach.call( root.querySelectorAll( WRAP_SELECTOR ), guard );
76	}
77
78	var scheduled = false;
79
80	/**
81	 * Coalesce repeated requests into a single pass before the next paint.
82	 *
83	 * @return {void}
84	 */
85	function scheduleScan() {
86		if ( scheduled ) {
87			return;
88		}
89
90		scheduled = true;
91		window.requestAnimationFrame( function () {
92			scheduled = false;
93			scan( document );
94		} );
95	}
96
97	function start() {
98		scan( document );
99
100		// Stylesheets loaded after the first pass, and lazy-loaded or
101		// Ajax-injected images (Loop Grids, product filters, infinite scroll),
102		// can both change the answer, so re-check when the DOM settles.
103		window.addEventListener( 'load', scheduleScan );
104
105		new MutationObserver( function ( mutations ) {
106			for ( var i = 0; i < mutations.length; i++ ) {
107				if ( mutations[ i ].addedNodes.length ) {
108					scheduleScan();
109					return;
110				}
111			}
112		} ).observe( document.documentElement, { childList: true, subtree: true } );
113	}
114
115	if ( 'loading' === document.readyState ) {
116		document.addEventListener( 'DOMContentLoaded', start );
117	} else {
118		start();
119	}
120}() );

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.