1/** 2 * Lets Elementor's native background video accept Livid URLs. 3 * 4 * Elementor's own BackgroundVideo handler only recognises YouTube/Vimeo and 5 * treats every other URL as a direct video file, so a pasted Livid watch URL 6 * ends up as a <video> src that can never play. This handler detects Livid 7 * links in `background_video_link`, removes that broken fallback, and mounts 8 * the Livid embed iframe with the same cover-sizing maths Elementor uses. 9 */ 10( function ( $ ) { 11 'use strict'; 12 13 $( window ).on( 'elementor/frontend/init', function () { 14 if ( ! window.elementorModules || ! elementorModules.frontend || ! elementorModules.frontend.handlers ) { 15 return; 16 } 17 18 const hosts = ( window.lividElementorBackground || {} ).hosts || []; 19 20 function parseLividVideo( link ) { 21 let url; 22 try { 23 url = new URL( link, window.location.href ); 24 } catch ( e ) { 25 return null; 26 } 27 if ( ! hosts.includes( url.hostname.replace( /^www\./, '' ) ) ) { 28 return null; 29 } 30 const match = url.pathname.match( /\/(?:watch|video|embed)\/([A-Za-z0-9_-]+)/ ); 31 return match ? { id: match[ 1 ], origin: url.origin } : null; 32 } 33 34 class LividBackgroundVideo extends elementorModules.frontend.handlers.Base { 35 getDefaultSettings() { 36 return { 37 selectors: { 38 container: '.elementor-background-video-container', 39 }, 40 }; 41 } 42 43 getDefaultElements() { 44 return { 45 $container: this.$element.find( this.getSettings( 'selectors.container' ) ), 46 }; 47 } 48 49 run() { 50 this.deactivate(); 51 52 const settings = this.getElementSettings(); 53 if ( 'video' !== settings.background_background || ! settings.background_video_link ) { 54 return; 55 } 56 if ( ! settings.background_play_on_mobile && 'mobile' === elementorFrontend.getCurrentDeviceMode() ) { 57 return; 58 } 59 const video = parseLividVideo( settings.background_video_link ); 60 if ( ! video ) { 61 return; 62 } 63 this.activate( video, settings ); 64 } 65 66 activate( video, settings ) { 67 const $container = this.elements.$container; 68 if ( ! $container.length ) { 69 return; 70 } 71 72 $container.children( '.elementor-background-video-hosted' ).remove(); 73 74 const src = new URL( video.origin + '/embed/' + encodeURIComponent( video.id ) ); 75 // background=1 implies autoplay/muted/loop and disables all player 76 // chrome; the explicit params guard against that default changing. 77 src.searchParams.set( 'background', '1' ); 78 src.searchParams.set( 'autoplay', '1' ); 79 src.searchParams.set( 'muted', '1' ); 80 src.searchParams.set( 'playsinline', '1' ); 81 src.searchParams.set( 'keyboard', '0' ); 82 src.searchParams.set( 'loop', settings.background_play_once ? '0' : '1' ); 83 if ( settings.background_privacy_mode ) { 84 src.searchParams.set( 'dnt', '1' ); 85 } 86 if ( settings.background_video_start > 0 ) { 87 src.hash = 't=' + settings.background_video_start; 88 } 89 90 this.$iframe = $( '<iframe>', { 91 src: src.toString(), 92 class: 'livid-background-video', 93 allow: 'autoplay; encrypted-media', 94 'aria-hidden': 'true', 95 tabindex: '-1', 96 } ).css( { 97 position: 'absolute', 98 top: '50%', 99 left: '50%', 100 transform: 'translate(-50%, -50%)', 101 border: 0, 102 maxWidth: 'none', 103 pointerEvents: 'none', 104 } ); 105 106 $container.append( this.$iframe ); 107 this.changeVideoSize(); 108 elementorFrontend.elements.$window.on( 'resize elementor/bg-video/recalc', this.changeVideoSize ); 109 } 110 111 changeVideoSize() { 112 if ( ! this.$iframe ) { 113 return; 114 } 115 const $container = this.elements.$container, 116 containerWidth = $container.outerWidth(), 117 containerHeight = $container.outerHeight(), 118 aspectRatio = 16 / 9, 119 isWidthFixed = containerWidth / containerHeight > aspectRatio; 120 121 this.$iframe 122 .width( isWidthFixed ? containerWidth : containerHeight * aspectRatio ) 123 .height( isWidthFixed ? containerWidth / aspectRatio : containerHeight ); 124 } 125 126 deactivate() { 127 if ( this.$iframe ) { 128 this.$iframe.remove(); 129 this.$iframe = null; 130 elementorFrontend.elements.$window.off( 'resize elementor/bg-video/recalc', this.changeVideoSize ); 131 } 132 } 133 134 onInit( ...args ) { 135 super.onInit( ...args ); 136 this.changeVideoSize = this.changeVideoSize.bind( this ); 137 this.run(); 138 } 139 140 onElementChange( propertyName ) { 141 if ( 0 === propertyName.indexOf( 'background_' ) ) { 142 this.run(); 143 } 144 } 145 146 onDestroy( ...args ) { 147 this.deactivate(); 148 super.onDestroy( ...args ); 149 } 150 } 151 152 [ 'section', 'column', 'container' ].forEach( function ( elementType ) { 153 elementorFrontend.hooks.addAction( 'frontend/element_ready/' + elementType, function ( $element ) { 154 elementorFrontend.elementsHandler.addHandler( LividBackgroun
154dVideo, { $element } ); 155 } ); 156 } ); 157 } ); 158} )( jQuery );
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.