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.