1( function () { 2 'use strict'; 3 4 const selector = '[data-riess-ai-interactive]'; 5 let keyboardNavigation = false; 6 let hydrationScheduled = false; 7 let overlayUpdateScheduled = false; 8 let sizeUpdateScheduled = false; 9 const overlayHosts = new Set(); 10 const overlayResizeObserver = typeof ResizeObserver === 'function' ? new ResizeObserver( scheduleOverlayUpdate ) : null; 11 const observedSizeReferences = new WeakSet(); 12 const sizeResizeObserver = typeof ResizeObserver === 'function' ? new ResizeObserver( function () { 13 updateDisclosureSizes( document ); 14 } ) : null; 15 16 function updateOverlayHost( host ) { 17 const reference = host.riessAiReference; 18 if ( ! reference || ! reference.isConnected ) { 19 overlayHosts.delete( host ); 20 host.remove(); 21 return; 22 } 23 24 const referenceRect = reference.getBoundingClientRect(); 25 host.style.left = referenceRect.left + 'px'; 26 host.style.top = referenceRect.top + 'px'; 27 host.style.width = referenceRect.width + 'px'; 28 host.style.height = referenceRect.height + 'px'; 29 } 30 31 function updateOverlayHosts() {
32 overlayHosts.forEach( updateOverlayHost ); 33 } 34 35 function scheduleOverlayUpdate() { 36 if ( overlayUpdateScheduled ) { 37 return; 38 } 39 overlayUpdateScheduled = true; 40 window.requestAnimationFrame( function () { 41 overlayUpdateScheduled = false; 42 updateOverlayHosts(); 43 } ); 44 } 45 46 function sizeReferenceFor( disclosure ) { 47 const overlayHost = disclosure.closest( '.riess-ai-overlay-host' ); 48 if ( overlayHost && overlayHost.riessAiSizeReference ) { 49 return overlayHost.riessAiSizeReference; 50 } 51 52 const media = disclosure.closest( '.riess-ai-media, .riess-ai-manual-disclosure' ); 53 return media ? media.querySelector( 'img' ) : null; 54 } 55 56 function updateDisclosureSize( disclosure ) { 57 const reference = sizeReferenceFor( disclosure ); 58 if ( ! reference || ! reference.isConnected ) { 59 return; 60 } 61 62 if ( sizeResizeObserver && ! observedSizeReferences.has( reference ) ) { 63 observedSizeReferences.add( reference ); 64 sizeResizeObserver.observe( reference ); 65 } 66 67 const rect = reference.getBoundingClientRect(); 68 const minWidth = Math.max( 0, Number.parseInt( disclosure.dataset.riessAiMinWidth || '0', 10 ) || 0 ); 69 const minHeight = Math.max( 0, Number.parseInt( disclosure.dataset.riessAiMinHeight || '0', 10 ) || 0 ); 70 const eligible = ( minWidth === 0 || rect.width >= minWidth ) && ( minHeight === 0 || rect.height >= minHeight ); 71 const changed = disclosure.classList.contains( 'riess-ai-size-hidden' ) === eligible; 72 73 disclosure.classList.toggle( 'riess-ai-size-hidden', ! eligible ); 74 75 const overlayHost = disclosure.closest( '.riess-ai-overlay-host' ); 76 const captionSpacer = overlayHost && overlayHost.riessAiReference && overlayHost.riessAiReference.classList.contains( 'riess-ai-caption-spacer' ) 77 ? overlayHost.riessAiReference 78 : null; 79 if ( captionSpacer ) { 80 captionSpacer.classList.toggle( 'riess-ai-size-hidden', ! eligible ); 81 } 82 83 if ( ! eligible && disclosure.matches( selector ) && disclosure.classList.contains( 'is-open' ) ) { 84 setOpen( disclosure, false, false ); 85 } 86 87 if ( changed && overlayHost ) { 88 scheduleOverlayUpdate(); 89 } 90 } 91 92 function updateDisclosureSizes( root ) { 93 const disclosures = []; 94 if ( root.nodeType === 1 && root.matches( '[data-riess-ai-min-width][data-riess-ai-min-height]' ) ) { 95 disclosures.push( root ); 96 } 97 root.querySelectorAll( '[data-riess-ai-min-width][data-riess-ai-min-height]' ).forEach( function ( disclosure ) { 98 disclosures.push( disclosure ); 99 } ); 100 disclosures.forEach( updateDisclosureSize ); 101 } 102 103 function scheduleSizeUpdate() { 104 if ( sizeUpdateScheduled ) { 105 return; 106 } 107 sizeUpdateScheduled = true; 108 window.setTimeout( function () { 109 sizeUpdateScheduled = false; 110 updateDisclosureSizes( document ); 111 }, 0 ); 112 } 113 114 function createDeferredOverlay( wrapper, reference, imageLink, disclosure, fallback, template ) { 115 const host = document.createElement( 'span' ); 116 wrapper.classList.forEach( function ( className ) { 117 if ( className !== 'riess-ai-auto-pending' ) { 118 host.classList.add( className ); 119 } 120 } ); 121 host.classList.add( 'riess-ai-auto-resolved', 'riess-ai-overlay-host' ); 122 host.dataset.riessAiMediaId = wrapper.dataset.riessAiMediaId || ''; 123 host.riessAiLayoutRoot = imageLink ? imageLink.parentElement : wrapper.parentElement; 124 host.riessAiSizeReference = reference; 125 126 if ( disclosure.classList.contains( 'riess-ai-caption' ) && fallback ) { 127 fallback.classList.add( 'riess-ai-caption-spacer' ); 128 fallback.removeAttribute( 'data-riess-ai-disclosure' ); 129 fallback.setAttribute( 'aria-hidden', 'true' ); 130 host.classList.add( 'riess-ai-overlay-host-caption' ); 131 host.riessAiReference = fallback; 132 } else { 133 if ( fallback ) { 134 fallback.remove(); 135 } 136 host.riessAiReference = reference; 137 } 138 139 template.remove(); 140 wrapper.replaceWith.apply( wrapper, Array.from( wrapper.childNodes ) ); 141 host.appendChild( disclosure ); 142 document.body.appendChild( host ); 143 overlayHosts.add( host ); 144 updateOverlayHost( host ); 145 updateDisclosureSize( disclosure ); 146 147 if ( overlayResizeObserver ) { 148 overlayResizeObserver.observe( host.riessAiReference ); 149 if ( host.riessAiLayoutRoot ) { 150 overlayResizeObserver.observe( host.riessAiLayoutRoot ); 151 } 152 } 153 } 154 155 function hydrateDeferredDisclosures( root ) { 156 const pending = []; 157 158 if ( root.nodeType === 1 && root.matches( '.riess-ai-auto-pending' ) ) { 159 pending.push( root ); 160 } 161 root.querySelectorAll( '.riess-ai-auto-pending' ).forEach( function ( element ) { 162 pending.push( element ); 163 } ); 164 165 pending.forEach( function ( wrapper ) { 166 if ( wrapper.dataset.riessAiHydrated === 'true' ) { 167 return; 168 } 169 170 const fallback = wrapper.querySelector( '.riess-ai-fallback' ); 171 const template = wrapper.querySelector( 'template.riess-ai-deferred-template' ); 172 const disclosure = template && template.content.firstElementChild ? template.content.firstElementChild.cloneNode( true ) : null; 173 const reference = wrapper.querySelector( 'img' ); 174 175 if ( ! disclosure || ! reference ) { 176 return; 177 } 178 179 wrapper.dataset.riessAiHydrated = 'true'; 180 const imageLink = wrapper.closest( 'a' ); 181 createDeferredOverlay( wrapper, reference, imageLink, disclosure, fallback, template ); 182 } ); 183 } 184 185 function scheduleHydration() { 186 if ( hydrationScheduled ) { 187 return; 188 } 189 hydrationScheduled = true; 190 window.requestAnimationFrame( function () { 191 hydrationScheduled = false;
192 hydrateDeferredDisclosures( document ); 193 } ); 194 } 195 196 function getParts( element ) { 197 return { 198 trigger: element.querySelector( '.riess-ai-trigger' ), 199 panel: element.querySelector( '.riess-ai-disclosure' ), 200 }; 201 } 202 203 function setOpen( element, open, returnFocus ) { 204 const parts = getParts( element ); 205 if ( ! parts.trigger || ! parts.panel ) { 206 return; 207 } 208 209 parts.trigger.setAttribute( 'aria-expanded', open ? 'true' : 'false' ); 210 parts.panel.hidden = ! open; 211 element.classList.toggle( 'is-open', open ); 212 213 if ( open && element.dataset.riessAiInteractive === 'dialog' ) { 214 parts.panel.focus(); 215 } 216 217 if ( ! open && returnFocus ) { 218 parts.trigger.focus(); 219 } 220 } 221 222 function closeOthers( except ) { 223 document.querySelectorAll( selector + '.is-open' ).forEach( function ( element ) { 224 if ( element !== except ) { 225 setOpen( element, false, false ); 226 } 227 } ); 228 } 229 230 document.addEventListener( 'click', function ( event ) { 231 const trigger = event.target.closest( selector + ' .riess-ai-trigger' ); 232 if ( trigger ) { 233 const element = trigger.closest( selector ); 234 const open = trigger.getAttribute( 'aria-expanded' ) !== 'true'; 235 event.preventDefault(); 236 closeOthers( element ); 237 setOpen( element, open, false ); 238 return; 239 } 240 241 document.querySelectorAll( selector + '.is-open' ).forEach( function ( element ) { 242 if ( ! element.contains( event.target ) ) { 243 setOpen( element, false, false ); 244 } 245 } ); 246 } ); 247 248 document.addEventListener( 'pointerdown', function () { 249 keyboardNavigation = false; 250 }, true ); 251 252 document.addEventListener( 'keydown', function ( event ) { 253 keyboardNavigation = true; 254 255 if ( event.key !== 'Escape' ) { 256 return; 257 } 258 259 const openElement = document.querySelector( selector + '.is-open' ); 260 if ( openElement ) { 261 event.preventDefault(); 262 setOpen( openElement, false, true ); 263 } 264 } ); 265 266 document.addEventListener( 'focusin', function ( event ) { 267 const element = event.target.closest( selector + '[data-riess-ai-interactive="tooltip"]' ); 268 if ( element && keyboardNavigation ) { 269 closeOthers( element ); 270 setOpen( element, true, false ); 271 } 272 } ); 273 274 document.addEventListener( 'focusout', function ( event ) { 275 const element = event.target.closest( selector + '[data-riess-ai-interactive="tooltip"]' ); 276 if ( ! element ) { 277 return; 278 } 279 280 window.setTimeout( function () { 281 if ( ! element.contains( document.activeElement ) ) { 282 setOpen( element, false, false ); 283 } 284 }, 0 ); 285 } ); 286 287 document.addEventListener( 'pointerover', function ( event ) { 288 if ( event.pointerType && event.pointerType !== 'mouse' ) { 289 return; 290 } 291 const element = event.target.closest( selector + '[data-riess-ai-interactive="tooltip"]' ); 292 if ( element ) { 293 setOpen( element, true, false ); 294 } 295 } ); 296 297 document.addEventListener( 'pointerout', function ( event ) { 298 if ( event.pointerType && event.pointerType !== 'mouse' ) { 299 return; 300 } 301 const element = event.target.closest( selector + '[data-riess-ai-interactive="tooltip"]' ); 302 if ( ! element || element.contains( event.relatedTarget ) || element.contains( document.activeElement ) ) { 303 return; 304 } 305 setOpen( element, false, false ); 306 } ); 307 308 hydrateDeferredDisclosures( document ); 309 updateDisclosureSizes( document ); 310 311 const observer = new MutationObserver( function ( mutations ) { 312 if ( mutations.some( function ( mutation ) { return mutation.addedNodes.length > 0; } ) ) { 313 scheduleHydration(); 314 scheduleOverlayUpdate(); 315 scheduleSizeUpdate(); 316 } 317 } ); 318 observer.observe( document.documentElement, { childList: true, subtree: true } ); 319 window.addEventListener( 'resize', function () { 320 scheduleOverlayUpdate(); 321 scheduleSizeUpdate(); 322 }, { passive: true } ); 323 window.addEventListener( 'load', function () { 324 scheduleOverlayUpdate(); 325 scheduleSizeUpdate(); 326 } ); 327 document.addEventListener( 'scroll', scheduleOverlayUpdate, { capture: true, passive: true } ); 328 if ( document.fonts && document.fonts.ready ) { 329 document.fonts.ready.then( scheduleOverlayUpdate ); 330 } 331}() );
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.