1/** 2 * DailyOM Guide â Ocean parent pages (landing + chat HTML). Hosted on livepel only. 3 * Edit cfg URLs below for staging/production. 4 */ 5(function (global) { 6 'use strict'; 7 8 var cfg = { 9 iframeOrigin: 'https://astrology.dailyom.com', 10 landingIframeUrl: 'https://astrology.dailyom.com/dailyom-guide', 11 chatIframeUrl: 'https://astrology.dailyom.com/dailyom-guide/chat-new', 12 landingPageUrl: 'https://www.dailyom.com', 13 chatPageUrl: 'https://www.dailyom.com/ai-course-search', 14 guideCssUrl: 'https://astrology.dailyom.com/media/css/dailyom-guide.css', 15 heightPadding: 20 16 }; 17 18 var DISCLOSURE_COOKIE_NAME = 'dailyom_guide_disclosure_accepted'; 19 var DISCLOSURE_COOKIE_MAX_AGE_DAYS = 365; 20 var SESSION_STORAGE_KEY = 'dailyom_guide_session_id'; 21 22 function originFromUrl(url) { 23 try { 24 return new URL(url).origin; 25 } catch (e) { 26 return ''; 27 } 28 } 29 30 function dirnameOfPage() { 31 try { 32 var path = global.location.pathname || '/'; 33 var i = path.lastIndexOf('/'); 34 if (i <= 0) { 35 return global.location.origin; 36 } 37 return global.location.origin + path.slice(0, i + 1); 38 } catch (e) { 39 return ''; 40 } 41 } 42 43 function resolvePageUrl(explicit, filename) { 44 if (explicit) { 45 return explicit; 46 } 47 var base = dirnameOfPage(); 48 return base ? base + filename : filename; 49 } 50 51 function getLandingPageUrl() { 52 return resolvePageUrl(cfg.landingPageUrl, 'dailyom-guide-landing.html'); 53 } 54 55 function getChatPageUrl() { 56 return resolvePageUrl(cfg.chatPageUrl, 'dailyom-guide-chat-new.html'); 57 } 58 59 function getIframeOrigin() { 60 return cfg.iframeOrigin || originFromUrl(cfg.landingIframeUrl) || originFromUrl(cfg.chatIframeUrl); 61 } 62 63 /** True when iframe has navigated to the child app (not about:blank / parent origin). */ 64 function isIframeMessagingReady(iframe) { 65 if (!iframe || !iframe.contentWindow) { 66 return false; 67 } 68 var expectedOrigin = getIframeOrigin(); 69 if (!expectedOrigin) { 70 return false; 71 } 72 var src = String(iframe.getAttribute('src') || iframe.src || '').trim(); 73 if (!src || src === 'about:blank' || originFromUrl(src) !== expectedOrigin) { 74 return false; 75 } 76 try { 77 var href = iframe.contentWindow.location.href; 78 if (!href || href === 'about:blank') { 79 return false; 80 } 81 return originFromUrl(href) === expectedOrigin; 82 } catch (e) { 83 // Cross-origin: child has left about:blank; trust configured src origin. 84 return true; 85 } 86 } 87 88 function captureParentAttribution() { 89 if (global.DailyomGuideAttribution && typeof global.DailyomGuideAttribution.captureFromLocation === 'function') { 90 global.DailyomGuideAttribution.captureFromLocation(); 91 } 92 } 93 94 function appendAttributionToUrl(urlString) { 95 if (global.DailyomGuideAttribution && typeof global.DailyomGuideAttribution.appendToUrl === 'function') { 96 return global.DailyomGuideAttribution.appendToUrl(urlString, global.location.href); 97 } 98 return urlString; 99 } 100 101 function appendAttributionToUrlObject(url) { 102 if (global.DailyomGuideAttribution && typeof global.DailyomGuideAttribution.appendToUrlObject === 'function') { 103 global.DailyomGuideAttribution.appendToUrlObject(url); 104 } 105 return url; 106 } 107 108 function postMarketingParamsToIframe(iframe) { 109 if (!iframe || !iframe.contentWindow || !global.DailyomGuideAttribution) { 110 return; 111 } 112 if (!isIframeMessagingReady(iframe)) { 113 return; 114 } 115 var origin = getIframeOrigin(); 116 if (!origin) { 117 return; 118 } 119 try { 120 iframe.contentWindow.postMessage({ 121 type: 'mo_guide_marketing_params', 122 params: global.DailyomGuideAttribution.getStored() 123 }, origin); 124 } catch (e) {} 125 } 126 127 function bindIframeMarketingSync(iframe) { 128 if (!iframe) { 129 return; 130 } 131 iframe.addEventListener('load', function () { 132 postMarketingParamsToIframe(iframe); 133 }); 134 // Child iframe may ask for params after it boots (quizzes / tools). 135 var allowedOrigin = getIframeOrigin(); 136 if (!global.__dailyomParentMarketingRequestBound) { 137 global.__dailyomParentMarketingRequestBound = true; 138 global.addEventListener('message', function (event) { 139 if (allowedOrigin && event.origin !== allowedOrigin) { 140 return; 141 } 142 var data = event.data || {}; 143 if (data.type !== 'request_mo_guide_marketing_params') { 144 return; 145 } 146 var frames = global.document.querySelectorAll('iframe'); 147 for (var i = 0; i < frames.length; i++) { 148 postMarketingParamsToIframe(frames[i]); 149 } 150 }); 151 } 152 } 153 154 function buildChatPageUrl(query) { 155 var url = new URL(getChatPageUrl(), global.location.href); 156 var q = String(query || '').trim(); 157 if (q) { 158 url.searchParams.set('q', q); 159 } else { 160 url.searchParams.delete('q'); 161 } 162 appendAttributionToUrlObject(url); 163 return url.toString(); 164 } 165
166 function appendParentParams(iframeUrl, parentLandingUrl, parentChatUrl) { 167 var url = new URL(iframeUrl, global.location.href); 168 url.searchParams.set('parent_landing_page', parentLandingUrl || getLandingPageUrl()); 169 url.searchParams.set('parent_chat_page', parentChatUrl || getChatPageUrl()); 170 return url.toString(); 171 } 172 173 function buildLandingIframeSrc() { 174 return appendAttributionToUrl( 175 appendParentParams(cfg.landingIframeUrl, getLandingPageUrl(), getChatPageUrl()) 176 ); 177 } 178 179 function buildChatIframeSrc(query) { 180 var url = new URL(cfg.chatIframeUrl, global.location.href); 181 url.searchParams.set('embed', '1'); 182 var q = String(query || '').trim(); 183 if (q) { 184 url.searchParams.set('q', q); 185 } 186 url.searchParams.set('parent_landing_page', getLandingPageUrl()); 187 url.searchParams.set('parent_chat_page', getChatPageUrl()); 188 appendAttributionToUrlObject(url); 189 return url.toString(); 190 } 191 192 function navigateTop(url) { 193 try { 194 if (global.top && global.top !== global.self) { 195 global.top.location.href = url; 196 return; 197 } 198 } catch (e) {} 199 global.location.href = url; 200 } 201 202 function goToChatPage(query) { 203 navigateTop(buildChatPageUrl(query)); 204 } 205 206 function goToLandingPage() { 207 navigateTop(getLandingPageUrl()); 208 } 209 210 function applyNavLinks(root) { 211 root = root || global.document; 212 if (!root || !root.querySelectorAll) { 213 return; 214 } 215 root.querySelectorAll('[data-mo-guide-nav]').forEach(function (el) { 216 var kind = (el.getAttribute('data-mo-guide-nav') || '').toLowerCase(); 217 if (kind === 'landing') { 218 el.setAttribute('href', getLandingPageUrl()); 219 } else if (kind === 'chat') { 220 var prefill = el.getAttribute('data-mo-guide-prefill') || ''; 221 el.setAttribute('href', buildChatPageUrl(prefill)); 222 } 223 }); 224 } 225 226 function scrollOceanParentToBottom(behavior) { 227 if (!global.document.documentElement.classList.contains('mo-guide-ocean-chat')) { 228 return; 229 } 230 var b = behavior === 'smooth' ? 'smooth' : 'auto'; 231 function run() { 232 var docEl = global.document.documentElement; 233 var body = global.document.body; 234 var maxScroll = Math.max(body.scrollHeight, docEl.scrollHeight) - global.innerHeight; 235 try { 236 global.window.scrollTo({ top: Math.max(0, maxScroll), left: 0, behavior: b }); 237 } catch (e) { 238 global.window.scrollTo(0, Math.max(0, maxScroll)); 239 } 240 } 241 run(); 242 global.requestAnimationFrame(run); 243 global.setTimeout(run, 120); 244 global.setTimeout(run, 350); 245 } 246 247 /** Scroll parent so the user's last message sits just below the fixed utility bar. */ 248 function scrollOceanParentToUserAnchor(data) { 249 if (!global.document.documentElement.classList.contains('mo-guide-ocean-chat')) { 250 return; 251 } 252 var iframe = global.document.getElementById('dailyom-guide-chat-frame'); 253 if (!iframe) { 254 return; 255 } 256 var msgTopInIframe = parseInt(data && data.messageTopInIframe, 10); 257 var offsetTop = parseInt(data && data.offsetTop, 10); 258 if (isNaN(offsetTop) || offsetTop < 0) { 259 offsetTop = 0; 260 } 261 var gap = parseInt(data && data.gap, 10); 262 if (isNaN(gap)) { 263 gap = 8; 264 } 265 var utility = global.document.querySelector('.mo-guide-ocean-utility'); 266 if (!utility) { 267 utility = global.document.querySelector('.utility-bar'); 268 } 269 var anchorY = utility ? utility.getBoundingClientRect().bottom + gap : 140; 270 var b = (data && data.behavior) === 'smooth' ? 'smooth' : 'auto'; 271 function run() { 272 var iframeRect = iframe.getBoundingClientRect(); 273 var target; 274 if (!isNaN(msgTopInIframe)) { 275 target = global.window.pageYOffset + iframeRect.top + msgTopInIframe - anchorY; 276 } else { 277 target = global.window.pageYOffset + iframeRect.top + offsetTop - anchorY; 278 } 279 target = Math.max(0, Math.round(target)); 280 try { 281 global.window.scrollTo({ top: target, left: 0, behavior: b }); 282 } catch (e) { 283 global.window.scrollTo(0, target); 284 } 285 } 286 run(); 287 global.requestAnimationFrame(run); 288 global.setTimeout(run, 120); 289 global.setTimeout(run, 350); 290 } 291 292 function bindHeightListener(iframe, onMessage) { 293 var allowedOrigin = getIframeOrigin(); 294 var isOceanChat = global.document.documentElement.classList.contains('mo-guide-ocean-chat'); 295 global.addEventListener('message', function (event) { 296 if (event.origin !== allowedOrigin) { 297 return; 298 } 299 var data = event.data || {}; 300 if (data.type === 'iframe_height_update' && data.height && iframe) { 301 var h = parseInt(data.height, 10); 302 if (!isNaN(h) && h > 0) { 303 iframe.style.height = (h + (cfg.heightPadding || 20)) + 'px'; 304 } 305 } 306 if (typeof onMessage === 'function') { 307 onMessage(event, data); 308 } 309 }); 310 } 311 312 function syncSiteHeaderOffset(headerEl) { 313 if (!headerEl) { 314 return; 315 } 316 function sync() { 317 global.document.documentElement.style.setProperty(
318 '--site-header-height', 319 headerEl.offsetHeight + 'px' 320 ); 321 } 322 sync(); 323 global.addEventListener('resize', sync); 324 } 325 326 function applyParentCss() { 327 var cssEl = global.document.getElementById('mo-guide-parent-css'); 328 if (cssEl && cfg.guideCssUrl) { 329 cssEl.href = cfg.guideCssUrl; 330 } 331 } 332 333 /** Webflow cannot set classes on <html>; also apply to body + #mo-guide-root wrapper. */ 334 function applyParentScopeClasses(mode) { 335 var classes = ['mo-guide-ocean-parent']; 336 if (mode === 'chat') { 337 classes.push('mo-guide-ocean-chat'); 338 } else if (mode === 'landing') { 339 classes.push('mo-guide-ocean-landing'); 340 } 341 var docEl = global.document.documentElement; 342 var body = global.document.body; 343 var i; 344 var c; 345 for (i = 0; i < classes.length; i++) { 346 c = classes[i]; 347 docEl.classList.add(c); 348 if (body) { 349 body.classList.add(c); 350 } 351 } 352 var root = global.document.getElementById('mo-guide-root'); 353 if (!root) { 354 root = global.document.querySelector('.mo-guide-ocean-parent'); 355 } 356 if (root) { 357 for (i = 0; i < classes.length; i++) { 358 root.classList.add(classes[i]); 359 } 360 } 361 } 362 363 function readDisclosureCookie() { 364 try { 365 var escaped = DISCLOSURE_COOKIE_NAME.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 366 var match = global.document.cookie.match(new RegExp('(?:^|; )' + escaped + '=([^;]*)')); 367 return match ? decodeURIComponent(match[1]) : ''; 368 } catch (e) { 369 return ''; 370 } 371 } 372 373 function persistDisclosureAccepted() { 374 try { 375 var maxAge = DISCLOSURE_COOKIE_MAX_AGE_DAYS * 24 * 60 * 60; 376 if (global.location.protocol === 'https:') { 377 global.document.cookie = DISCLOSURE_COOKIE_NAME + '=1; Max-Age=' + maxAge + '; Path=/; SameSite=None; Secure'; 378 } else { 379 global.document.cookie = DISCLOSURE_COOKIE_NAME + '=1; Max-Age=' + maxAge + '; Path=/; SameSite=Lax'; 380 } 381 } catch (e) {} 382 } 383 384 function initLandingParent() { 385 captureParentAttribution(); 386 global.document.documentElement.classList.add('mo-guide-ocean-parent', 'mo-guide-ocean-landing'); 387 388 syncSiteHeaderOffset(global.document.getElementById('site-header')); 389 390 var wrapper = global.document.getElementById('dailyom-guide-iframe'); 391 var iframe = wrapper ? wrapper.querySelector('iframe') : null; 392 if (iframe) { 393 iframe.src = buildLandingIframeSrc(); 394 bindHeightListener(iframe); 395 bindIframeMarketingSync(iframe); 396 } 397 398 applyNavLinks(global.document); 399 400 global.addEventListener('message', function (event) { 401 if (event.origin !== getIframeOrigin()) { 402 return; 403 } 404 var data = event.data || {}; 405 if (data.type === 'mo_guide_go_chat' && data.query) { 406 goToChatPage(data.query); 407 } 408 }); 409 } 410 411 function syncOceanComposerOffset() { 412 if (!global.document.documentElement.classList.contains('mo-guide-ocean-chat')) { 413 return; 414 } 415 var wrap = global.document.querySelector('.chat-page-input__wrapper'); 416 if (!wrap) { 417 return; 418 } 419 var h = Math.ceil(wrap.getBoundingClientRect().height) + 12; 420 global.document.documentElement.style.setProperty('--mo-guide-composer-offset', h + 'px'); 421 return h; 422 } 423 424 function initChatParent() { 425 captureParentAttribution(); 426 applyParentScopeClasses('chat'); 427 428 var iframe = global.document.getElementById('dailyom-guide-chat-frame'); 429 var composer = global.document.getElementById('chat-composer'); 430 var submitBtn = global.document.getElementById('chat-send-submit'); 431 var chatForm = global.document.getElementById('chat-input-form'); 432 var composerDisabled = false;
433 434 applyNavLinks(global.document); 435 436 function clearGuideSession() { 437 try { 438 global.sessionStorage.removeItem('dailyom_guide_initial_query'); 439 global.sessionStorage.removeItem('dailyom_guide_chat_bootstrap'); 440 global.sessionStorage.removeItem(SESSION_STORAGE_KEY); 441 } catch (e) {} 442 } 443 444 function bindOceanStartOverClear() { 445 var btn = global.document.getElementById('course-finder-start-over'); 446 if (!btn) { 447 return; 448 } 449 btn.addEventListener('click', function () { 450 clearGuideSession(); 451 }); 452 } 453 bindOceanStartOverClear(); 454 455 function onViewportChange() { 456 syncOceanComposerOffset(); 457 } 458 onViewportChange(); 459 global.addEventListener('resize', onViewportChange); 460 if (global.visualViewport) { 461 global.visualViewport.addEventListener('resize', onViewportChange); 462 } 463 if (iframe) { 464 iframe.addEventListener('load', onViewportChange); 465 } 466 467 function getQueryParam() { 468 return (new URLSearchParams(global.location.search || '').get('q') || '').trim(); 469 } 470 471 function postToIframe(payload) { 472 if (!iframe || !iframe.contentWindow || !isIframeMessagingReady(iframe)) { 473 return false; 474 } 475 try { 476 iframe.contentWindow.postMessage(payload, getIframeOrigin()); 477 return true; 478 } catch (e) { 479 return false; 480 } 481 } 482 483 function setComposerDisabled(disabled) { 484 composerDisabled = !!disabled; 485 if (submitBtn) { 486 submitBtn.disabled = composerDisabled; 487 } 488 if (composer) { 489 composer.setAttribute('aria-disabled', composerDisabled ? 'true' : 'false'); 490 composer.setAttribute('contenteditable', composerDisabled ? 'false' : 'true'); 491 } 492 } 493 494 function composerText() { 495 return composer ? (composer.textContent || '').trim() : ''; 496 } 497 498 function clearComposer() { 499 if (composer) { 500 composer.innerHTML = ''; 501 } 502 } 503 504 function focusComposer() { 505 if (!composer || composerDisabled) { 506 return; 507 } 508 try { 509 composer.focus({ preventScroll: true }); 510 } catch (e) { 511 composer.focus(); 512 } 513 } 514 515 function loadChatIframe(q) { 516 if (!iframe) { 517 return; 518 } 519 iframe.src = buildChatIframeSrc(q); 520 bindIframeMarketingSync(iframe); 521 } 522 523 function showDisclosureModal() { 524 var modal = global.document.getElementById('mo-guide-disclosure'); 525 if (!modal) { 526 return; 527 } 528 modal.hidden = false; 529 global.document.documentElement.classList.add('mo-guide-disclosure-open'); 530 if (global.document.body) { 531 global.document.body.classList.add('mo-guide-disclosure-open'); 532 } 533 var rootOpen = global.document.getElementById('mo-guide-root'); 534 if (rootOpen) { 535 rootOpen.classList.add('mo-guide-disclosure-open'); 536 } 537 } 538 539 function hideDisclosureModal() { 540 var modal = global.document.getElementById('mo-guide-disclosure'); 541 if (!modal) { 542 return; 543 } 544 modal.hidden = true; 545 global.document.documentElement.classList.remove('mo-guide-disclosure-open'); 546 if (global.document.body) { 547 global.document.body.classList.remove('mo-guide-disclosure-open'); 548 } 549 var rootClose = global.document.getElementById('mo-guide-root'); 550 if (rootClose) { 551 rootClose.classList.remove('mo-guide-disclosure-open'); 552 } 553 } 554 555 function initDisclosureGate(onAccepted) { 556 if (readDisclosureCookie() === '1') { 557 if (typeof onAccepted === 'function') { 558 onAccepted(); 559 } 560 return; 561 } 562 showDisclosureModal(); 563 var agreeBtn = global.document.getElementById('mo-guide-disclosure-agree'); 564 if (agreeBtn) { 565 agreeBtn.addEventListener('click', function () { 566 persistDisclosureAccepted(); 567 hideDisclosureModal(); 568 postToIframe({ type: 'mo_guide_disclosure_result', accepted: true }); 569 if (typeof onAccepted === 'function') { 570 onAccepted(); 571 } 572 }, { once: true }); 573 } 574 } 575 576 function sendComposerMessage() { 577 if (composerDisabled) { 578 return; 579 } 580 var text = composerText(); 581 if (!text) { 582 return; 583 } 584 if (postToIframe({ type: 'mo_guide_send_message', text: text })) { 585 clearComposer(); 586 } 587 } 588 589 if (chatForm) { 590 chatForm.addEventListener('submit', function (e) { 591 e.preventDefault(); 592 sendComposerMessage(); 593 }); 594 } 595 596 if (composer) { 597 composer.addEventListener('keydown', function (e) { 598 if (e.key === 'Enter' && !e.shiftKey) { 599 e.preventDefault(); 600 sendComposerMessage(); 601 } 602 }); 603 } 604 605 bindHeightListener(iframe, function (event, data) { 606 if (data.type === 'mo_guide_scroll_bottom') { 607 scrollOceanParentToBottom(data.behavior); 608 return; 609 } 610 if (data.type === 'mo_guide_scroll_user_anchor') { 611 scrollOceanParentToUserAnchor(data); 612 return; 613 } 614 if (data.type === 'mo_guide_chat_state') { 615 setComposerDisabled(!!data.composerDisabled || !!data.loading); 616 return; 617 } 618 if (data.type === 'mo_guide_focus_composer') { 619 focusComposer(); 620 return; 621 } 622 if (data.type === 'mo_guide_disclosure_request') { 623 if (readDisclosureCookie() === '1') { 624 postToIframe({ type: 'mo_guide_disclosure_result', accepted: true }); 625 } 626 } 627 }); 628 629 var q = getQueryParam(); 630 if (!q) { 631 goToLandingPage(); 632 return; 633 } 634 635 initDisclosureGate(function () { 636 loadChatIframe(q); 637 onViewportChange(); 638 }); 639 } 640
641 function init() { 642 applyParentCss(); 643 644 if (global.document.getElementById('dailyom-guide-chat-frame')) { 645 initChatParent(); 646 return; 647 } 648 if (global.document.getElementById('dailyom-guide-landing-frame')) { 649 initLandingParent(); 650 } 651 } 652 653 global.MoGuideParentConfig = cfg; 654 global.MoGuideParent = { 655 config: cfg, 656 getLandingPageUrl: getLandingPageUrl, 657 getChatPageUrl: getChatPageUrl, 658 getIframeOrigin: getIframeOrigin, 659 buildChatPageUrl: buildChatPageUrl, 660 buildLandingIframeSrc: buildLandingIframeSrc, 661 buildChatIframeSrc: buildChatIframeSrc, 662 goToChatPage: goToChatPage, 663 goToLandingPage: goToLandingPage, 664 navigateTop: navigateTop, 665 applyNavLinks: applyNavLinks, 666 bindHeightListener: bindHeightListener, 667 syncSiteHeaderOffset: syncSiteHeaderOffset 668 }; 669 670 if (global.document.readyState === 'loading') { 671 global.document.addEventListener('DOMContentLoaded', init); 672 } else { 673 init(); 674 } 675})(typeof window !== 'undefined' ? window : this);
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.