1(function () { 2 // Initialize global resources only once 3 if (!window._oonoInitialized) { 4 window._oonoInitialized = true; 5 6 // Create in-memory storage fallback 7 const memoryStorage = {}; 8 9 // Storage wrapper to handle cases where localStorage is denied 10 window._oonoStorageWrapper = { 11 getItem: function(key) { 12 try { 13 return localStorage.getItem(key); 14 } catch (e) { 15 return memoryStorage[key] || null; 16 } 17 }, 18 setItem: function(key, value) { 19 try { 20 localStorage.setItem(key, value); 21 } catch (error) {} 22 finally { 23 memoryStorage[key] = value; 24 } 25 }, 26 removeItem: function(key) { 27 try { 28 localStorage.removeItem(key); 29 } catch (e) { 30 delete memoryStorage[key]; 31 } 32 } 33 }; 34 35 // Initialize global variables 36 if (typeof window._oonoStoriesInQuestion === 'undefined') { 37 window._oonoStoriesInQuestion = []; 38 } 39 40 // Global constants 41 window._oonoIsProd = true; 42 window._oonoGetJsonCUrl = () => 43 `https://media${window._oonoIsProd ? "-live" : ""}.oono.ai/carousal`; 44 45 // Global functions 46 window._oonoLoadSocketIO = function() { 47 return new Promise((resolve, reject) => { 48 const script = document.createElement("script"); 49 script.src = "https://cdn.socket.io/4.8.1/socket.io.min.js"; 50 script.onload = () => { 51 resolve(); 52 }; 53 script.onerror = () => { 54 reject("Failed to load Socket.IO script"); 55 }; 56 document.head.appendChild(script); 57 }); 58 }; 59 60 window._oonoInitSocketIO = async function(url) { 61 if (window._oonoSocket && window._oonoSocket.connected) { 62 return window._oonoSocket; 63 } 64 65 try { 66 await window._oonoLoadSocketIO(); 67 window._oonoSocket = io(url); 68 69 window._oonoSocket.on("connect", () => { 70 console.log("Connected to the server"); 71 }); 72 window._oonoSocket.on("disconnect", () => { 73 console.log("Disconnected from the server"); 74 }); 75 return window._oonoSocket; 76 } catch (error) { 77 console.error("Error initializing Socket.IO:", error); 78 throw error; 79 } 80 }; 81 82 window._oonoEmitEvent = async function(url, event, data) { 83 try { 84 console.log("action: ", data.action) 85 const socket = await window._oonoInitSocketIO(url); 86 socket.emit(event, data); 87 } catch (error) { 88 console.error("Error emitting event:", error); 89 } 90 }; 91 92 window._oonoGetCountry = async function() { 93 try { 94 const countryValue = window._oonoStorageWrapper.getItem("country"); 95 if (countryValue && countryValue != "undefined") return countryValue; 96 const response = await fetch("https://ipinfo.io/json"); 97 const data = await response.json(); 98 window._oonoStorageWrapper.setItem("country", data.country); 99 return data.country; 100 } catch (error) { 101 console.error("Error fetching location data:", error); 102 } 103 }; 104 105 window._oonoGetDeviceType = function() { 106 return /Android|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i.test( 107 navigator.userAgent 108 ) 109 ? "mobile" 110 : "web"; 111 }; 112 113 window._oonoGetCollection = function(collectionId) { 114 const colData = JSON.parse(window._oonoStorageWrapper.getItem(`data_${collectionId}`)) || null; 115 return colData; 116 }; 117 118 window._oonoGetCollectionId = function(collectionId) { 119 const colData = JSON.parse(window._oonoStorageWrapper.getItem(`jsonData_${collectionId}`)) || null; 120 return colData?._id; 121 }; 122 123 // Helper function to get collection code and name for URL 124 window._oonoGetCollectionCodeAndName = function(collectionId) { 125 const colData = JSON.parse(window._oonoStorageWrapper.getItem(`jsonData_${collectionId}`)) || null; 126 if (colData?.code) { 127 return { 128 code: colData.code, 129 name: colData.name || '' 130 }; 131 } 132 return null; 133 }; 134 135 // Helper function to set URL parameters based on collection type 136 window._oonoSetCollectionUrlParams = function(url, collectionId, storyNumber = 0) { 137 const collectionData = window._oonoGetCollectionCodeAndName(collectionId); 138 139 if (collectionData) { 140 const formattedName = collectionData.name.replace(/\s+/g, '-'); 141 // Clear existing parameters first 142 url.searchParams.delete("c"); 143 url.searchParams.delete("story"); 144 url.searchParams.delete("oono"); 145 // Set parameters in correct order: c first, then story 146 url.searchParams.set("c", `${collectionData.code}-${formattedName}`); 147 url.searchParams.set("story", storyNumber.toString()); 148 } else { 149 // Old format: oono={collectionId}&story={storyNumber} 150 // Clear existing parameters first 151 url.searchParams.delete("oono"); 152 url.searchParams.delete("story"); 153 url.searchParams.delete("c"); 154 // Set parameters in correct order: oono first, then story 155 url.searchParams.set("oono", collectionId); 156 url.searchParams.set("story", storyNumber.toString()); 157 } 158 }; 159 160 // Helper function to get collection ID from URL (supports both formats) 161 window._oonoGetCollectionIdFromUrl = function(url) { 162 // Check new format first 163 const newFormat = url.searchParams.get("c"); 164 if (newFormat) { 165 const code = newFormat.split('-')[0]; // Extract code part 166 // Find collection by code by checking all stored collection data 167 try { 168 const allKeys = Object.keys(localStorage || {}).filter(key => key.startsWith('jsonData_')); 169 for (const key of allKeys) { 170 try { 171 const collectionId = key.replace('jsonData_', ''); 172 const colData = JSON.parse(window._oonoStorageWrapper.getItem(`jsonData_${collectionId}`)) || null; 173 if (colData?.code === code) { 174 return collectionId; 175 } 176 } catch (e) { 177 // Skip invalid JSON 178 } 179 } 180 } catch (e) { 181 console.warn('Error accessing localStorage:', e); 182 } 183 } 184 185 // Fallback to old format 186 return url.searchParams.get("oono"); 187 }; 188 189 // Helper function to get story number from URL 190 window._oonoGetStoryNumberFromUrl = function(url) { 191 return url.searchParams.get("story"); 192 }; 193 } 194 195 const storageWrapper = window._oonoStorageWrapper; 196 const isProd = window._oonoIsProd; 197 const getJsonCUrl = window._oonoGetJsonCUrl; 198 const loadSocketIO = window._oonoLoadSocketIO; 199 const initSocketIO = window._oonoInitSocketIO; 200 const EmitEvent = window._oonoEmitEvent; 201 const getCountry = window._oonoGetCountry; 202 const getDeviceType = window._oonoGetDeviceType; 203 const getCollection = window._oonoGetCollection; 204 const getCollectionId = window._oonoGetCollectionId; 205 const getCollectionCodeAndName = window._oonoGetCollectionCodeAndName; 206 const setCollectionUrlParams = window._oonoSetCollectionUrlParams; 207 const getCollectionIdFromUrl = window._oonoGetCollectionIdFromUrl; 208 const getStoryNumberFromUrl = window._oonoGetStoryNumberFromUrl; 209 window._oonoFirstClick = window._oonoFirstClick || false; 210 211 function initOonoStories() { 212 // Prevent multiple initializations especially on mobile 213 if (window._oonoStoriesInitialized) { 214 return; 215 } 216 window._oonoStoriesInitialized = true; 217 218 const scriptTag = 219 document.currentScript || 220 Array.from(document.getElementsByTagName("script")).pop();
221 const urlParams = new URLSearchParams(new URL(scriptTag.src).search); 222 const brandId = urlParams.get("brandId"); 223 const url = new URL(window.location); 224 const collectionSlug = getCollectionIdFromUrl(url); 225 if (collectionSlug && brandId) { 226 fetch(`${getJsonCUrl()}/${brandId}.json`) 227 .then((response) => response.json()) 228 .then((data) => { 229 data?.collections?.forEach((id) => { 230 if (id == collectionSlug) { 231 const newConfig = { 232 collectionId: id, 233 isProd: isProd, 234 }; 235 const newDiv = document.createElement("div"); 236 newDiv.id = "oono-stories-container"; 237 newDiv.style.display = "flex"; 238 newDiv.style.overflow = "auto"; 239 initializeStories(newDiv, newConfig); 240 document.body.appendChild(newDiv); 241 } 242 }); 243 }); 244 } 245 document.querySelectorAll('div[id^="oono-stories"]').forEach((div) => { 246 if (!div.getAttribute("data-initialized")) { 247 div.setAttribute("data-initialized", "true"); 248 249 const config = JSON.parse(div.getAttribute("data-config")); 250 251 const styleElement = document.createElement("style"); 252 styleElement.textContent = ` 253 @keyframes shimmer { 254 0% { background-position: -200% 0; } 255 100% { background-position: 200% 0; } 256 } 257 258 .skeleton-loader { 259 display: block; 260 aspect-ratio: 9 / 16; 261 height: 400px; 262 background: linear-gradient(90deg, #e0e0e0 25%, #f5f5f5 50%, #e0e0e0 75%); 263 background-size: 200% 100%; 264 animation: shimmer 1.5s infinite linear; 265 border-radius: 16px; 266 margin-right: 10px; 267 } 268 269 .skeleton-container { 270 display: flex; 271 } 272 `; 273 document.head.appendChild(styleElement); 274 const skeletonContainer = document.createElement("div"); 275 skeletonContainer.className = "skeleton-container"; 276 const skeletonLoader = document.createElement("div"); 277 skeletonLoader.className = "skeleton-loader"; 278 skeletonContainer.appendChild(skeletonLoader); 279 280 div.appendChild(skeletonContainer); 281 282 const updatedConfig = { 283 ...config, 284 isProd: isProd, 285 }; 286 287 if (!config.carouselId) { 288 initializeStories(div, updatedConfig); 289 } else { 290 let isLoading = true; 291 292 const updateSkeletonVisibility = () => { 293 skeletonContainer.style.display = isLoading ? "flex" : "none"; 294 }; 295 296 updateSkeletonVisibility(); 297 298 fetch(`${getJsonCUrl()}/${config.carouselId}.json`) 299 .then((response) => response.json()) 300 .then((data) => { 301 isLoading = false; 302 updateSkeletonVisibility(); 303 304 if (data?.enabled) { 305 const mainDiv = document.createElement("div"); 306 mainDiv.className = "oono-carousel-container"; 307 mainDiv.style.display = "flex"; 308 mainDiv.style.overflow = "auto"; 309 310 const styleElement = document.createElement("style"); 311 styleElement.textContent = ` 312 .oono-carousel-container { 313 overflow: auto; 314 } 315 .oono-carousel-container::-webkit-scrollbar { 316 display: none; 317 } 318 .oono-carousel-container { 319 -ms-overflow-style: none; 320 scrollbar-width: none; 321 } 322 `; 323 document.head.appendChild(styleElement); 324 div.appendChild(mainDiv); 325 326 if (data.carousalSetting && data.carousalSetting.length > 0) { 327 data.carousalSetting[0].collectionIds.forEach((id) => { 328 const newDiv = document.createElement("div"); 329 newDiv.id = "oono-stories-container"; 330 const newConfig = { 331 ...config, 332 collectionId: id, 333 type: "carousel", 334 height: data.carousalSetting[0].height, 335 brandId: data.carousalSetting[0].brandSlug, 336 brandRealId: data.brand, 337 isProd: isProd, 338 }; 339 newDiv.setAttribute( 340 "data-config", 341 JSON.stringify(newConfig) 342 ); 343 newDiv.setAttribute("data-initialized", "true"); 344 mainDiv.appendChild(newDiv); 345 initializeStories(newDiv, newConfig); 346 }); 347 } 348 } 349 }); 350 } 351 } 352 }); 353 document.querySelectorAll("body *").forEach((el) => { 354 if (!el.childNodes) return;
355 el.childNodes.forEach((node, index) => { 356 if (node.nodeType === Node.TEXT_NODE) { 357 const matches = node.nodeValue.match(/{{oono-([a-z0-9]+)}}/gi); 358 if (matches) { 359 matches.forEach((match) => { 360 const collectionId = match.match(/{{oono-([a-z0-9]+)}}/i)[1]; 361 const newConfig = { 362 collectionId: collectionId, 363 isProd: isProd, 364 type: "link", 365 text: node.nodeValue, // Keep the text so initializeStories handles it 366 index: index, 367 }; 368 const newDiv = document.createElement("div"); 369 newDiv.id = `oono-stories-container-${collectionId}`; 370 newDiv.style.display = "flex"; 371 newDiv.style.overflow = "auto"; 372 initializeStories(newDiv, newConfig); 373 const fragment = document.createDocumentFragment(); 374 fragment.appendChild(newDiv); 375 el.replaceChild(fragment, node); 376 }); 377 } 378 } 379 }); 380 }); 381 382 const anchorTags = document.querySelectorAll('a[href*="oono="], a[href*="c="]'); 383 anchorTags.forEach((anchor) => { 384 const url = new URL(anchor.href); 385 const collectionId = getCollectionIdFromUrl(url); 386 if (collectionId) { 387 const wrapper = document.createElement("span"); 388 wrapper.id = "wrapper"; 389 document.body.appendChild(wrapper); 390 anchor.id = "anchor"; 391 initializeStories(wrapper, { 392 type: "anchor", 393 collectionId, 394 isProd: isProd, 395 anchor: anchor, 396 }); 397 } 398 }); 399 } 400 401function initializeStories( 402 container, 403 { 404 collectionId, 405 brandId, 406 position, 407 type, 408 positionType, 409 style, 410 index, 411 height, 412 text, 413 isProd, 414 anchor, 415 brandRealId, 416 } 417) { 418 console.log("br", brandRealId); 419 if (!container.shadowRoot) { 420 const shadowRoot = container.attachShadow({ mode: "open" }); 421 422 const getAWSMediaURL = (url) => { 423 return url 424 ? `https://media${isProd ? "-live" : ""}.oono.ai/uploads/` + url 425 : ""; 426 }; 427 const getJsonUrl = () => 428 `https://media${isProd ? "-live" : ""}.oono.ai/meta_data`; 429 const backendUrl = isProd 430 ? "https://apis.oono.ai" 431 : "https://staging-apis-v2.oono.ai"; 432 const webStoriesUrl = isProd 433 ? "https://oono.ai" 434 : "https://staging-brand.oono.ai"; 435 436 const generateUniqueId = () => { 437 const uniqueId = Array(6) 438 .fill(0) 439 .map(() => Math.random().toString(36).substring(2)) 440 .join("") 441 .substring(0, 36); 442 storageWrapper.setItem("uniqueId", uniqueId); 443 }; 444 445 if (!storageWrapper.getItem("uniqueId")) { 446 generateUniqueId(); 447 } 448 449 EmitEvent(backendUrl, "stories-stats", { 450 collectionId: getCollectionId(collectionId), 451 brandId: brandRealId, 452 identifier: storageWrapper.getItem("uniqueId"), 453 action: 8, 454 }); 455 456 shadowRoot.innerHTML = ` 457 <style> 458 ${ 459 type === "carousel" 460 ? ` 461 .oono-carousel-container { 462 display: flex; 463 overflow-x: auto; 464 scroll-behavior: smooth; 465 padding: 20px; 466 height: ${height + height * 0.1}px; 467 } 468 ` 469 : "" 470 } 471 .carousel-item { 472 cursor: pointer; 473 position: relative; 474 flex-shrink: 0; 475 border-radius: 16px; 476 width: 100%; 477 height: ${height + height * 0.05}px; 478 overflow: hidden; 479 transition: transform 0.2s ease-in-out; 480 } 481 .carousel-item img { 482 box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.15); 483 object-fit: cover; 484 border-radius: 16px; 485 height: ${height}px; 486 aspect-ratio: 9/16; 487 } 488 .carousel-item:hover { 489 transform: scale(1.1); 490 } 491 492 .link-click { 493 text-decoration: underline; 494 background-color: transparent; 495 cursor: pointer; 496 } 497 498 .avatar-overlay { 499 position: absolute; 500 bottom: -20px; 501 right: 20px; 502 z-index: 1; 503 left: 50%; 504 transform: translateX(-50%); 505 width: 60px; 506 height: 60px; 507 border-radius: 50%; 508 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); 509 } 510 #playButton { 511 z-index: 2147483647; 512 padding: 10px 20px; 513 font-size: 16px; 514 color: ${style?.labelColor ? style.labelColor : "#fff"}; 515 width: ${style?.width ? style.width : "auto"}; 516 height: ${style?.height ? style.height : "auto"}; 517 border: ${style?.border ? style.border : "none"}; 518 border-radius: ${style?.borderRadius ? style.borderRadius : "30px"}; 519 cursor: pointer; 520 transition: background-color 0.3s, transform 0.3s; 521 background-color: ${style?.background ? style.background : "#007BFF"}; 522 } 523 #playButton:active, #Widget:active { 524 transform: scale(0.98); 525 } 526 #storyModal { 527 z-index: -1; 528 display: flex; 529 align-items: center; 530 justify-content: center; 531 opacity: -1; 532 } 533 #Widget { 534 border: none; 535 background-color: #20E5F9; 536 cursor: pointer; 537 } 538 #oono-stories-container { 539 position: relative; 540 } 541 #imgDiv { 542 z-index: 214748; 543 background-color: white; 544 border-radius: 50%; 545 width: 65px; 546 display: flex; 547 justify-content: center; 548 align-items: center; 549 height: 65px; 550 ${position === "top-right" ? "top: 50px; right: 50px;" : ""} 551 ${position === "top-left" ? "top: 50px; left: 50px;" : ""} 552 ${position === "bottom-right" ? "bottom: 50px; right: 50px;" : ""} 553 ${position === "bottom-left" ? "bottom: 50px; left: 50px;" : ""} 554 position: ${ 555 positionType === "float" 556 ? "fixed" 557 : positionType === "fixed" 558 ? "static" 559 : "absolute" 560 }; 561 } 562 .lightbox { 563 z-index: 2147483647; 564 display: none; 565 position: fixed; 566 top: 0; 567 left: 0; 568 width: 100%; 569 height: 100%; 570 background-color: rgba(0, 0, 0, 0.8); 571 align-items: center; 572 justify-content: center; 573 visibility: visible; 574 opacity: 1; 575 } 576 amp-story-player.my-player { 577 height: 100vh !important; 578 width: 100vw !important; 579 overflow: hidden !important; 580 } 581 @media (max-width: 500px) { 582 amp-story-player.my-player { 583 height: 100% !important; 584 } 585 } 586 #imgDiv img { 587 cursor: pointer; 588 border-radius: 50%; 589 } 590 #ring { 591 z-index: 214748; 592 position: absolute; 593 cursor: pointer; 594 width: 70px; 595 height: 70px; 596 display: flex; 597 justify-content: center; 598 align-items: center; 599 border-radius: 50%; 600 background: conic-gradient(from 0deg, #ff8a00, #e52e71, #9b51e0, #4a00e0, #ff8a00); 601 ${position === "top-right" ? "top: 48px; right: 48px;" : ""} 602 ${position === "top-left" ? "top: 48px; left: 48px;" : ""} 603 ${position === "bottom-right" ? "bottom: 48px; right: 48px;" : ""} 604 ${position === "bottom-left" ? "bottom: 48px; left: 48px;" : ""} 605 position: ${ 606 positionType === "float" 607 ? "fixed" 608 : positionType === "fixed" 609 ? "static" 610 : "absolute" 611 }; 612 } 613 #playerInitialize { 614 width: ${style?.width ? style.width : "350px"}; 615 height: ${style?.height ? style.height : "550px"}; 616 cursor: pointer; 617 overflow: hidden; 618 position: relative; 619 z-index: 9999999 !important; 620 } 621 622 .progress-bar-container { 623 position: absolute; 624 top: 10px; 625 left: 10px; 626 right: 10px; 627 display: flex; 628 gap: 5px; 629 } 630 .progress-bar { 631 flex: 1; 632 height: 4px; 633 background: rgba(131, 128, 128, 0.5); 634 opacity: 0.5; 635 border-radius: 4px; 636 } 637 .progress-bar1 { 638 flex: 1; 639 height: 4px; 640 box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); 641 background: white; 642 border-radius: 4px; 643 } 644 .inPage-player { 645 z-index: 100; 646 } 647 #no-stories { 648 width: 100vw; 649 background-color: #f5f5f5; 650 height: 100vh; 651 overflow: hidden !important; 652 z-index: 1222221; 653 position: absolute; 654 top: 0; 655 display: none; 656 align-items: center; 657 justify-content: center; 658 flex-direction: column; 659 font-family: Arial, sans-serif; 660 } 661 .image-container { 662 position: relative; 663 width: ${style?.width ? style.width : "198px"}; 664 height: ${style?.width ? style.height : "368px"}; 665 aspect-ratio: 9/16; 666 display: none; 667 overflow: hidden; 668 transition: transform 0.2s ease-in-out; 669 border-radius: ${style?.borderRadius ? style.borderRadius : "8px"}; 670 border: 1px solid rgb(236, 234, 234); 671 } 672 673 .image-container:hover { 674 transform: scale(1.03); 675 } 676 677 #collectionImage { 678 width: 100%; 679 height: 100%; 680 cursor: pointer; 681 overflow: hidden; 682 position: relative; 683 } 684 .image-container img { 685 width: 100%; 686 height: 100%; 687 object-fit: contain; 688 transition: transform 0.2s ease-in-out; 689 } 690 691 692 .image-container:hover #collectionImage img { 693 transform: scale(1.02); 694 } 695 #no-stories a { 696 font-family: Arial, sans-serif; 697 font-size: 20px; 698 text-decoration: none; 699 } 700 @media (max-width: 500px) { 701 #no-stories h2, #no-stories a { 702 font-size: 1.3em; 703 text-align: center; 704 } 705 } 706 #imgDivMain { 707 cursor: pointer; 708 } 709 </style> 710 ${ 711 type === "button" 712 ? `<div id="playButtonDiv"><button id="playButton">${ 713 style?.label ? style?.label : "Open Collection" 714 }</button></div>` 715 : "" 716 } 717 ${ 718 type === "floating" 719 ? ` 720 <div id="imgDivMain"> 721 <div id="ring"></div> 722 <div id="imgDiv"> 723 <img src="${backendUrl}/media/avatar/default.png" width="50px" height="50px" /> 724 </div> 725 </div>` 726 : "" 727 } 728 ${ 729 type === "inPage" 730 ? ` 731 <div class = "inPage-loader-container"> 732 <div class="image-container"> 733 <div id="collectionImage"></div> 734 <div class="progress-bar-container"></div> 735 </div> 736 </div>` 737 : "" 738 } 739 <div id="storyModal" class="lightbox"></div> 740 <div id="no-stories"> 741 <img width="100px" height="100px" src="${backendUrl}/media/avatar/default.png" /> 742 <h2>oono Collection is not available on the Page.</h2> 743 <a href="${webStoriesUrl}/${brandId}" target="_blank">Click here to see on oono</a> 744 </div> 745 ${type !== "link" ? `<div class="oono-carousel-container"></div> ` : ""} 746 ${ 747 type === "link" 748 ? `<p id="paragraph-${index}" class="interactive-text minimalist"></p>` 749 : "" 750 } 751 `; 752 753 const ampScript = document.createElement("script"); 754 ampScript.async = true; 755 ampScript.src = "https://cdn.ampproject.org/v0.js"; 756 shadowRoot.appendChild(ampScript); 757 758 const ampStoryPlayerScript = document.createElement("script"); 759 ampStoryPlayerScript.async = true; 760 ampStoryPlayerScript.setAttribute("custom-element", "amp-story-player"); 761 ampStoryPlayerScript.src = 762 "https://cdn.ampproject.org/v0/amp-story-player-0.1.js"; 763 shadowRoot.appendChild(ampStoryPlayerScript); 764 765 const ampStoryPlayerLink = document.createElement("link"); 766 ampStoryPlayerLink.href = 767 "https://cdn.ampproject.org/amp-story-player-v0.css"; 768 ampStoryPlayerLink.rel = "stylesheet"; 769 ampStoryPlayerLink.type = "text/css"; 770 shadowRoot.appendChild(ampStoryPlayerLink); 771 772 function updateStoryCount() { 773 let data = {}; 774 try { 775 const stored = storageWrapper.getItem("storyClipsCount"); 776 data = stored ? JSON.parse(stored) : {}; 777 } catch (e) { 778 console.warn("Failed to parse storyClipsCount:", e); 779 data = {}; 780 } 781 782 let seenStories = {}; 783 try { 784 const getCount = storageWrapper.getItem("seenStories"); 785 seenStories = getCount ? JSON.parse(getCount) : {}; 786 } catch (e) { 787 console.warn("Failed to parse seenStories:", e); 788 } 789 790 const collectionCount = data[collectionId] || 0; 791 const storyCount = seenStories?.[collectionId]?.length || 0; 792 const res = storyCount > 0 ? collectionCount - storyCount : collectionCount; 793 794 const oldStyle = shadowRoot.querySelector("style[data-type='story-badge']"); 795 if (oldStyle) oldStyle.remove(); 796 797 const style = document.createElement("style"); 798 style.setAttribute("data-type", "story-badge"); 799 style.textContent = ` 800 #imgDiv::after { 801 content: "${isNaN(res) || res === undefined ? 0 : Math.max(0, res)}"; 802 font-size: 12px; 803 display: flex; 804 justify-content: center; 805 align-items: center; 806 color: white; 807 position: absolute; 808 top: -5px; 809 right: 0;
810 width: 20px; 811 height: 20px; 812 background-color: ${res > 0 ? "red" : "#bdbdbd"}; 813 border-radius: 50%; 814 }`; 815 816 shadowRoot.appendChild(style); 817 } 818 819 const containers = shadowRoot.querySelector(".oono-carousel-container"); 820 821 // function toast() { 822 // const url = new URL(window.location); 823 // url.searchParams.delete('oono'); 824 // url.searchParams.delete('story'); 825 // window.history.pushState({}, '', url.href); 826 // const toast = document.createElement('div'); 827 // toast.style.position = 'fixed'; 828 // toast.style.top = '20px'; 829 // toast.style.left = '50%'; 830 // toast.style.transform = 'translateX(-50%)'; 831 // toast.style.backgroundColor = '#ff4d4d'; 832 // toast.style.color = '#fff'; 833 // toast.style.padding = '15px 30px'; 834 // toast.style.borderRadius = '8px'; 835 // toast.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.2)'; 836 // toast.style.zIndex = '2147483647'; 837 // toast.style.fontSize = '16px'; 838 // toast.style.fontWeight = 'bold'; 839 // toast.style.textAlign = 'center'; 840 // toast.innerText = 'No stories available'; 841 // document.body.appendChild(toast); 842 843 // setTimeout(() => { 844 // toast.style.transition = 'opacity 0.5s'; 845 // toast.style.opacity = '0'; 846 // setTimeout(() => { 847 // document.body.removeChild(toast); 848 // }, 500); 849 // }, 3000); 850 // } 851 852 // Create a style element and append it to the head 853 // if (type === "inPage") { 854 855 let brandSlug; 856 fetch(`${getJsonUrl()}/${collectionId}.json`) 857 .then((response) => response.json()) 858 .then((data) => { 859 brandSlug = data?.brandSlug; 860 861 if (data?.storiesCount > 1 && type === "inPage") { 862 const progressBars = shadowRoot.querySelector( 863 ".progress-bar-container" 864 ); 865 866 for (let i = 0; i < Math.min(data?.storiesCount, 10); i++) { 867 const progressBar = document.createElement("div"); 868 if (i === 0) { 869 progressBar.className = "progress-bar1"; 870 } else { 871 progressBar.className = "progress-bar"; 872 } 873 progressBars.appendChild(progressBar); 874 } 875 } 876 if (type === "link") { 877 const paragraph = shadowRoot.querySelector(`#paragraph-${index}`); 878 let textWithLinks = text; 879 if (textWithLinks) { 880 textWithLinks = textWithLinks.replace( 881 /{{oono-([^}]+)}}/g, 882 `<span class="link-click">${data?.name}</span>` 883 ); 884 paragraph.innerHTML = textWithLinks; 885 } 886 } 887 888 storageWrapper.setItem(`jsonData_${collectionId}`, JSON.stringify(data)); 889 const storyModal = container.shadowRoot.querySelector("#storyModal"); 890 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 891 const lastStoryPage = lastStory[collectionId] || "page-1"; 892 const storyClipsCounts = 893 JSON.parse(storageWrapper.getItem("storyClipsCount")) || {}; 894 if (data) { 895 storyClipsCounts[collectionId] = 896 data.storyClipsCount || data.storiesCount || 0; 897 } else { 898 storyClipsCounts[collectionId] = 0; 899 } 900 storageWrapper.setItem( 901 "storyClipsCount", 902 JSON.stringify(storyClipsCounts) 903 ); 904 updateStoryCount(); 905 const url = new URL(window.location); 906 const story = getStoryNumberFromUrl(url); 907 const collection = getCollectionIdFromUrl(url); 908 let current; 909 if (collection === collectionId && story) { 910 storageWrapper.setItem( 911 "lastStory", 912 JSON.stringify({ ...lastStory, [collectionId]: `page-${story}` }) 913 ); 914 current = `page-${story}`; 915 } else { 916 current = lastStoryPage; 917 }
918 async function renderStoryModal(collection) { 919 if (!storyModal) return; 920 const response = await fetch( 921 `${backendUrl}/api/public/stories-collection?collectionId=${collection}`, 922 { 923 method: "GET", 924 headers: { 925 "Content-Type": "application/json", 926 "app-token": 927 "9f8e7d6c5b4a3e2f1a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e7f", 928 }, 929 } 930 ); 931 const data = await response.json(); 932 window._oonoStoriesInQuestion = data?.data[0].stories; 933 storageWrapper.setItem( 934 `data_${data?.data[0].collectionId}`, 935 JSON.stringify(data?.data[0]) 936 ); 937 const uniqueId = storageWrapper.getItem("uniqueId"); 938 939 // const playerInitialize = container.shadowRoot.querySelector("#playerInitialize"); 940 // if(playerInitialize){ 941 // playerInitialize.innerHTML = ` 942 // <amp-story-player class="inPage-player" height="${style?.height ? style.heigh: '550'}" width="${ 943 // style?.width ? style.width : '350' 944 // }" layout="fixed"> 945 // ${filteredCollections 946 // .map( 947 // (collection) => ` 948 // <a href="${webStoriesUrl}/new-amp?brandId=${brandId}&collection=${collection._id}&brand=${collection?.brand}"></a> 949 // ` 950 // .join("")} 951 // </amp-story-player>`; 952 // } 953 954 const url = new URL(window.location); 955 const currentStory = getStoryNumberFromUrl(url); 956 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 957 const lastStoryPage = lastStory[collectionId] || "page-1"; 958 959 const storyToShow = currentStory ? `page-${currentStory}` : lastStoryPage; 960 961 storyModal.innerHTML = ` 962 <amp-story-player class="my-player" height="100vh" width="100vw" layout="fixed"> 963 <script type="application/json"> 964 { 965 "controls": [ 966 { 967 "name": "close", 968 "position": "end" 969 } 970 ] 971 } 972 </script> 973 ${data?.data 974 .map( 975 (collection) => ` 976 <a href="${webStoriesUrl}/amp?brandId=${ 977 brandSlug || brandId 978 }&collection=${ 979 collection._id 980 }&embed=true&type=${type}&identifier=${uniqueId}#page=${storyToShow}"></a> 981 ` 982 ) 983 .join("")} 984 </amp-story-player> 985 `; 986 } 987 988 // renderStoryModal(data?._id); 989 updateStoryCount(); 990 991 // Preload the player for faster initial loading (with slight delay to not block initial render) 992 // On mobile, delay preloading more to prevent issues 993 const isMobile = getDeviceType() === 'mobile'; 994 const preloadDelay = isMobile ? 2000 : 500; 995 996 setTimeout(() => { 997 preloadPlayer(); 998 }, preloadDelay); 999 if (type === "inPage") { 1000 function LoaderCheck() { 1001 if (!container.shadowRoot) return; 1002 1003 const styleElement = document.createElement("style"); 1004 styleElement.innerHTML = ` 1005 @keyframes shimmer { 1006 0% { background-position: -200px 0; } 1007 100% { background-position: 200px 0; } 1008 } 1009 1010 .skeleton-loader { 1011 position: relative; 1012 width: ${style?.width ? style.width : "198px"}; 1013 height: ${style?.height ? style.height : "368px"}; 1014 aspect-ratio: 9/16; 1015 overflow: hidden; 1016 transition: transform 0.2s ease-in-out; 1017 border-radius: ${ 1018 style?.borderRadius ? style.borderRadius : "8px" 1019 }; 1020 border: 1px solid rgb(236, 234, 234); 1021 background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); 1022 background-size: 200% 100%; 1023 animation: shimmer 1.5s infinite linear; 1024 } 1025 `; 1026 1027 container.shadowRoot.appendChild(styleElement); 1028 const skeletonDiv = document.createElement("div"); 1029 skeletonDiv.className = "skeleton-loader"; 1030 skeletonDiv.id = "skeletonLoader"; 1031 1032 const loaderContainer = container.shadowRoot.querySelector( 1033 ".inPage-loader-container" 1034 ); 1035 1036 if (loaderContainer) { 1037 loaderContainer.appendChild(skeletonDiv); 1038 } 1039 } 1040 1041 function removeSkeletonLoader() { 1042 const skeletonDiv = 1043 container.shadowRoot.querySelector("#skeletonLoader"); 1044 if (skeletonDiv) { 1045 skeletonDiv.remove(); 1046 } 1047 } 1048 1049 LoaderCheck(); 1050 1051 setTimeout(async () => { 1052 EmitEvent(backendUrl, "stories-stats", { 1053 collectionId: getCollectionId(collectionId), 1054 brandId: brandRealId, 1055 identifier: storageWrapper.getItem("uniqueId"), 1056 action: 10, 1057 country: await getCountry(), 1058 deviceType: getDeviceType(), 1059 }); 1060 const data = JSON.parse( 1061 storageWrapper.getItem(`jsonData_${collectionId}`) 1062 ); 1063 const imgDiv = 1064 container.shadowRoot.querySelector("#collectionImage"); 1065 const coverUrl = getAWSMediaURL(data?.cover); 1066 const inPageDiv = 1067 container.shadowRoot.querySelector(".image-container"); 1068 if (inPageDiv) { 1069 inPageDiv.addEventListener("click", async () => { 1070 await EmitEvent(backendUrl, "stories-stats", { 1071 collectionId: getCollectionId(collectionId), 1072 brandId: brandRealId, 1073 identifier: storageWrapper.getItem("uniqueId"), 1074 action: 11, 1075 }); 1076 window._oonoFirstClick = true; 1077 1078 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1079 const lastStoryPage = lastStory[collectionId] || "page-1"; 1080 const storyNumber = (parseInt(lastStoryPage.split("-")[1]) || 1).toString(); 1081 1082 const collectionData = getCollection(collectionId); 1083 const stories = collectionData?.stories; 1084 const storyId = stories?.[parseInt(storyNumber) - 1]?._id 1085 1086 await EmitEvent(backendUrl, "stories-stats", { 1087 collectionId: getCollectionId(collectionId), 1088 brandId: brandRealId, 1089 identifier: storageWrapper.getItem("uniqueId"), 1090 action: 1, 1091 storyId, 1092 country: await getCountry(), 1093 deviceType: getDeviceType(), 1094 }); 1095 1096 startTime = Date.now(); 1097 }); 1098 } 1099 if (coverUrl) { 1100 removeSkeletonLoader(); 1101 inPageDiv.style.display = "block"; 1102 imgDiv.innerHTML = `<img src="${coverUrl}" />`; 1103 } else { 1104 imgDiv.style.display = "none"; 1105 } 1106 }, 1000); 1107 } 1108 1109 const imgDiv = shadowRoot.querySelector("#imgDiv"); 1110 if (type === "button") { 1111 const playButton = shadowRoot.querySelector("#playButton"); 1112 window._oonoFirstClick = true; 1113 playButton?.addEventListener("click", async () => { 1114 await EmitEvent(backendUrl, "stories-stats", { 1115 collectionId: getCollectionId(collectionId), 1116 brandId: brandRealId, 1117 identifier: storageWrapper.getItem("uniqueId"), 1118 action: 11, 1119 }); 1120 1121 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1122 const lastStoryPage = lastStory[collectionId] || "page-1"; 1123 const storyNumber = (parseInt(lastStoryPage.split("-")[1]) || 1).toString(); 1124 1125 const collectionData = getCollection(collectionId); 1126 const stories = collectionData?.stories; 1127 const storyId = stories?.[parseInt(storyNumber) - 1]?._id 1128 1129 await EmitEvent(backendUrl, "stories-stats", { 1130 collectionId: getCollectionId(collectionId), 1131 brandId: brandRealId, 1132 identifier: storageWrapper.getItem("uniqueId"), 1133 action: 1, 1134 storyId, 1135 country: await getCountry(), 1136 deviceType: getDeviceType(), 1137 }); 1138 1139 startTime = Date.now(); 1140 }); 1141 } 1142 imgDiv?.addEventListener("click", async () => { 1143 window._oonoFirstClick = true; 1144 await EmitEvent(backendUrl, "stories-stats", { 1145 collectionId: getCollectionId(collectionId), 1146 brandId: brandRealId, 1147 identifier: storageWrapper.getItem("uniqueId"), 1148 action: 11, 1149 }); 1150 1151 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1152 const lastStoryPage = lastStory[collectionId] || "page-1"; 1153 const storyNumber = (parseInt(lastStoryPage.split("-")[1]) || 1).toString(); 1154 1155 const collectionData = getCollection(collectionId); 1156 const stories = collectionData?.stories; 1157 const storyId = stories?.[parseInt(storyNumber)]?._id 1158 1159 await EmitEvent(backendUrl, "stories-stats", { 1160 collectionId: getCollectionId(collectionId), 1161 brandId: brandRealId, 1162 identifier: storageWrapper.getItem("uniqueId"), 1163 action: 1, 1164 storyId, 1165 country: await getCountry(), 1166 deviceType: getDeviceType(), 1167 }); 1168 startTime = Date.now(); 1169 }); 1170 let startTime = 0; 1171 let currentPageId = ""; 1172 1173 const handleNavigation = async (event) => { 1174 const previousPageId = storageWrapper.getItem("currentPageId"); 1175 const seenStories = 1176 JSON.parse(storageWrapper.getItem("seenStories")) || {}; 1177 const collectionSeenStories = seenStories[collectionId] || []; 1178 if (!collectionSeenStories.includes(event.detail.pageId)) { 1179 collectionSeenStories.push(event.detail.pageId); 1180 seenStories[collectionId] = collectionSeenStories; 1181 storageWrapper.setItem("seenStories", JSON.stringify(seenStories)); 1182 } 1183 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1184 lastStory[collectionId] = event.detail.pageId; 1185 storageWrapper.setItem("lastStory", JSON.stringify(lastStory)); 1186 const currentPageIdNumber = parseInt( 1187 event.detail.pageId.split("-")[1] 1188 ); 1189 storageWrapper.setItem("currentPageId", currentPageIdNumber); 1190 const collections = JSON.parse(storageWrapper.getItem("collection")); 1191 const storyId = collections?.stories[currentPageIdNumber]?._id; 1192 storageWrapper.setItem("storyId", storyId); 1193 let timeSpent = 0; 1194 if (currentPageId !== "") { 1195 const endTime = Date.now(); 1196 timeSpent = (endTime - startTime) / 1000; 1197 } 1198 const timeSpentSeconds = Math.round(timeSpent); 1199 startTime = Date.now(); 1200 currentPageId = currentPageIdNumber; 1201 storageWrapper.setItem("timeSpent", timeSpentSeconds); 1202 1203 const url = new URL(window.location); 1204 if (window._oonoFirstClick) { 1205 const storyNumber = event.detail.pageId.split("-")[1]; 1206 setCollectionUrlParams(url, collectionId, storyNumber); 1207 1208 // Prevent infinite loops by checking if URL actually changed 1209 if (window.location.href !== url.toString()) { 1210 try { 1211 window.history.replaceState({}, "", url.toString()); 1212 } catch (e) { 1213 console.warn('Failed to update URL state:', e); 1214 } 1215 } 1216 } 1217 1218 const coll = getCollectionIdFromUrl(url); 1219 if (coll === collectionId) { 1220 if (currentPageId == previousPageId) { 1221 return; 1222 } 1223 const isForward = currentPageId > previousPageId; 1224 const currentStoryNumber = parseInt(storyNumber); 1225 const collectionData = getCollection(collectionId); 1226 const stories = collectionData?.stories; 1227 const storyId = stories?.[currentStoryNumber]?._id 1228 1229 await EmitEvent(backendUrl, "stories-stats", { 1230 storyId, 1231 collectionId: getCollectionId(collectionId), 1232 brandId: brandRealId, 1233 identifier: storageWrapper.getItem("uniqueId"), 1234 action: isForward ? 3 : 4, 1235 timeSpent: timeSpentSeconds, 1236 storyId, 1237 }); 1238 1239 await EmitEvent(backendUrl, "stories-stats", { 1240 collectionId: getCollectionId(collectionId), 1241 brandId: brandRealId, 1242 identifier: storageWrapper.getItem("uniqueId"), 1243 action: 1, 1244 storyId, 1245 country: await getCountry(), 1246 deviceType: getDeviceType(), 1247 }); 1248 } 1249 }; 1250 const intervalId = setInterval(() => { 1251 let player = shadowRoot.querySelector(".my-player"); 1252 if (player) { 1253 player.addEventListener("storyNavigation", handleNavigation); 1254 clearInterval(intervalId); 1255 } 1256 }, 1000); 1257 1258 // Debounce function to prevent rapid execution 1259 let checkHashTimeout; 1260 const checkHashAndToggleModal = (item) => { 1261 clearTimeout(checkHashTimeout); 1262 checkHashTimeout = setTimeout(() => { 1263 const url = new URL(window.location); 1264 const collection = getCollectionIdFromUrl(url); 1265 const targetCollectionId = item ? item : collectionId; 1266 1267 const isMatch = collection === targetCollectionId; 1268 let isCodeMatch = false;
1269 if (url.searchParams.get("c")) { 1270 const targetCodeData = getCollectionCodeAndName(targetCollectionId); 1271 if (targetCodeData) { 1272 const urlCode = url.searchParams.get("c").split('-')[0]; 1273 isCodeMatch = urlCode === targetCodeData.code; 1274 } 1275 } 1276 1277 if (isMatch || isCodeMatch) { 1278 const lastStory = 1279 JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1280 const lastStoryPage = lastStory[item ?? collectionId] || "page-1"; 1281 if (lastStoryPage) { 1282 setCollectionUrlParams(url, targetCollectionId, lastStoryPage.split("-")[1]); 1283 1284 // Prevent infinite loops by checking if URL actually changed 1285 if (window.location.href !== url.toString()) { 1286 try { 1287 window.history.replaceState({}, "", url.toString()); 1288 } catch (e) { 1289 console.warn('Failed to update URL state:', e); 1290 } 1291 } 1292 } 1293 toggleModal(true); 1294 } 1295 // else if (window.location.hash !== `#oono-embed-${data.collectionId}` && window.location.hash.includes('#oono')) { 1296 // const noStories = container.shadowRoot.querySelector("#no-stories"); 1297 // noStories.style.display = "flex"; 1298 // } 1299 else { 1300 // const noStories = container.shadowRoot.querySelector("#no-stories"); 1301 // noStories.style.display = "none"; 1302 toggleModal(false); 1303 } 1304 }, 100); // 100ms debounce delay 1305 }; 1306 1307 if (containers && type === "carousel") { 1308 [collectionId]?.forEach(async (item) => { 1309 const slideElement = document.createElement("div"); 1310 slideElement.className = "carousel-item"; 1311 const img = document.createElement("img"); 1312 img.src = data?.cover 1313 ? getAWSMediaURL(data.cover) 1314 : `${backendUrl}/media/avatar/default.png`; 1315 img.alt = `Slide`; 1316 if (!data.cover) { 1317 img.style.objectFit = "contain"; 1318 img.style.border = "1px solid #BFBFBF"; 1319 img.style.background = "#BFBFBF"; 1320 } 1321 slideElement.appendChild(img); 1322 1323 EmitEvent(backendUrl, "stories-stats", { 1324 collectionId: getCollectionId(collectionId), 1325 brandId: brandRealId, 1326 identifier: storageWrapper.getItem("uniqueId"), 1327 action: 10, 1328 country: await getCountry(), 1329 deviceType: getDeviceType(), 1330 }); 1331 1332 const progressBarContainer = document.createElement("div"); 1333 progressBarContainer.className = "progress-bar-container"; 1334 slideElement.appendChild(progressBarContainer); 1335 1336 if (data?.storiesCount > 1) { 1337 const progressBarContainer = document.createElement("div"); 1338 progressBarContainer.className = "progress-bar-container"; 1339 slideElement.appendChild(progressBarContainer); 1340 1341 for (let i = 0; i < Math.min(data?.storiesCount, 10); i++) { 1342 const progressBar = document.createElement("div"); 1343 if (i === 0) { 1344 progressBar.className = "progress-bar1"; 1345 } else { 1346 progressBar.className = "progress-bar"; 1347 } 1348 progressBarContainer.appendChild(progressBar); 1349 } 1350 } 1351 1352 // const avatar = document.createElement('img'); 1353 // avatar.src = getAWSMediaURL(data.cover); 1354 // avatar.alt = 'Avatar'; 1355 // avatar.style.width = '80px'; 1356 // avatar.style.height = '80px'; 1357 // avatar.style.borderRadius = '50%'; 1358 // avatar.style.zIndex = 6000000; 1359 // avatar.style.position = 'absolute'; 1360 // avatar.className = 'avatar-overlay'; 1361 // slideElement.appendChild(avatar); 1362 containers.appendChild(slideElement); 1363 slideElement.addEventListener("click", async () => { 1364 await EmitEvent(backendUrl, "stories-stats", { 1365 collectionId: getCollectionId(collectionId), 1366 brandId: brandRealId, 1367 identifier: storageWrapper.getItem("uniqueId"), 1368 action: 11, 1369 }); 1370 window._oonoFirstClick = true; 1371 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1372 const lastStoryPage = lastStory[item] || "page-1"; 1373 const storyNumber = (parseInt(lastStoryPage.split("-")[1]) || 1).toString(); 1374 1375 const collectionData = getCollection(collectionId); 1376 const stories = collectionData?.stories; 1377 const storyId = stories?.[parseInt(storyNumber) - 1]?._id 1378 1379 await EmitEvent(backendUrl, "stories-stats", { 1380 collectionId: getCollectionId(collectionId), 1381 brandId: brandRealId, 1382 identifier: storageWrapper.getItem("uniqueId"), 1383 action: 1, 1384 storyId, 1385 country: await getCountry(), 1386 deviceType: getDeviceType(), 1387 }); 1388 1389 const url = new URL(window.location); 1390 setCollectionUrlParams(url, item, storyNumber); 1391 1392 // Prevent infinite loops by checking if URL actually changed 1393 if (window.location.href !== url.toString()) { 1394 try { 1395 window.history.replaceState({}, "", url.toString()); 1396 } catch (e) { 1397 console.warn('Failed to update URL state:', e); 1398 } 1399 } 1400 checkHashAndToggleModal(item); 1401 startTime = Date.now(); 1402 }); 1403 }); 1404 } 1405 1406 if (anchor) { 1407 anchor.addEventListener("click", async (event) => { 1408 event.preventDefault(); 1409 if (collectionId === data.collectionId) { 1410 await EmitEvent(backendUrl, "stories-stats", { 1411 collectionId: getCollectionId(collectionId), 1412 brandId: brandRealId, 1413 identifier: storageWrapper.getItem("uniqueId"), 1414 action: 11, 1415 }); 1416 window._oonoFirstClick = true; 1417 1418 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1419 const lastStoryPage = lastStory[collectionId] || "page-1"; 1420 const storyNumber = (parseInt(lastStoryPage.split("-")[1]) || 1).toString(); 1421 1422 const collectionData = getCollection(collectionId); 1423 const stories = collectionData?.stories; 1424 const storyId = stories?.[parseInt(storyNumber) - 1]?._id 1425 1426 await EmitEvent(backendUrl, "stories-stats", { 1427 collectionId: getCollectionId(collectionId), 1428 brandId: brandRealId, 1429 identifier: storageWrapper.getItem("uniqueId"), 1430 action: 1, 1431 storyId, 1432 country: await getCountry(), 1433 deviceType: getDeviceType(), 1434 }); 1435 const url = new URL(window.location); 1436 setCollectionUrlParams(url, collectionId, storyNumber); 1437 1438 // Prevent infinite loops by checking if URL actually changed 1439 if (window.location.href !== url.toString()) { 1440 try { 1441 window.history.replaceState({}, "", url.toString()); 1442 } catch (e) { 1443 console.warn('Failed to update URL state:', e); 1444 } 1445 } 1446 checkHashAndToggleModal(); 1447 startTime = Date.now(); 1448 } 1449 }); 1450 } 1451 1452 [ 1453 "#playButton", 1454 "#imgDiv", 1455 ".image-container", 1456 ".link-click", 1457 // "#playerInitialize", 1458 ].forEach((id) => { 1459 const el = shadowRoot.querySelector(id); 1460 el && 1461 el.addEventListener("click", (event) => { 1462 event.preventDefault(); 1463 if (collectionId === data.collectionId) { 1464 if (window.self !== window.top) { 1465 toggleModal(true); 1466 } else { 1467 const url = new URL(window.location); 1468 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1469 const lastStoryPage = lastStory[collectionId] || "page-1"; 1470 const storyNumber = (parseInt(lastStoryPage.split("-")[1]) || 1).toString(); 1471 setCollectionUrlParams(url, collectionId, storyNumber); 1472 1473 // Prevent infinite loops by checking if URL actually changed 1474 if (window.location.href !== url.toString()) { 1475 try { 1476 window.history.replaceState({}, "", url.toString()); 1477 } catch (e) { 1478 console.warn('Failed to update URL state:', e); 1479 } 1480 } 1481 checkHashAndToggleModal(); 1482 } 1483 } 1484 }); 1485 }); 1486 1487 // Prevent multiple event listeners 1488 if (!window._oonoHashChangeListenerAdded) { 1489 window._oonoHashChangeListenerAdded = true; 1490 window.addEventListener("hashchange", checkHashAndToggleModal); 1491 } 1492 checkHashAndToggleModal(); 1493 1494 function toggleModal(show) { 1495 const storyModal = container.shadowRoot.querySelector("#storyModal"); 1496 // const filter = JSON.parse(localStorage.getItem(`filterCollection-${collectionId}`)); 1497 // if (filter.length > 0) { 1498 if (show) { 1499 const existingPlayer = shadowRoot.querySelector(".my-player"); 1500 const isPreloaded = existingPlayer && existingPlayer.getAttribute('data-preloaded') === 'true'; 1501 1502 // Check if we need to update the story URL (for URL changes) 1503 const url = new URL(window.location); 1504 const currentStory = getStoryNumberFromUrl(url); 1505 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1506 const lastStoryPage = lastStory[collectionId] || "page-1"; 1507 const storyToShow = currentStory ? `page-${currentStory}` : lastStoryPage; 1508 1509 // Only reset player if not preloaded or if story URL changed 1510 if (!isPreloaded || !existingPlayer || existingPlayer.querySelectorAll('a').length === 0) { 1511 resetPlayer(); 1512 } else { 1513 // Update the href of existing preloaded player if story changed 1514 const existingLink = existingPlayer.querySelector('a'); 1515 const uniqueId = storageWrapper.getItem("uniqueId"); 1516 const data = JSON.parse(storageWrapper.getItem(`jsonData_${collectionId}`)); 1517 const expectedHref = `${webStoriesUrl}/amp?brandId=${brandSlug || brandId}&collection=${data._id}&embed=true&type=${type}&identifier=${uniqueId}#page=${storyToShow}`; 1518 1519 if (existingLink && !existingLink.href.includes(`#page=${storyToShow}`)) { 1520 existingLink.href = expectedHref; 1521 } 1522 1523 // Preloaded player is ready to use (amp-story-player manages its own visibility) 1524 } 1525 1526 storyModal.style.zIndex = "21474836472222"; 1527 storyModal.style.opacity = "1"; 1528 document.documentElement.style.overflow = "hidden"; 1529 const allElements = document.querySelectorAll( 1530 "body *:not(#oono-stories-container):not(#oono-stories-container *)" 1531 );
1532 allElements.forEach((el) => { 1533 el.style.visibility = "hidden"; 1534 }); 1535 // localStorage.setItem("scrollPosition", window.scrollY); 1536 setTimeout(() => { 1537 playPlayer(); 1538 }, isPreloaded ? 0 : 100); // Immediate for preloaded, slight delay for new players 1539 } else { 1540 storyModal.style.zIndex = "-1"; 1541 storyModal.style.opacity = "0"; 1542 document.documentElement.style.overflow = "auto"; 1543 const allElements = document.querySelectorAll( 1544 "body *:not(#oono-stories-container):not(#oono-stories-container *)" 1545 ); 1546 allElements.forEach((el) => { 1547 el.style.visibility = "visible"; 1548 }); 1549 // window.scrollTo(0, localStorage.getItem("scrollPosition")); 1550 1551 // Pause the player (amp-story-player manages its own visibility) 1552 const player = shadowRoot.querySelector(".my-player"); 1553 if (player) { 1554 player.pause(); 1555 } 1556 } 1557 // } else { 1558 // // toast() 1559 // } 1560 } 1561 1562 if (positionType === "float") { 1563 window.addEventListener("scroll", () => { 1564 imgDiv.style.position = "fixed"; 1565 }); 1566 } else if (positionType === "fixed") { 1567 imgDiv.style.position = "absolute"; 1568 } 1569 1570 function preloadPlayer() { 1571 // Prevent multiple preloads for the same collection 1572 if (window[`_oonoPreloaded_${collectionId}`]) { 1573 return; 1574 } 1575 window[`_oonoPreloaded_${collectionId}`] = true; 1576 1577 const uniqueId = storageWrapper.getItem("uniqueId"); 1578 const data = JSON.parse( 1579 storageWrapper.getItem(`jsonData_${collectionId}`) 1580 ); 1581 const storyModal = shadowRoot.querySelector("#storyModal"); 1582 1583 if (storyModal && !shadowRoot.querySelector(".my-player") && data) { 1584 const url = new URL(window.location); 1585 const currentStory = getStoryNumberFromUrl(url); 1586 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1587 const lastStoryPage = lastStory[collectionId] || "page-1"; 1588 1589 const storyToShow = currentStory ? `page-${currentStory}` : lastStoryPage; 1590 1591 console.log('Preloading amp-story-player for collection:', collectionId); 1592 1593 // Create the player (amp-story-player manages its own visibility) 1594 storyModal.innerHTML = ` 1595 <amp-story-player class="my-player" height="100vh" width="100vw" layout="fixed"> 1596 <script type="application/json"> 1597 { 1598 "controls": [ 1599 { 1600 "name": "close", 1601 "position": "end" 1602 } 1603 ] 1604 } 1605 </script> 1606 <a href="${webStoriesUrl}/amp?brandId=${brandSlug || brandId}&collection=${data._id}&embed=true&type=${type}&identifier=${uniqueId}#page=${storyToShow}"></a> 1607 </amp-story-player>`; 1608 1609 // Wait for amp scripts to load and mark as preloaded 1610 const checkPlayerReady = () => { 1611 const player = shadowRoot.querySelector(".my-player"); 1612 if (player) { 1613 // Try to initialize the player to preload content 1614 try { 1615 // Mark as preloaded after a reasonable time for amp initialization 1616 setTimeout(() => { 1617 player.setAttribute('data-preloaded', 'true'); 1618 console.log('amp-story-player preloaded successfully for collection:', collectionId); 1619 }, 2000); 1620 } catch (e) { 1621 console.log('Player preload initialization completed for collection:', collectionId); 1622 player.setAttribute('data-preloaded', 'true'); 1623 } 1624 } 1625 }; 1626 1627 // Check immediately and also after a delay 1628 setTimeout(checkPlayerReady, 100); 1629 } 1630 } 1631 1632 function resetPlayer() { 1633 const uniqueId = storageWrapper.getItem("uniqueId"); 1634 const data = JSON.parse( 1635 storageWrapper.getItem(`jsonData_${collectionId}`) 1636 ); 1637 const storyModal = shadowRoot.querySelector("#storyModal");
1638 if (storyModal) { 1639 const url = new URL(window.location); 1640 const currentStory = getStoryNumberFromUrl(url); 1641 const lastStory = JSON.parse(storageWrapper.getItem("lastStory")) || {}; 1642 const lastStoryPage = lastStory[collectionId] || "page-1"; 1643 1644 const storyToShow = currentStory ? `page-${currentStory}` : lastStoryPage; 1645 1646 storyModal.innerHTML = ` 1647 <amp-story-player class="my-player" height="100vh" width="100vw" layout="fixed"> 1648 <script type="application/json"> 1649 { 1650 "controls": [ 1651 { 1652 "name": "close", 1653 "position": "end" 1654 } 1655 ] 1656 } 1657 </script> 1658 <a href="${webStoriesUrl}/amp?brandId=${brandSlug || brandId}&collection=${data._id}&embed=true&type=${type}&identifier=${uniqueId}#page=${storyToShow}"></a> 1659 </amp-story-player>`; 1660 } 1661 } 1662 1663 function closeAllOonoModals() { 1664 document.querySelectorAll('div[id^="oono-stories-container"]').forEach(div => { 1665 if (div.shadowRoot) { 1666 const storyModal = div.shadowRoot.querySelector("#storyModal"); 1667 if (storyModal) { 1668 storyModal.style.opacity = "0"; 1669 storyModal.style.zIndex = "-1"; 1670 } 1671 } 1672 }); 1673} 1674 1675 const handleClose = async () => { 1676 const storyModal = container.shadowRoot.querySelector("#storyModal"); 1677 updateStoryCount(); 1678 closeAllOonoModals(); 1679 storyModal.style.opacity = "0"; 1680 storyModal.style.zIndex = "-1"; 1681 document.documentElement.style.overflow = "auto"; 1682 const allElements = document.querySelectorAll( 1683 "body *:not(#oono-stories-container):not(#oono-stories-container *)" 1684 ); 1685 allElements.forEach((el) => { 1686 el.style.visibility = "visible"; 1687 }); 1688 1689 // find current storyNumber 1690 const url = new URL(window.location); 1691 const storyNumber = parseInt(getStoryNumberFromUrl(url) || 0); 1692 1693 const collectionData = getCollection(collectionId); 1694 const stories = collectionData?.stories; 1695 const storyId = stories?.[storyNumber]?._id 1696 window._oonoFirstClick = false; 1697 1698 // calculate the timeSpent 1699 const endTime = Date.now(); 1700 const timeSpent = (endTime - startTime) / 1000; 1701 const timeSpentSeconds = Math.round(timeSpent); 1702 1703 await EmitEvent(backendUrl, "stories-stats", { 1704 collectionId: getCollectionId(collectionId), 1705 brandId: brandRealId, 1706 identifier: storageWrapper.getItem("uniqueId"), 1707 action: 5, 1708 storyId, 1709 timeSpent: timeSpentSeconds, 1710 }); 1711 1712 // Just pause the player instead of trying to remove it 1713 const player = shadowRoot.querySelector(".my-player"); 1714 if (player) { 1715 player.pause(); 1716 } 1717 1718 storageWrapper.removeItem("storyId"); 1719 storageWrapper.removeItem("timeSpent"); 1720 1721 // Clear URL parameters based on collection type 1722 const collectionCodeData = getCollectionCodeAndName(collectionId); 1723 if (collectionCodeData) { 1724 url.searchParams.delete("c"); 1725 url.searchParams.delete("story"); 1726 } else { 1727 url.searchParams.delete("oono"); 1728 url.searchParams.delete("story"); 1729 } 1730 1731 // Prevent infinite loops by checking if URL actually changed 1732 if (window.location.href !== url.href) { 1733 try { 1734 window.history.pushState({}, "", url.href); 1735 } catch (e) { 1736 console.warn('Failed to update URL state:', e); 1737 } 1738 } 1739 }; 1740 window.addEventListener("popstate", () => { 1741 handleClose(); 1742 }); 1743 1744 function playPlayer() { 1745 const tryPlayPlayer = () => { 1746 const player = shadowRoot.querySelector(".my-player"); 1747 if (player) { 1748 const isPreloaded = player.getAttribute('data-preloaded') === 'true'; 1749 1750 if (!isPreloaded && (player.readyState === 0 || player.querySelectorAll('a').length === 0)) { 1751 resetPlayer(); 1752 return; 1753 } 1754 1755 // Remove existing event listener to prevent duplicates 1756 player.removeEventListener("amp-story-player-close", handleClose); 1757 player.addEventListener("amp-story-player-close", handleClose); 1758 player.show(); 1759 player.play(); 1760 } else { 1761 const intervalId = setInterval(() => { 1762 const player = shadowRoot.querySelector(".my-player"); 1763 1764 if (player) { 1765 clearInterval(intervalId); 1766 player.removeEventListener("amp-story-player-close", handleClose); 1767 player.addEventListener( 1768 "amp-story-player-close", 1769 handleClose 1770 ); 1771 player.show(); 1772 player.play(); 1773 } 1774 }, 1000); 1775 } 1776 }; 1777 tryPlayPlayer(); 1778 } 1779 1780 window.addEventListener("message", (event) => { 1781 if (event.data.openCollection) { 1782 // Don't reset player, just close the current modal 1783 handleClose(); 1784 } 1785 const handlePlayerAction = () => { 1786 const player = shadowRoot.querySelector(".my-player"); 1787 if (player) { 1788 if (event.data.action === "pause") { 1789 player.pause(); 1790 } else if (event.data.action === "play") { 1791 player.play(); 1792 } 1793 } else { 1794 const intervalId = setInterval(() => { 1795 handlePlayerAction(); 1796 clearInterval(intervalId); 1797 }, 1000); 1798 } 1799 }; 1800 1801 if (event.data.moveTo) { 1802 const player = shadowRoot.querySelector(".my-player"); 1803 if (player) { 1804 const negativeMoveTo = -Math.abs(parseInt(event.data.moveTo, 10)); 1805 player.go(0, negativeMoveTo); 1806 } 1807 } 1808 1809 handlePlayerAction(); 1810 if (event.origin === webStoriesUrl) { 1811 if (event.data.collection) { 1812 storageWrapper.setItem( 1813 "collection", 1814 JSON.stringify(event.data.collection) 1815 ); 1816 } 1817 if (event.data.story) { 1818 handleClose(); 1819 } 1820 } 1821 }); 1822 }) 1823 .catch((error) => { 1824 // if (error) { 1825 // ["#playButton", "#imgDiv", "#collectionImage",".carousel-item"]?.forEach(id => { 1826 // const el = shadowRoot.querySelector(id); 1827 // el && el.addEventListener("click", () => { 1828 // // toast() 1829 // }); 1830 // }); 1831 // } 1832 }); 1833 } 1834} 1835 1836 initOonoStories(); 1837})();
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.