@@ -276,94 +276,71 @@ module Scroll = {
276276 }
277277}
278278
279- // Helper to safely get iframe contentWindow - returns None for cross-origin iframes
280- // Cross-origin iframes throw SecurityError when accessing contentWindow properties
281- let getIframeWindowSafe : WebAPI .DOMAPI .element => option <WebAPI .DOMAPI .window > = %raw (`
282- function (iframe ) {
283- try {
284- var win = iframe .contentWindow ;
285- // Verify we have access by reading location (throws if cross-origin)
286- if (win && win .location && win .location .href ) {
287- return win;
288- }
289- return undefined ;
290- } catch (e) {
291- // Expected for cross-origin iframes - log for debugging
292- console .debug (' [useIFrameLocation] Cross-origin iframe access denied:' , e .message );
293- return undefined ;
279+ module NavigateEvent = {
280+ type destination
281+ type t
282+
283+ @get external destination : t => destination = "destination"
284+ @get external url : destination => string = "url"
285+ }
286+
287+ let getIframeWindowSafe = (iframe : WebAPI .DOMAPI .element ): option <WebAPI .DOMAPI .window > => {
288+ let iframeElement = iframe -> Obj .magic
289+ try {
290+ switch WebAPI .HTMLIFrameElement .contentWindow (iframeElement )-> Null .toOption {
291+ | None => None
292+ | Some (iframeWindow ) =>
293+ ignore (iframeWindow -> WebAPI .Window .location -> WebAPI .Location .href )
294+ Some (iframeWindow )
294295 }
296+ } catch {
297+ | _ => None
295298 }
296- ` )
299+ }
297300
298- let useIFrameLocation = (~iframeRef : Nullable . t <WebAPI .DOMAPI .element >) => {
301+ let useIFrameLocation = (~iframeElement : option <WebAPI .DOMAPI .element >, ~ attachmentKey : int ) => {
299302 let (location , setLocation ) = React .useState (() => None )
300303
301304 React .useEffect (() => {
302- let iframeWindow =
303- iframeRef
304- -> Nullable .toOption
305- -> Option .flatMap (iframe => getIframeWindowSafe (iframe ))
306-
307- switch iframeWindow {
308- | Some (iframeWindow ) =>
309- // Get initial location (safe since getIframeWindowSafe verified access)
310- let initialLocation = Some (iframeWindow -> WebAPI .Window .location -> WebAPI .Location .href )
311- setLocation (_ => initialLocation )
312-
313- // Listen for navigation events
314- let onPopState = _ev => {
315- let currentLocation = Some (iframeWindow -> WebAPI .Window .location -> WebAPI .Location .href )
316- setLocation (_ => currentLocation )
317- }
318- let onNavigation = ev => {
319- let url = ev ["destination" ]["url" ]
320- let currentLocation = Some (url )
321- setLocation (_ => currentLocation )
322- }
323-
324- // Check if Navigation API is supported (not available in Firefox/Safari)
325- let navigationSupported = %raw (` typeof iframeWindow .navigation !== ' undefined' ` )
326-
327- WebAPI .Window .addEventListener (
328- iframeWindow ,
329- Custom ("popstate" ),
330- onPopState ,
331- ~options = {capture : false },
332- )
305+ switch iframeElement {
306+ | None =>
307+ setLocation (_ => None )
308+ None
309+ | Some (iframe ) =>
310+ switch getIframeWindowSafe (iframe ) {
311+ | None =>
312+ setLocation (_ => None )
313+ None
314+ | Some (iframeWindow ) =>
315+ let initialLocation = Some (iframeWindow -> WebAPI .Window .location -> WebAPI .Location .href )
316+ setLocation (_ => initialLocation )
317+
318+ let onNavigation = (ev : WebAPI .EventAPI .event ) => {
319+ let navigateEvent : NavigateEvent .t = ev -> Obj .magic
320+ let destinationUrl = navigateEvent -> NavigateEvent .destination -> NavigateEvent .url
321+ setLocation (_ => Some (destinationUrl ))
322+ }
333323
334- // Only use Navigation API if supported
335- if navigationSupported {
336324 WebAPI .Navigation .addEventListener (
337325 iframeWindow .navigation ,
338326 Custom ("navigate" ),
339327 onNavigation ,
340328 ~options = {capture : false },
341329 )
342- }
343-
344- Some (
345- () => {
346- WebAPI .Window .removeEventListener (
347- iframeWindow ,
348- Custom ("popstate" ),
349- onPopState ,
350- ~options = {capture : false },
351- )
352330
353- // Only remove Navigation API listener if it was added
354- if navigationSupported {
331+ Some (
332+ () => {
355333 WebAPI .Navigation .removeEventListener (
356334 iframeWindow .navigation ,
357335 Custom ("navigate" ),
358336 onNavigation ,
359337 ~options = {capture : false },
360338 )
361- }
362- },
363- )
364- | None => None
339+ },
340+ )
341+ }
365342 }
366- }, (iframeRef , setLocation ))
343+ }, (iframeElement , attachmentKey ))
367344
368345 location
369346}
0 commit comments