diff --git a/gdpr-content-blocker/assets/frontend.js b/gdpr-content-blocker/assets/frontend.js index 2052b3f..adfec5d 100644 --- a/gdpr-content-blocker/assets/frontend.js +++ b/gdpr-content-blocker/assets/frontend.js @@ -261,17 +261,61 @@ } } - /** Elementor video widgets store the URL in data-settings and build the - * player via JS — handle them before that happens. */ + /** Reconstruct a YouTube watch URL from a thumbnail (i.ytimg.com/vi/ID/…). */ + function ytIdFromThumb( s ) { + const m = String( s || '' ).match( /(?:i\.ytimg\.com|img\.youtube\.com)\/vi\/([\w-]{6,})\// ); + return m ? m[ 1 ] : ''; + } + + /** + * Find the embedded video URL of an Elementor video widget. Elementor often + * does NOT put the URL in data-settings (only {"video_type":"youtube"}) and + * builds the player via the JS API — so we look in several places. + */ + function videoUrlForWidget( widget ) { + const ds = widget.getAttribute( 'data-settings' ) || ''; + + // 1) Explicit URL keys in data-settings (older/other Elementor versions). + try { + const s = JSON.parse( ds || '{}' ); + const u = s.youtube_url || s.vimeo_url || s.video_url || s.external_url + || s.hosted_url || ( s.link && s.link.url ) || ''; + if ( u ) return u; + } catch ( e ) { /* not JSON / no keys */ } + + // 2) Any youtube/vimeo URL anywhere in the data-settings string (JSON values + // are quoted, so stop at a quote/space; tolerate escaped slashes \/). + const m = ds.match( /https?:[^"\s]*?(?:youtube\.com|youtu\.be|vimeo\.com)[^"\s]*/i ); + if ( m ) return m[ 0 ].replace( /\\\//g, '/' ).replace( /\\/g, '' ); + + // 3) A server-rendered iframe already inside the widget. + const ifr = widget.querySelector( 'iframe[src]' ); + if ( ifr ) return ifr.getAttribute( 'src' ); + + // 4) A YouTube thumbnail (lazyload / image-overlay mode) → rebuild the URL. + const thumb = widget.querySelector( + 'img[src*="ytimg.com/vi/"], img[src*="img.youtube.com/vi/"], [style*="ytimg.com/vi/"]' + ); + if ( thumb ) { + const id = ytIdFromThumb( thumb.getAttribute( 'src' ) || thumb.getAttribute( 'style' ) || '' ); + if ( id ) return 'https://www.youtube.com/watch?v=' + id; + } + return ''; + } + + /** Elementor video widgets build the player via JS — replace them with our + * consent placeholder before that happens. */ function handleElementorVideos() { - document.querySelectorAll( '.elementor-widget-video[data-settings]' ).forEach( function ( widget ) { - let settings; - try { - settings = JSON.parse( widget.dataset.settings ); - } catch ( e ) { - return; - } - const raw = settings.youtube_url || settings.vimeo_url || settings.external_url || ''; + const widgets = document.querySelectorAll( + '.elementor-widget-video, .elementor-widget[data-widget_type^="video"]' + ); + widgets.forEach( function ( widget ) { + const container = widget.querySelector( '.elementor-widget-container' ) || widget; + // Already turned into a placeholder (e.g. by the server-side autodetect + // catching a rendered iframe) → leave it. + if ( container.querySelector( '.cb-blocker' ) ) return; + + const raw = videoUrlForWidget( widget ); if ( ! raw ) return; const embed = toEmbedUrl( raw ); @@ -282,7 +326,6 @@ // Neutralise Elementor so it won't build the player / load the overlay. widget.removeAttribute( 'data-settings' ); - const container = widget.querySelector( '.elementor-widget-container' ) || widget; container.innerHTML = ''; container.appendChild( buildPlaceholder( svc, embed, {} ) ); } );