1/** 2 * Cookie Consent by https://www.PrivacyPolicies.com 3 */ 4(function ($, Drupal, drupalSetting) { 5 Drupal.behaviors.veoliaPlatformVideo = { 6 attach: function (context) { 7 $(once('veoliaPlatformVideo', 'body', context)).ready(function () { 8 // Create the "didomiOnReady" listener 9 window.didomiOnReady = window.didomiOnReady || []; 10 window.didomiOnReady.push(function (Didomi) { 11 let didomiVendors = { 'youtube': 'video-embed-field-provider-youtube', 'vimeo': 'video-embed-field-provider-vimeo', 'tencentqq-Neqr6ADb': 'video-embed-field-provider-qq', 'bilibili-FdVp8NqX': 'video-embed-field-provider-BiliBili' }; 12 // addVendorStatusListener only listens to changes in consent status 13 // To handle the initial state, we need to check the current user status 14 let userStatus = Didomi.getCurrentUserStatus(); 15 $.each(didomiVendors, function (vendor, identifier) { 16 const selector = '.' + identifier + '.video-embed-field-responsive-video'; 17 const handleConsent = (consentStatus) => { 18 if (consentStatus.enabled === true) { 19 document.querySelectorAll(selector).forEach(video => { 20 playVideoAndHideOverlay(video, identifier); 21 }); 22 } else if (consentStatus.enabled === false) { 23 document.querySelectorAll(selector).forEach(video => { 24 getIframeWrapper('.' + identifier); 25 }); 26 } 27 }; 28 29 // Check the current consent status for the vendor 30 if (userStatus.vendors[vendor]) { 31 handleConsent(userStatus.vendors[vendor]); 32 } 33 34 // Listen for consent changes 35 Didomi.addVendorStatusListener(vendor, handleConsent); 36 }); 37 38 // An event listener is attached to each button element 39 document.querySelectorAll('.video-disclaimer').forEach(function (a) { 40 let provider = $(a).find('.click-button').attr('data-provider'); 41 a.addEventListener('click', function () { 42 setPositiveConsentStatusForVendor('c:' + provider); 43 }); 44 }); 45 }); 46 }); 47 48 const setPositiveConsentStatusForVendor = (vendorId) => { 49 // Use openCurrentUserStatusTransaction for Vimeo, openTransaction for others 50 let transaction; 51 let purposes, liPurposes; 52 53 if (vendorId === 'c:vimeo') { 54 transaction = Didomi.openCurrentUserStatusTransaction(); 55 transaction.enableVendor('vimeo'); 56 57 purposes = Didomi.getVendorById('c:vimeo').purposeIds; 58 transaction.enablePurposes(purposes); 59 60 liPurposes = Didomi.getVendorById('c:vimeo').legIntPurposeIds; 61 transaction.enablePurposes(liPurposes); 62 } else { 63 transaction = Didomi.openTransaction(); 64 transaction.enableVendor(vendorId); 65 66 purposes = Didomi.getVendorById(vendorId).purposeIds; 67 transaction.enablePurposes(...purposes); 68 } 69 70 transaction.commit(); 71 }; 72 73 const playVideoAndHideOverlay = (container, identifier) => { 74 let iframe_element = $(container).find('iframe'); 75 $(iframe_element).attr('src', $(iframe_element).attr('data-src')); 76 $('.' + identifier + '.video-embed-field-responsive-video').removeClass('consent_enabled'); 77 $('.' + identifier + ' .video-text-overlay').remove(); 78 $('.' + identifier + ' img.video-img-overlay').remove(); 79 80 if ($('.' + identifier + '.video-embed-field-responsive-video').length) { 81 $('.' + identifier + '.video-embed-field-responsive-video').css('position', 'static'); 82 } 83 }; 84 85 const setSrcToThumbnail = (element, provider, vid) => { 86 if (provider === 'vimeo') { 87 fetch(`https://vimeo.com/api/v2/video/${vid}.json`) 88 .then(response => response.json()) 89 .then(data => { 90 // Vimeo large thumbnail size is 640 x 360 (16:9) 91 element.src = data[0].thumbnail_large; 92 }) 93 .catch(error => { 94 console.error('Error fetching Vimeo thumbnail: ', error); 95 }); 96 } 97 else if (provider === 'youtube') { 98 // YouTube maxresdefault img is normally 1280 x 720 (16:9) 99 element.src = "https://img.youtube.com/vi/" + vid + "/maxresdefault.jpg"; 100 // There is also the 1st frame `https://img.youtube.com/vi/${vid}/0.jpg` 101 // For 1st frame w x h appears to always equal 480 x 360 (4:3). 102 // We can do little in terms of checking if any of these .jpg images 103 // actually exist, due to CORS: a fetch() will fail. 104 } 105 else if (provider === 'bilibili') { 106 element.src = `https://i0.hdslb.com/bfs/archive/${vid}_320x180.jpg`; 107 } 108 }; 109 110 const showConsentPrompt = (iframe) => { 111 // add consent_enabled class to the iframe parent 112 $(iframe).parent().addClass('consent_enabled'); 113 $(iframe).parents().find('.media-video__inner').parent().addClass('atp_consent_enabled'); 114 115 // When a user embeds via the CKEditor Source function, they may use 116 // For Vimeo: 117 // https://player.vimeo.com/video/VIDEO_ID 118 // For YouTube 119 // https://youtube.com/embed/VIDEO_ID or 120 // https://youtube-nocookie.com/embed/VIDEO_ID 121 // vimeo.com/VIDEO_ID and youtu.be/VIDEO_ID may appear in 122 // Drupal-generated special URLs 123 let data_src = $(iframe).attr('data-src'); 124 if (typeof data_src === 'undefined') { 125 data_src = $(iframe).attr('src'); 126 } 127 const match = iframe && data_src.match( 128 /(\/embed|youtu\.be|youtube\.com|vimeo\.com\/video|vimeo\.com|v.qq\.com|bilibili\.com\/video|player\.bilibili\.com\/player\.html\?bvid=)([^?&]+)/
128); 129 if (!match || !match[2]) { 130 // Not a YouTube, Vimeo, QQ, or Bilibili iframe. 131 return false; 132 } 133 134 // Remember VIDEO_ID and provider for use below. 135 const vid = match[2]; 136 let provider = 'youtube'; 137 if (match[1].startsWith('vimeo.com')) { 138 provider = 'vimeo'; 139 } 140 else if (match[1].startsWith('v.qq.com')) { 141 provider = 'tencentqq-Neqr6ADb'; 142 } 143 else if (match[1].includes('bilibili.com')) { 144 provider = 'bilibili-FdVp8NqX'; // Added Bilibili support 145 } 146 else { 147 provider = 'youtube'; 148 } 149 const src = data_src ? data_src : iframe.src; 150 151 // Load the video's default frame as a placeholder. Loading this img does 152 // not involve the creation of cookies or other local storage, so is GDPR 153 // compliant. 154 // Create a placeholder img and place it over the top of the video frame. 155 const img = document.createElement('img'); 156 $(img).addClass('video-img-overlay'); 157 if (drupalSettings.veolia_platform_didomi.videoPlaceholderImg) { 158 $(img).attr('src', drupalSettings.veolia_platform_didomi.videoPlaceholderImg); 159 } 160 else { 161 setSrcToThumbnail(img, provider, vid); 162 } 163 164 // Add an "I agree" button, which when clicked removes the overlay text 165 // and loads the video into the iframe. 166 const button_element = document.createElement('a'); 167 const button_wrapper = document.createElement('div'); 168 $(button_wrapper).addClass('media-call-to-action'); 169 $(button_element).addClass('click-button'); 170 $(button_element).attr('data-provider', provider); 171 button_element.addEventListener('click', function () { 172 setPositiveConsentStatusForVendor('c:' + provider); 173 }); 174 $(button_wrapper).addClass('media-call-to-action--theme--veo-' + drupalSettings.veolia_platform_didomi.videoConsentCtaBgClr); 175 $(button_element).html(drupalSettings.veolia_platform_didomi.consentButtonLabel); 176 $(button_wrapper).append(button_element); 177 178 // Create a consent text and place it over the top of the video frame. 179 const overlay_element = document.createElement('div'); 180 const overlay_text = document.createElement('div'); 181 const overlay_text_button = document.createElement('div'); 182 $(overlay_text_button).addClass('whole-wrapper'); 183 $(overlay_element).addClass('video-text-overlay video-disclaimer'); 184 $(overlay_text).addClass('video-text-wrapper'); 185 186 // Add Consent text based on Provider. 187 let provider_html = drupalSettings.veolia_platform_didomi.videoConsentTextYouTube; 188 switch (provider) { 189 case 'vimeo': 190 provider_html = drupalSettings.veolia_platform_didomi.videoConsentTextVimeo; 191 break; 192 case 'tencentqq-Neqr6ADb': 193 provider_html = drupalSettings.veolia_platform_didomi.videoConsentTextQq; 194 break; 195 case 'bilibili-FdVp8NqX': 196 provider_html = drupalSettings.veolia_platform_didomi.videoConsentTextBilibili; 197 break; 198 case 'youtube': 199 case 'default': 200 provider_html = drupalSettings.veolia_platform_didomi.videoConsentTextYouTube; 201 break; 202 } 203 $(overlay_text).html(provider_html); 204 205 // Append some useful parameters to the video URL. 206 // rel=0 : don't show related videos when paused (YouTube only) 207 // loop=1: auto-restart video when it completes 208 // @todo FIX Drupal bug: doesn't work when embedding via Media button. 209 const pars = (src.indexOf('?') > 0 ? '&' : '?') + 210 (provider == 'vimeo' ? 'loop=1' : 'rel=0&loop=1&playlist=' + vid); 211 $(iframe).attr('src', 'javascript:void(0)'); 212 $(iframe).attr('data-src', data_src); 213 214 // remove the current iframe and append a new one with the same attributes. 215 const newIframe = iframe.cloneNode(true); 216 iframe.parentNode.replaceChild(newIframe, iframe); 217 $(newIframe).attr('src', 'javascript:void(0)'); 218 $(newIframe).attr('data-src', data_src); 219 220 // Append "I agree" button to the overlay. 221 // Append img and overlay as siblings of the iframe. 222 $(overlay_text_button).append(overlay_text); 223 $(overlay_text_button).append(button_wrapper); 224 $(overlay_element).append(overlay_text_button); 225
226 // Do not show popup if already cookie is accepted. 227 newIframe.parentNode.append(img, overlay_element); 228 229 // Make the video frame responsive, based on 16:9 ratio. 230 newIframe.parentNode.setAttribute('style', 'width:100%; height:0; position:relative'); 231 newIframe.setAttribute('style', 'width:100%; height:100%; position:absolute; left:0; top:0'); 232 }; 233 234 const getIframeWrapper = (providerSelector) => { 235 if ($('.video-embed-field-responsive-video').length) { 236 const ele = $(providerSelector + '.video-embed-field-responsive-video iframe'); 237 ele.each(function (index, element) { 238 // check if consent is already enabled for the iframe. If not, then show the consent prompt. 239 if (!$(element).parent().hasClass('consent_enabled')) { 240 showConsentPrompt(element); 241 } 242 }); 243 } 244 }; 245 }, 246 }; 247})(jQuery, Drupal, drupalSettings);
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.