PageSourceSearch

https://mountaincabinsutah.com/wp-content/plugins/homerunner-toolk…/js/mobile-map-gestures.js?ver=3.309.18

js mountaincabinsutah.com collected 2026-10-10 02:02:20 UTC 5,543 bytes, 162 lines download raw bytes

1/**
2 * Map Gestures — frontend patcher.
3 *
4 * Forces gestureHandling:'greedy' on the HomeRunner explorer Google Map so
5 * one-finger pan and two-finger pinch-zoom act on the MAP, and the browser
6 * never steals the gesture to zoom the whole page. Once the map is greedy,
7 * Google Maps calls preventDefault on touch gestures inside the canvas, which
8 * is what actually stops the iOS page-zoom (touch-action CSS alone does not).
9 *
10 * Why a prototype-method hook and NOT a constructor wrap:
11 * the plugin constructs the explorer map before this (deferred) script runs,
12 * so wrapping google.maps.Map only ever catches future constructions — of
13 * which there are none. Instead we wrap google.maps.Map.prototype methods the
14 * plugin calls on the live instance and apply greedy on the first call.
15 *
16 * Why getDiv is in the hook list (and listed first):
17 * it is the ONLY map method the plugin calls during initialisation regardless
18 * of markers — `map.getDiv()` runs inside addMapControls right after the map
19 * is constructed. The framing methods (panTo / fitBounds / setZoom) only fire
20 * once there are markers to frame, which can be late, or never on a clustered
21 * or empty result set. Hooking getDiv applies greedy the instant the map
22 * exists, closing the first-paint window where the page could still pinch-zoom.
23 */
24(function () {
25	'use strict';
26
27	var MAX_ATTEMPTS = 200; // 20s at 100ms — covers slow Maps API loads.
28	var POLL_MS      = 100;
29	var HOOK_METHODS = [ 'getDiv', 'panTo', 'panBy', 'fitBounds', 'setZoom', 'setCenter', 'setOptions' ];
30
31	// The native getDiv, captured before wrapping, so isExplorerMap() never
32	// re-enters the wrapped getDiv (no recursion).
33	var nativeGetDiv = null;
34
35	var attempts = 0;
36	var tick = setInterval( function () {
37		attempts++;
38
39		var maps = window.google && window.google.maps;
40		if ( maps && maps.Map && maps.Map.prototype ) {
41			if ( ! maps.__hrtkGesturesHooked ) {
42				maps.__hrtkGesturesHooked = true;
43				try {
44					hookPrototype( maps );
45				} catch ( e ) {
46					// Leave native behaviour intact on any error.
47				}
48			}
49			clearInterval( tick );
50			return;
51		}
52
53		if ( attempts >= MAX_ATTEMPTS ) {
54			clearInterval( tick );
55		}
56	}, POLL_MS );
57
58	/**
59	 * Is this Map instance the explorer map? Identified by its container
60	 * having id="map" inside a .hfse ancestor — the same contract the plugin
61	 * uses to build it. Uses the native getDiv reference to avoid re-entering
62	 * the wrapped method.
63	 *
64	 * @param {object} map google.maps.Map instance.
65	 * @return {boolean}
66	 */
67	function isExplorerMap( map ) {
68		try {
69			var div = nativeGetDiv ? nativeGetDiv.call( map ) : ( map.getDiv && map.getDiv() );
70			return !! ( div && div.id === 'map' && div.closest && div.closest( '.hfse' ) );
71		} catch ( e ) {
72			return false;
73		}
74	}
75
76	/**
77	 * Flip the explorer map to greedy gesture handling, exactly once.
78	 *
79	 * The __hrtkGreedyApplied flag is set BEFORE the setOptions call so the
80	 * wrapped setOptions re-entering applyGreedy is a no-op — no recursion.
81	 *
82	 * @param {object} map google.maps.Map instance.
83	 */
84	function applyGreedy( map ) {
85		if ( ! map || map.__hrtkGreedyApplied ) {
86			return;
87		}
88		if ( ! isExplorerMap( map ) ) {
89			return;
90		}
91		map.__hrtkGreedyApplied = true;
92		try {
93			map.setOptions( { gestureHandling: 'greedy' } );
94		} catch ( e ) {
95			// no-op
96		}
97	}
98
99	/**
100	 * Wrap the chosen prototype methods so the first call for the explorer map
101	 * applies greedy handling. Each wrapper is marked so this module never
102	 * double-wraps the same method (other modules may also wrap, which simply
103	 * stacks — every concern still runs).
104	 *
105	 * @param {object} maps google.maps namespace.
106	 */
107	function hookPrototype( maps ) {
108		var proto = maps.Map.prototype;
109
110		// Capture the native getDiv before it is (possibly) wrapped below.
111		if ( typeof proto.getDiv === 'function' ) {
112			nativeGetDiv = proto.getDiv;
113		}
114
115		HOOK_METHODS.forEach( function ( name ) {
116			var orig = proto[ name ];
117			if ( typeof orig !== 'function' || orig.__hrtkGesturesWrapped ) {
118				return;
119			}
120
121			function wrapped() {
122				applyGreedy( this );
123				return orig.apply( this, arguments );
124			}
125			wrapped.__hrtkGesturesWrapped = true;
126
127			proto[ name ] = wrapped;
128		} );
129	}
130
131	/*
132	 * Selection guard (provider-agnostic, works for Leaflet and Google Maps).
133	 *
134	 * The map pane itself is user-select:none via this module's inline CSS,
135	 * but a drag that starts on the map and travels past its edge would
136	 * still paint text selection across the rest of the explorer — the
137	 * property cards next to a side-by-side map are the usual victim. While
138	 * a pointer that went down inside the map is held, the .hfse wrapper
139	 * carries hrtk-map-drag (unselectable via the same inline CSS); it is
140	 * removed the moment the pointer lifts, so card text stays copyable in
141	 * every other situation.
142	 */
143	document.addEventListener( 'pointerdown', function ( e ) {
144		var mapEl = e.target && e.target.closest && e.target.closest( '.hfse #map' );
145		if ( ! mapEl ) {
146			return;
147		}
148		var root = mapEl.closest( '.hfse' );
149		if ( ! root || root.classList.contains( 'hrtk-map-drag' ) ) {
150			return;
151		}
152		root.classList.add( 'hrtk-map-drag' );
153
154		function release() {
155			root.classList.remove( 'hrtk-map-drag' );
156			document.removeEventListener( 'pointerup', release, true );
157			document.removeEventListener( 'pointercancel', release, true );
158		}
159		document.addEventListener( 'pointerup', release, true );
160		document.addEventListener( 'pointercancel', release, true );
161	}, true );
162})();

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.