PageSourceSearch

https://caneveryoneuse.com/wp-content/plugins/greyd-plugin/src/fea…/blocks/navigation/frontend.js?ver=2.20.2

js caneveryoneuse.com collected 2026-10-03 20:29:42 UTC 6,641 bytes, 213 lines download raw bytes

1/**
2 * Navigation Extension frontend features:
3 * anchor-active-style.
4 * 
5 * @since 1.13.0
6 * @see greyd.scrollObserver for details on the mechanic.
7 */
8
9document.addEventListener( "DOMContentLoaded", function() {
10
11	if ( !greyd?.scrollObserver ) return;
12
13	function initNavigations() {
14
15		// get navigation blocks with anchor-active-style
16		var navBlocks = document.querySelectorAll('.wp-block-navigation.is-anchor-active-style');
17		if ( navBlocks.length == 0 ) return;
18
19		navBlocks.forEach( ( wrapper, key ) => {
20
21			const setup = wrapper.dataset.anchoractive ? JSON.parse(wrapper.dataset.anchoractive) : {};
22			if ( !setup.enable) return;
23
24			const activeLinks = wrapper.querySelectorAll('a.wp-block-navigation-item__content[href*="#"]');
25			if ( activeLinks.length == 0 ) return;
26
27			// setup
28			let start = setup.start ? parseInt(setup.start) : 0;
29			let end = setup.end ? parseInt(setup.end) : 100;
30			if ( end < start ) {
31				let tmp = start;
32				start = end;
33				end = tmp;
34			}
35			const multiple = setup.multiple ? setup.multiple : '';
36			const none = setup.none ? setup.none : '';
37	
38			let items = [];
39			activeLinks.forEach( ( link, key ) => {
40				const item = link.parentElement;
41				// get items href, anchor-id and anchor-element
42				const href = link.href;
43				const id = href.split('#')[1];
44				const anchor = document.getElementById(id);
45				if ( anchor ) {
46					// console.log(item);
47					// console.log(href);
48					items.push( { item: item, anchor: anchor } );
49
50					var simple = start == 0 && end == 100 && multiple == '' && none == '';
51					if ( simple ) {
52						// simple observer (default setup)
53						greyd.scrollObserver.observeElement(
54							anchor,
55							( target, event, inViewport ) => {
56								// toggle active class
57								if ( inViewport ) {
58									item.classList.add('current-menu-item');
59								}
60								else {
61									item.classList.remove('current-menu-item');
62								}
63							},
64							'change'
65						);
66					}
67					else {
68						// advanced observer
69						greyd.scrollObserver.observeElement(
70							anchor,
71							( target, event, inViewport ) => {
72
73								// get offsets
74								var boundingClientRect = target.getBoundingClientRect();
75								var targetTop          = boundingClientRect.y;
76								var targetBottom       = targetTop + boundingClientRect.height;
77								var endLine            = (window.innerHeight / 100) * end;
78								var startLine          = (window.innerHeight / 100) * start;
79
80								// get distance to center function
81								const getDistance = ( element ) => {
82									// get offsets
83									var bounds = element.getBoundingClientRect();
84									var top    = bounds.y;
85									var bottom = top + bounds.height;
86									var center = (endLine + startLine) / 2;
87									// var center = window.innerHeight / 2;
88									// calculate distance
89									var distance = 0;
90									if ( bottom < center && top < center ) {
91										// above center
92										distance = center - bottom;
93									}
94									if ( bottom > center && top > center ) {
95										// below center
96										distance = top - center;
97									}
98									return distance;
99								};
100
101								// check if target is between start and end
102								var inside = targetBottom > startLine && targetTop < endLine;
103								
104								// multiple: show closest to center
105								if ( inside && multiple == 'closest' ) {
106
107									// calculate this distance to center
108									var distance = getDistance(target);
109									// check if other item is active
110									items.forEach( (other) => {
111										// escape this and non active items
112										if ( other.item === item || !other.item.classList.contains('current-menu-item') ) return;
113										// calculate other distance
114										if ( getDistance(other.anchor) < distance ) {
115											// don't show this if other item is closer to center
116											inside = false;
117										}
118									} );
119
120								}
121
122								// multiple: show only latest
123								if ( inside && !item.classList.contains('current-menu-item') && multiple == 'latest' ) {
124
125									// deactivate other elements
126									items.forEach( (other) => {
127										// escape this and non active items
128										if ( other.item === item || !other.item.classList.contains('current-menu-item') ) return;
129										other.item.classList.remove('current-menu-item');
130									} );
131
132								}
133								
134								// toggle active class
135								if ( inside ) {
136									item.classList.add('current-menu-item');
137								}
138								else {
139									item.wasActive = item.classList.contains('current-menu-item');
140									if ( item.wasActive ) items.forEach( (other) => {
141										// escape this
142										if ( other.item === item ) return;
143										other.item.wasActive = false;
144									} );
145
146									item.classList.remove('current-menu-item');
147								}
148
149								// no active
150								if ( none != '' ) {
151
152									// check if any item is active
153									var anyActive = false;
154									var distances = [];
155									items.forEach( (other, index) => {
156										// remove keeper class
157										if ( other.item.classList.contains('keep-anchor-active') ) {
158											other.item.classList.remove('current-menu-item', 'keep-anchor-active');
159										}
160										// check if item is active
161										if ( other.item.classList.contains('current-menu-item') ) {
162											anyActive = true;
163										}
164										else {
165											// get distance to center for closest/fallback
166											distances.push( { index: index, distance: getDistance(other.anchor) } );
167										}
168									} );
169									if ( !anyActive ) {
170
171										// keep active until next element enters
172										if ( none == 'keep' ) {
173											items.forEach( (other, index) => {
174												// check if item was active
175												if ( other.item.wasActive ) {
176													other.item.classList.add('current-menu-item', 'keep-anchor-active');
177													anyActive = true;
178												}
179											} );
180										}
181
182										// activate closest element
183										// fallback / none == 'closest'
184										if ( !anyActive ) {
185											// sort by distance to center
186											distances.sort((a, b) => a.distance - b.distance);
187											// add keeper class if no other item is active
188											items[distances[0].index].item.classList.add('current-menu-item', 'keep-anchor-active');
189										}
190										
191									}
192
193								}
194
195							},
196							'always'
197						);
198
199						// remove active class initially
200						// (observeElement 'always' does not trigger on inViewport false)
201						item.classList.remove('current-menu-item');
202					}
203				}
204			} );
205
206		} );
207
208		console.log("navigation scripts loaded.");
209	}
210
211	initNavigations();
212
213} );

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.