PageSourceSearch

https://www.blueline.ca/wp-content/themes/kadence-pubx/js/pubx-interscroll.js?ver=1788103836

js blueline.ca collected 2026-10-02 21:13:15 UTC 5,714 bytes, 215 lines download raw bytes

1/**
2 * Shows #InterAdspot while .pubx-interscroll is in view (parallax interscroller layer).
3 */
4(function () {
5	'use strict';
6
7	function clamp(n, min, max) {
8		return Math.min(Math.max(n, min), max);
9	}
10
11	function setStickyOffsetVar() {
12		var root = document.documentElement;
13		if (!root) {
14			return;
15		}
16
17		// The visible header is a `.website-header` rendered by a Kadence
18		// Element, wrapped in `.kadence-element-wrap` (which is the actual
19		// sticky element). Desktop and mobile versions both render to the
20		// DOM; Kadence hides one per breakpoint via CSS, so we pick the one
21		// that's currently laid out (non-zero height).
22		var height = 0;
23		var headers = document.querySelectorAll('#wrapper > .kadence-element-wrap');
24		for (var i = 0; i < headers.length; i++) {
25			if (!headers[i].querySelector(':scope > .website-header')) {
26				continue;
27			}
28			var h = headers[i].offsetHeight || 0;
29			if (h > height) {
30				height = h;
31			}
32		}
33		if (!height) {
34			// Fallback: measure the inner `.website-header` directly.
35			var fallback = document.querySelector('.website-header');
36			if (fallback) {
37				height = fallback.offsetHeight || 0;
38			}
39		}
40
41		root.style.setProperty('--pubx-interscroll-sticky-offset', height + 'px');
42	}
43
44	function getTopOffsetPx() {
45		var root = document.documentElement;
46		if (!root) {
47			return 0;
48		}
49		var value = window.getComputedStyle(root).getPropertyValue('--pubx-interscroll-top');
50		var px = parseFloat(value);
51		return isFinite(px) ? px : 0;
52	}
53
54	function getCreativeEl(spot) {
55		// Prefer the GPT iframe if present.
56		var iframe = spot.querySelector('iframe');
57		if (iframe) {
58			return iframe;
59		}
60		// Fallback to slot wrapper.
61		var slot = spot.querySelector('.pubx-gpt-slot');
62		return slot || spot;
63	}
64
65	function getParallaxEl(spot) {
66		var slot = spot.querySelector('.pubx-gpt-slot');
67		if (slot) {
68			return slot;
69		}
70		return getCreativeEl(spot);
71	}
72
73	function measureCreativeHeight(el) {
74		if (!el) {
75			return 0;
76		}
77		// Prefer rendered dimensions (after CSS/layout), then fall back.
78		var rectH = el.getBoundingClientRect ? el.getBoundingClientRect().height : 0;
79		if (rectH && isFinite(rectH)) {
80			return rectH;
81		}
82		var attrH = el.getAttribute && el.getAttribute('height');
83		var h = attrH ? parseFloat(attrH) : 0;
84		if (h && isFinite(h)) {
85			return h;
86		}
87		return el.scrollHeight || el.offsetHeight || 0;
88	}
89
90	function init() {
91		setStickyOffsetVar();
92
93		var section = document.querySelector('.pubx-interscroll.showad2');
94		var spot = document.getElementById('InterAdspot');
95		if (!section || !spot) {
96			return;
97		}
98
99		if (section.classList.contains('pubx-interscroll--empty')) {
100			spot.style.display = 'none';
101			return;
102		}
103
104		var rafId = null;
105		var isActive = false;
106
107		function resetCreativeTransform() {
108			var parallaxEl = getParallaxEl(spot);
109			if (parallaxEl && parallaxEl.style) {
110				parallaxEl.style.transform = '';
111				parallaxEl.style.willChange = '';
112			}
113		}
114
115		function updateParallax() {
116			rafId = null;
117
118			if (!isActive) {
119				spot.style.display = 'none';
120				spot.style.left = '';
121				spot.style.width = '';
122				resetCreativeTransform();
123				return;
124			}
125
126			// Tunnel-driven behavior: once section is in view, keep the interscroller visible.
127			spot.style.display = 'flex';
128
129			var topOffset = getTopOffsetPx();
130			var rect = section.getBoundingClientRect();
131			var sectionWidth = Math.max(0, Math.round(rect.width || 0));
132			var sectionLeft = Math.round(rect.left || 0);
133
134			// Keep fixed interscroller window constrained to the in-flow rail.
135			spot.style.left = sectionLeft + 'px';
136			spot.style.width = sectionWidth + 'px';
137
138			var creativeMeasureEl = getCreativeEl(spot);
139			var parallaxEl = getParallaxEl(spot);
140			if (!creativeMeasureEl || !parallaxEl) {
141				return;
142			}
143
144			var creativeHeight = measureCreativeHeight(creativeMeasureEl);
145			if (!creativeHeight) {
146				return;
147			}
148
149			var visibleHeight = spot.getBoundingClientRect().height || 0;
150			var scrollable = Math.max(0, creativeHeight - visibleHeight);
151			if (!scrollable) {
152				parallaxEl.style.willChange = 'transform';
153				parallaxEl.style.transform = 'translate3d(0,0,0)';
154				return;
155			}
156
157			var sectionHeight = rect.height || 0;
158			var denom = Math.max(1, sectionHeight - visibleHeight);
159
160			// Progress: 0 when section top aligns with fixed window top; 1 when section bottom reaches window bottom.
161			var progress = clamp((-rect.top + topOffset) / denom, 0, 1);
162			var translateY = -Math.round(progress * scrollable);
163
164			parallaxEl.style.willChange = 'transform';
165			parallaxEl.style.transform = 'translate3d(0,' + translateY + 'px,0)';
166		}
167
168		function requestUpdate() {
169			if (rafId) {
170				return;
171			}
172			rafId = window.requestAnimationFrame(updateParallax);
173		}
174
175		var observer = new IntersectionObserver(
176			function (entries) {
177				entries.forEach(function (entry) {
178					if (section.classList.contains('pubx-interscroll--empty')) {
179						spot.style.display = 'none';
180						return;
181					}
182					isActive = !!entry.isIntersecting;
183					if (isActive) {
184						requestUpdate();
185					} else {
186						spot.style.display = 'none';
187						spot.style.left = '';
188						spot.style.width = '';
189						resetCreativeTransform();
190					}
191				});
192			},
193			{ root: null, rootMargin: '0px', threshold: 0.01 }
194		);
195
196		observer.observe(section);
197
198		// Drive the "reveal the bottom portion" behavior while scrolling the tunnel.
199		window.addEventListener('scroll', requestUpdate, { passive: true });
200		window.addEventListener(
201			'resize',
202			function () {
203				setStickyOffsetVar();
204				requestUpdate();
205			},
206			{ passive: true }
207		);
208	}
209
210	if (document.readyState === 'loading') {
211		document.addEventListener('DOMContentLoaded', init);
212	} else {
213		init();
214	}
215})();

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.