PageSourceSearch

https://www.wgi.org/wp-content/plugins/ubermenu/custom/custom.js?ver=1790805584

js wgi.org collected 2026-10-01 11:45:50 UTC 10,213 bytes, 216 lines download raw bytes

1
2// Guarded: this is top-level, so a missing wrapper here would throw and abort the
3// whole file - taking the menu behavior below down with it.
4const nav = document.getElementsByClassName('elementor-widget-ubermenu')[0]
5if (nav) nav.onclick = function (element) {
6  const target = element.target
7  if (target.className === 'elementor-widget-container') {
8    const header = document.getElementsByClassName('nav-opened')[0]
9    nav.classList.remove('is-toggled')
10    header.classList.remove('nav-opened')
11  }
12}
13
14jQuery(function($) {
15
16	// Below the responsive breakpoint, require an explicit click to open a submenu
17	// instead of hover. Hovering with a mouse in a narrow/resized browser window is what
18	// caused the whole hover-intent-sensitivity saga below in the first place, and it's
19	// not how anyone actually interacts with a mobile layout anyway. Touch devices
20	// already use a deliberate tap (handleTap), which is untouched - this only changes
21	// mouse behavior at narrow widths. Real desktop-width hover_intent is unaffected.
22	//
23	// This rides on ubermenu's own per-item trigger override rather than patching
24	// handleMouseIntent: the plugin's hover bindings are delegated with
25	// ':not([data-ubermenu-trigger])' in the selector, and delegated selectors are
26	// matched at dispatch time rather than bind time - so setting that attribute at
27	// runtime stops hover firing on the item immediately, no monkey-patching needed.
28	//
29	// Deliberately placed above the prototype patching below, which bails early when it
30	// can't reach a live instance. Click enforcement must not be gated on that.
31	var OURS = 'custom-mobile-click';	// marks only the attributes we added ourselves
32
33	function syncTriggers() {
34		$( '.ubermenu' ).each( function() {
35			var $u = $( this );
36			var inst = $u.data( 'plugin_ubermenu' );
37			if ( !inst ) return;
38
39			// isMobile() reads each instance's own configured breakpoint - never hardcode it
40			var mobile = inst.isMobile();
41
42			$u.find( '.ubermenu-item.ubermenu-has-submenu-drop' ).each( function() {
43				var $li = $( this );
44				if ( mobile ) {
45					if ( $li.data( OURS ) !== undefined ) return;	// already ours
46					// Override author-set triggers too (level-0 items ship with
47					// data-ubermenu-trigger="hover_intent" from wp-admin), but stash
48					// whatever was there so desktop gets it back verbatim. Storing null
49					// for "there was no attribute" keeps that case distinguishable.
50					var existing = $li.attr( 'data-ubermenu-trigger' );
51					$li.data( OURS, existing === undefined ? null : existing );
52					$li.attr( 'data-ubermenu-trigger', 'click' );
53				}
54				else if ( $li.data( OURS ) !== undefined ) {
55					var prev = $li.data( OURS );
56					if ( prev === null ) $li.removeAttr( 'data-ubermenu-trigger' );
57					else $li.attr( 'data-ubermenu-trigger', prev );
58					$li.removeData( OURS );
59				}
60			});
61		});
62	}
63
64	// handleMouseClick already implements exactly the toggle behavior we want here (open
65	// on first click; on a second click, follow the link if there is one and close).
66	// Ubermenu only binds its own click handler to items that carried
67	// data-ubermenu-trigger at init time, so the ones we mark later need this. Delegated
68	// from document so it survives the menu being re-rendered.
69	$( document ).on( 'click.ubermenu-mobile-click-toggle', '.ubermenu-item.ubermenu-has-submenu-drop[data-ubermenu-trigger="click"] > .ubermenu-target', function( e ) {
70		var $li = $( this ).parent();
71		var stashed = $li.data( OURS );
72
73		// Not one of ours - we're above the breakpoint, or syncTriggers hasn't reached
74		// this item. Must be an undefined check, not truthiness: null is a meaningful
75		// stashed value meaning "this item had no trigger attribute of its own".
76		if ( stashed === undefined ) return;
77
78		var inst = $( this ).closest( '.ubermenu' ).data( 'plugin_ubermenu' );
79		if ( !inst ) return;
80
81		// If the item's own configured trigger was already 'click', ubermenu bound a
82		// click handler directly to it at init (the divergents loop) and driving it from
83		// here as well would toggle twice - open then straight back closed. Items
84		// configured for hover/hover_intent never got a click handler, so those are ours
85		// to drive. With trigger overrides disabled that loop doesn't run at all, so
86		// nothing was bound and we handle them either way.
87		if ( stashed === 'click' && inst.allow_trigger_overrides ) return;
88
89		// Pointer-enabled devices already get open/close via handleTap (bound to
90		// pointerup) with preventDefault suppressing the synthetic click that would
91		// follow - skip here too, matching the plugin's own suppress_clicks convention,
92		// so a tap doesn't toggle twice.
93		if ( inst.suppress_clicks ) return;
94		inst.handleMouseClick( e, this, inst );
95	});
96
97	var resizeTimer;
98	$( window ).on( 'resize.ubermenu-mobile-click-toggle', function() {
99		clearTimeout( resizeTimer );
100		resizeTimer = setTimeout( syncTriggers, 150 );
101	});
102
103	// Once now, and again at load in case ubermenu initializes after DOM ready.
104	syncTriggers();
105	$( window ).on( 'load.ubermenu-mobile-click-toggle', syncTriggers );
106
107	// Ubermenu's Plugin constructor/prototype are closed over inside ubermenu.js's
108	// own IIFE - not exposed globally - so they can't be monkey-patched the normal
109	// way (there's no jQuery.fn.ubermenu.Constructor). The only external hook is the
110	// live instance jQuery stores per-element via $.data(el, 'plugin_ubermenu').
111	// Object.getPrototypeOf() on that instance gets the real shared prototype
112	// object regardless (ubermenu.js reassigns Plugin.prototype = {...} as a whole
113	// object literal, which drops the default `constructor` back-reference, so
114	// `instance.constructor` can't be trusted - getPrototypeOf() doesn't care).
115	//
116	// Ubermenu constructs its instances inside its OWN jQuery ready callback, and
117	// ubermenu-custom is enqueued depending only on 'jquery' - so whether an instance
118	// exists by the time this runs comes down to script order, which nothing
119	// enforces. This used to `return` when it didn't, silently disabling every patch
120	// below with no console error to show for it. Wait for it instead. The mu-plugin
121	// ubermenu-custom-js-deps.php makes the ordering deterministic; this is the
122	// belt-and-braces half.
123	function withInstance( cb ) {
124		var tries = 0;
125		(function poll() {
126			var $menu = $( '.ubermenu' ).first();
127			var instance = $menu.length ? $menu.data( 'plugin_ubermenu' ) : null;
128			if ( instance ) return cb( instance );
129			if ( ++tries > 40 ) return;	// ~4s, then give up rather than poll forever
130			setTimeout( poll, 100 );
131		})();
132	}
133
134	withInstance( function( instance ) {
135
136		var proto = Object.getPrototypeOf( instance );
137
138		// The menu is definitely initialized now, so re-sync the triggers set up
139		// above - the first syncTriggers() call may have run before there was an
140		// instance to read isMobile() from.
141		syncTriggers();
142
143		// Items carrying their own data-ubermenu-trigger get their hover handler bound
144		// DIRECTLY to the element in ubermenu's divergents loop - not delegated, and
145		// with no ':not([data-ubermenu-trigger])' filter to fall foul of. Rewriting the
146		// attribute above therefore can't suppress those, and every level-0 item here
147		// ships with trigger="hover_intent" set in wp-admin. So hover still has to be
148		// gated at the prototype. handleMouseover covers the same case for items whose
149		// configured trigger is plain 'hover' rather than 'hover_intent'.
150		var origHandleMouseIntent = proto.handleMouseIntent;
151		proto.handleMouseIntent = function( e, item, plugin ) {
152			if ( plugin.isMobile() ) return;
153			return origHandleMouseIntent.apply( this, arguments );
154		};
155
156		var origHandleMouseover = proto.handleMouseover;
157		proto.handleMouseover = function( e, target, plugin ) {
158			if ( plugin.isMobile() ) return;
159			return origHandleMouseover.apply( this, arguments );
160		};
161
162		// How long the mouse must rest on an item before a hover-triggered submenu
163		// switch is confirmed. Ubermenu's own intent_threshold/intent_interval (set in
164		// wp-admin: Hover Intent Settings) only gate how STILL the mouse must be
165		// between polls, not how LONG it must stay put - a mouse that's naturally
166		// resting (normal hand tremor) passes even a strict threshold on the very
167		// first poll, so switching still felt near-instant without this.
168		var CUSTOM_INTENT_MIN_DWELL = 400; // ms
169
170		var origHandleMouseIntentSuccess = proto.handleMouseIntentSuccess;
171		proto.handleMouseIntentSuccess = function( e, $item, plugin ) {
172			var self = this;
173			var args = arguments;
174
175			function attemptOpen() {
176				// Also hold off while another submenu is mid-transition - opening now
177				// would force triggerSubmenu to cut that transition short (see its
178				// closeSubmenuInstantly on ".ubermenu-active, .ubermenu-in-transition"
179				// siblings), which is what makes submenus feel like they're rapidly
180				// flipping between each other.
181				if ( plugin.$ubermenu.find( '.ubermenu-in-transition' ).length ) {
182					setTimeout( attemptOpen, plugin.settings.intent_interval );
183					return;
184				}
185				origHandleMouseIntentSuccess.apply( self, args );
186			}
187
188			setTimeout( function() {
189				// If the mouse already left before our minimum dwell elapsed, ubermenu's
190				// own mouseleave.mouse_intent_none handler will have reset this back to
191				// 0 already - don't open in that case.
192				if ( $item.data( 'mouse_intent_state' ) !== 1 ) return;
193				attemptOpen();
194			}, CUSTOM_INTENT_MIN_DWELL );
195		};
196
197		// Touch taps have no gating at all otherwise (unlike mouse hover, which goes
198		// through compare()'s intent_threshold/interval) - a rapid run of taps would
199		// immediately cut short whatever panel is still animating in/out.
200		var origHandleTap = proto.handleTap;
201		proto.handleTap = function( e, target, plugin ) {
202			if ( plugin.$ubermenu.find( '.ubermenu-in-transition' ).length ) {
203				e.preventDefault();
204				e.stopPropagation();
205				plugin.log( 'Ignoring tap during active transition (custom.js)' );
206				var $target = $( target );
207				$target.data( 'ubermenu-killTouch', false );
208				plugin.resetHandlers( $target, 'handleTap-transition-hold', plugin );
209				return;
210			}
211			return origHandleTap.apply( this, arguments );
212		};
213
214	});
215
216});

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.