PageSourceSearch

https://www.bragghomeservices.com/common/usc/p/passive-show-hide.js

js bragghomeservices.com collected 2026-10-09 22:15:47 UTC 4,852 bytes, 161 lines download raw bytes

1if ( !window.USC ) { window.USC = {}; }
2require2( ['usc/p/usc-utils', 'usc/p/slide-toggle'], function () {
3
4	window.USC.showHide = function ( e ) {
5
6		var defaultOptions = {
7			// The class added is customizable.
8			className: 'show',
9			// Do you need a class added to the html element? It goes on the container by default.
10			htmlClass: false,
11			// Should the panel slide open and shut?
12			slider: false
13		}
14
15		// Define the elements
16		var el = e.target;
17		var type = e.type;
18		var box = el.closest( '[data-showhide]' );
19		var panel = box.querySelector( '[data-role="panel"]' );
20		var btns = Array.from( box.querySelectorAll( '[data-role="btn"]' ) );
21		var focusable = Array.from( panel.querySelectorAll( 'a, button, input, select, [tabindex="0"], video' ));
22		var lastFocus = focusable.pop();
23		var returnSpot = btns[0];
24		var videos = Array.from(panel.querySelectorAll( 'video' ));
25
26		if ( !lastFocus ) lastFocus = panel;
27
28		// Set the options
29		var data = USC.elementData( box );
30		el.options = Object.assign( {}, defaultOptions, data );
31
32		// Create the toggling functionality
33		function toggleActive( el, e ) {
34
35			// Check our active state and toggle some functionality
36			var active = ( !panel.getAttribute( 'aria-hidden' ) || panel.getAttribute( 'aria-hidden' ) === "true" ) ? false : true;
37
38			// If the slider option is turned on, trigger the slider functionality
39			if ( el.options.slider === true ) USC.slideToggle( panel, !active )
40
41			// Toggle our classes and attributes
42			box.classList.toggle( el.options.className );
43			if ( el.options.htmlClass ) document.documentElement.classList.toggle( el.options.className );
44			panel.setAttribute( 'aria-hidden', active );
45
46			// Set the state of the buttons
47			btns.forEach((btn) => {
48				btn.setAttribute('aria-expanded', !active);
49			});
50
51			// Set the state of videos and set our focus depending on if we're closing or opening a panel
52			if ( active ) {
53				// Loop through and pause our videos if we close a panel
54				videos.forEach( function ( vid ) {
55					try { vid.pause(); }
56					catch ( ex ) { ; }
57				} );
58
59				// Make focusable items non-focusable if closing
60                focusable.forEach((el) => {
61                    el.setAttribute('tabindex','-1');
62                });
63				panel.setAttribute('tabindex', '-1');
64
65				returnSpot.focus();
66			} else {
67				// Play our first video if we have one when we open a panel
68				if ( videos[0] && videos[0].readyState >= 1 ) {
69					initVideo( videos[0] ).then( video => {
70						try { video.play(); }
71						catch ( ex ) { ; }
72					} );
73				}
74				 
75				// Make focusable items focusable when opening 
76                focusable.forEach((el) => {
77                    el.setAttribute('tabindex','0');
78                });
79				panel.setAttribute('tabindex','0');
80				panel.focus();
81			}
82
83		}
84
85		// Before we run everything, validate to make sure our targets and types are correct
86		var run;
87
88		// if we click or pressed enter on a button
89		if ( e.keyCode === 13 && el.closest( '[data-role="btn"]' ) || type == 'click' && el.closest( '[data-role="btn"]' ) ) run = true;
90
91		// if we pressed escape on a showhide element
92		if ( e.keyCode == 27 && el.closest( '[data-showhide]' ) ) run = true;
93
94		// if we pressed tab
95		if ( e.keyCode === 9 ) {
96
97			// If shift was held to move back and we're on the panel, toggle the panel
98			if ( e.shiftKey && panel == el ) {
99				run = true;
100				e.preventDefault();
101				returnSpot.focus();
102			}
103			// If moving forward and we're currently on our last element, toggle the panel
104			else if ( !e.shiftKey && lastFocus == el ) {
105				run = true;
106				lastFocus = panel;
107			}
108
109		}
110
111		// Fire when ready
112		if ( run === true ) toggleActive( el, e );
113
114	};
115
116	function initVideo( video ) {
117		return new Promise( resolve => {
118			if ( !window._sa_videoStart || video.$videoEvents ) {
119				// Make sure we have scorpion analytics on the page, that the video hasn't already been wired up.
120				resolve( video );
121				return;
122			} else if ( USC.initAnalytics ) {
123				// If the video script has already been loaded, run it.
124				USC.initAnalytics( video );
125				resolve( video );
126				return;
127			}
128
129			// Load the video script.
130			require2( '/common/usc/p/video.js' );
131
132			// As soon as it's loaded we'll resolve the promiser.
133			let _interval = 0;
134			const _max_wait_time = 2000;
135			const _start = performance.now();
136			const fn = () => {
137				if ( USC.initAnalytics ) {
138					// It's loaded and ready.
139					clearInterval( _interval );
140					USC.initAnalytics( video );
141					resolve( video );
142					return;
143				}
144
145				let _now = performance.now();
146				if ( _now - _start > _max_wait_time ) {
147					// Can't wait any longer.
148					clearInterval( _interval );
149					resolve( video );
150					return;
151				}
152			};
153			_interval = setInterval( fn, 250 );
154		} );
155	}
156
157	if ( window.register ) {
158		window.register( 'usc/p/passive-show-hide' );
159	}
160
161} );

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.