1// add delayed functionality here 2import { getMetadata, sampleRUM, loadCSS } from "./aem.js"; 3import { getLanguage, isHomePage, loadAdobeAnalytics } from './utils-core.js'; 4import { 5 a, span, i, 6 section, 7} from './dom-helpers.js'; 8import { loadConsentManager, hasTargetingConsent } from './consent.js'; 9 10 11/** 12 * Swoosh on page 13 */ 14 15// Adobe Target 16window.targetGlobalSettings = { 17 bodyHidingEnabled: false, 18}; 19 20function pageSwoosh() { 21 const pSwoosh = getMetadata('page-swoosh'); 22 if (!pSwoosh || pSwoosh.length < 1) return; 23 if (pSwoosh !== 'page-swoosh-no') { 24 document.body.classList.add(pSwoosh); 25 } else { 26 document.body.classList.remove(pSwoosh); 27 } 28} 29 30// refactor tweetable links function 31/** 32 * Opens a popup for the Twitter links autoblock. 33 */ 34function openPopUp(popUrl) { 35 const popupParams = `height=450, width=550, top=${(window.innerHeight / 2 - 275)}` 36 + `, left=${(window.innerWidth / 2 - 225)}` 37 + ', toolbar=0, location=0, menubar=0, directories=0, scrollbars=0'; 38 window.open(popUrl, 'fbShareWindow', popupParams); 39} 40 41/** 42 * Finds and decorates anchor elements with Twitter hrefs 43 */ 44function buildTwitterLinks() { 45 const main = document.querySelector('main'); 46 if (!main) return; 47 48 // get all paragraph elements 49 const paras = main.querySelectorAll('p'); 50 const url = window.location.href; 51 const encodedUrl = encodeURIComponent(url); 52 53 [...paras].forEach((paragraph) => { 54 const tweetables = paragraph.innerHTML.match(/<tweetable[^>]*>([\s\S]*?)<\/tweetable>/g); 55 if (tweetables) { 56 tweetables.forEach((tweetableTag) => { 57 const matchedContent = tweetableTag.match( 58 /<tweetable(?:[^>]*data-channel=['"]([^'"]*)['"])?(?:[^>]*data-hashtag=['"]([^'"]*)['"])?[^>]*>([\s\S]*?)<\/tweetable>/, 59 ); 60 const channel = matchedContent[1] || ''; 61 const hashtag = matchedContent[2] || ''; 62 const tweetContent = matchedContent[3]; 63 64 let modalURL = `https://twitter.com/intent/tweet?text=${encodeURIComponent(tweetContent)}` 65 + `&original_referrer=${encodedUrl}&source=tweetbutton`; 66 if (channel) modalURL += `&via=${encodeURIComponent(channel.charAt(0) === '@' ? channel.substring(1) : channel)}`; 67 if (hashtag) modalURL += `&hashtags=${encodeURIComponent(hashtag)}`; 68 69 const tweetableEl = span( 70 { class: 'tweetable' }, 71 a({ href: modalURL, target: '_blank', tabindex: 0 }, tweetContent, i({ class: 'lp lp-twit' })), 72 ); 73 paragraph.innerHTML = paragraph.innerHTML.replace(tweetableTag, tweetableEl.outerHTML); 74 }); 75 } 76 [...paragraph.querySelectorAll('.tweetable > a')].forEach((twitterAnchor) => { 77 twitterAnchor.addEventListener('click', (event) => { 78 event.preventDefault(); 79 const apiURL = twitterAnchor.href; 80 openPopUp(apiURL); 81 }); 82 }); 83 }); 84} 85 86async function removeTitleAttrFromButtons() { 87 const buttons = document.querySelectorAll('.button-container .button'); 88 buttons.forEach((button) => { 89 if (button.hasAttribute('title')) { 90 button.removeAttribute('title'); 91 } 92 const dataTitle = button.getAttribute('data-title'); 93 if (dataTitle) { 94 button.setAttribute('title', dataTitle); 95 button.removeAttribute('data-title'); 96 } 97 }); 98} 99 100function loadFlourishScript() { 101 return new Promise((resolve, reject) => { 102 // If it's already defined, resolve immediately 103 if (window.Flourish) { 104 resolve(); 105 return; 106 } 107 108 // Set configuration to prevent auto-loading if you want full manual control 109 window.Flourish = { disable_autoload: true }; 110 111 const script = document.createElement('script'); 112 script.src = 'https://public.flourish.studio/resources/embed.js'; 113 script.async = true; 114 115 script.onload = () => resolve(); 116 script.onerror = (err) => reject(err); 117 118 document.head.appendChild(script); 119 }); 120} 121 122async function handleFlourishEmbedScripts() { 123 const embeds = document.querySelectorAll('.flourish-embed:not(:has(iframe))'); 124 125 if (!embeds.length) return; 126 127 // Ensure the Flourish library is loaded 128 if (!window.Flourish) { 129 await loadFlourishScript(); 130 } 131 132 // Re-initialize logic 133 if (window.Flourish && typeof window.Flourish.loadEmbed === 'function') { 134 embeds.forEach(embed => { 135 window.Flourish.loadEmbed(embed); 136 }); 137 } 138 139 // Fallback to init() if loadEmbed isn't supported for some reason 140 else if (window.Flourish && typeof window.Flourish.init === 'function') { 141 window.Flourish.init(); 142 } 143} 144 145function getClosestShowNotes(iframe) { 146 let ancestor = iframe.parentElement; 147 while (ancestor) { 148 const notesEl = ancestor.querySelector('.cp-show-notes'); 149 if (notesEl) return notesEl; 150 ancestor = ancestor.parentElement; 151 } 152 return null; 153} 154 155async function handleCaptivateEmbedScripts() { 156 const iframe = document.querySelector('iframe[src*="player.captivate.fm"]'); 157 if (!iframe) return; 158 159 const allow = iframe.getAttribute('allow') || ''; 160 if (!allow.includes('autoplay')) { 161 iframe.setAttribute('allow', allow ? `${allow};
161 autoplay` : 'autoplay'); 162 } 163 164 let didSetup = false; 165 const setup = () => { 166 if (didSetup) return; 167 didSetup = true; 168 169 // eslint-disable-next-line no-undef 170 const player = new CP(iframe); 171 172 const notesEl = getClosestShowNotes(iframe); 173 if (!notesEl) return; 174 175 const TIMESTAMP_REGEX = /(?:[0-5]\d|2[0-3]):(?:[0-5]\d):?(?:[0-5]\d)?/g; 176 177 notesEl.innerHTML = notesEl.innerHTML.replace(TIMESTAMP_REGEX, (match) => ( 178 `<a href="javascript: void(0);" data-ts="${match}" class="cp-timestamp">${match}</a>` 179 )); 180 181 notesEl.addEventListener('click', (evt) => { 182 const target = evt.target.closest('.cp-timestamp'); 183 if (!target) return; 184 185 const parts = target.dataset.ts.split(':'); 186 let seconds = 0; 187 let multiplier = 1; 188 while (parts.length > 0) { 189 seconds += multiplier * parseInt(parts.pop(), 10); 190 multiplier *= 60; 191 } 192 193 player.seekTo(seconds); 194 }); 195 }; 196 197 iframe.addEventListener('load', setup); 198 setup(); 199} 200 201async function loadDelayed() { 202 pageSwoosh(); 203 sampleRUM('cwv'); 204 await removeTitleAttrFromButtons(); 205 // Defer the OneTrust CMP to an idle gap so its ~1s of main-thread work runs 206 // after the page has settled, instead of competing with other delayed scripts. 207 if ('requestIdleCallback' in window) { 208 requestIdleCallback(() => loadConsentManager(), { timeout: 5000 }); 209 } else { 210 setTimeout(() => loadConsentManager(), 3000); 211 } 212 if (hasTargetingConsent()) { 213 //todo: add any scripts that require targeting consent here 214 } 215 216 if (!isHomePage()) { 217 await loadAdobeAnalytics(); 218 } 219 await handleFlourishEmbedScripts(); 220 await handleCaptivateEmbedScripts(); 221 // insertSchemaScript(); 222} 223loadDelayed(); 224 225 226function isInUniversalEditor() { 227 return window.self !== window.top; 228} 229 230async function loadDelayedScripts() { 231 if (isInUniversalEditor()) { 232 const { default: registerUEExtensions } = await import('./ue-extensions.js'); 233 registerUEExtensions(); 234 } 235} 236 237loadDelayedScripts();
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.