1(function () { 2 const RESIZE_MESSAGE_TYPE = "resize"; 3 const parentOrigin = getParentOrigin(); 4 5 function getParentOrigin() { 6 const value = new URLSearchParams(window.location.search).get("parentOrigin"); 7 if (!value) { 8 return "*"; 9 } 10 11 try { 12 return new URL(value).origin; 13 } catch (error) { 14 return "*"; 15 } 16 } 17 18 function postWidgetResize() { 19 if (window.parent === window) { 20 return; 21 } 22 23 const documentHeight = Math.max( 24 document.documentElement.scrollHeight, 25 document.documentElement.getBoundingClientRect().height 26 ); 27 28 window.parent.postMessage({ 29 type: RESIZE_MESSAGE_TYPE, 30 height: documentHeight 31 }, parentOrigin); 32 } 33 34 function debounce(fn, delay) { 35 let timer = 0; 36 return function () { 37 window.clearTimeout(timer); 38 timer = window.setTimeout(fn, delay); 39 }; 40 } 41 42 function sendTracking(url, id) { 43 if (!url || !id) { 44 return; 45 } 46 47 const beaconUrl = url.indexOf("?") === -1 48 ? url + "?id=" + encodeURIComponent(id) 49 : url + "&id=" + encodeURIComponent(id); 50 51 if (navigator.sendBeacon) { 52 navigator.sendBeacon(beaconUrl); 53 return; 54 } 55 56 fetch(url, { 57 method: "POST", 58 headers: { 59 "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" 60 }, 61 body: "id=" + encodeURIComponent(id), 62 keepalive: true 63 }).catch(function () { }); 64 } 65 66 function applySingleImageBackground(card) { 67 if (!card 68 || !card.classList.contains("is-single-image-contained") 69 || card.dataset.singleImageBackgroundState) { 70 return; 71 } 72 73 const image = card.querySelector(".publio-card__single-image"); 74 const src = image ? (image.currentSrc || image.src) : ""; 75 76 card.dataset.singleImageBackgroundState = "ready"; 77 if (src) { 78 card.style.setProperty("--publio-single-image-source", "url(" + JSON.stringify(src) + ")"); 79 } 80 } 81 82 function attachVideoSource(videoEl) { 83 if (!videoEl || videoEl.dataset.videoReady === "1") { 84 return; 85 } 86 87 const src = videoEl.getAttribute("data-hls-src"); 88 if (!src) { 89 return; 90 } 91 92 if (videoEl.canPlayType("application/vnd.apple.mpegURL") || videoEl.canPlayType("application/x-mpegURL")) { 93 videoEl.src = src; 94 } else if (window.Hls) { 95 const hls = new Hls({ autoStartLoad: true }); 96 hls.loadSource(src); 97 hls.attachMedia(videoEl); 98 videoEl.publioHlsInstance = hls; 99 } else { 100 videoEl.src = src; 101 } 102 103 videoEl.dataset.videoReady = "1"; 104 } 105 106 function stopVideo(card) { 107 if (!card) { 108 return; 109 } 110 111 const videoEl = card.querySelector(".publio-card__video"); 112 if (!videoEl) { 113 return; 114 } 115 116 videoEl.pause(); 117 videoEl.currentTime = 0; 118 card.classList.remove("is-video-playing"); 119 } 120 121 function playVideo(card, root) { 122 if (!card) { 123 return; 124 } 125 126 const videoEl = card.querySelector(".publio-card__video"); 127 if (!videoEl) { 128 return; 129 } 130 131 root.querySelectorAll(".publio-card.is-video-post").forEach(function (otherCard) { 132 if (otherCard !== card) { 133 stopVideo(otherCard); 134 } 135 }); 136 137 attachVideoSource(videoEl); 138 videoEl.muted = true; 139 videoEl.playsInline = true; 140 141 const playPromise = videoEl.play(); 142 if (playPromise && typeof playPromise.catch === "function") { 143 playPromise.catch(function () { }); 144 } 145 146 card.classList.add("is-video-playing"); 147 } 148 149 function applySingleImageLayout(card) { 150 if (!card || card.dataset.ratioApplied === "1" || card.classList.contains("is-single-panel")) { 151 return; 152 } 153 154 const image = card.querySelector(".publio-card__image"); 155 if (!image) { 156 return; 157 } 158 159 function updateLayout() {
160 const width = image.naturalWidth; 161 const height = image.naturalHeight; 162 163 if (!width || !height) { 164 return; 165 } 166 167 const ratio = width / height; 168 card.classList.remove("is-ratio-pending", "is-single-cover", "is-single-wide"); 169 card.classList.add(ratio > 1.45 ? "is-single-wide" : "is-single-cover"); 170 card.dataset.ratioApplied = "1"; 171 } 172 173 if (image.complete) { 174 updateLayout(); 175 } else { 176 image.addEventListener("load", updateLayout, { once: true }); 177 } 178 } 179 180 function getCarouselCards(carousel) { 181 return Array.from(carousel.querySelectorAll(".publio-card-track")); 182 } 183 184 function getNearestCardIndex(carousel) { 185 const cards = getCarouselCards(carousel); 186 if (!cards.length) { 187 return 0; 188 } 189 190 let closestIndex = 0; 191 let closestDistance = Number.POSITIVE_INFINITY; 192 193 cards.forEach(function (card, index) { 194 const distance = Math.abs(card.offsetLeft - carousel.scrollLeft); 195 if (distance < closestDistance) { 196 closestDistance = distance; 197 closestIndex = index; 198 } 199 }); 200 201 return closestIndex; 202 } 203 204 function getFirstVisibleCardIndex(carousel) { 205 const cards = getCarouselCards(carousel); 206 if (!cards.length) { 207 return 0; 208 } 209 210 const currentLeft = carousel.scrollLeft + 1; 211 const firstVisibleIndex = cards.findIndex(function (card) { 212 return card.offsetLeft + card.offsetWidth > currentLeft; 213 }); 214 215 return firstVisibleIndex === -1 ? Math.max(0, cards.length - 1) : firstVisibleIndex; 216 } 217 218 function getCardsPerView(carousel) { 219 const cards = getCarouselCards(carousel); 220 if (!cards.length) { 221 return 1; 222 } 223 224 const cardWidth = cards[0].offsetWidth; 225 if (!cardWidth) { 226 return 1; 227 } 228 229 const gap = cards.length > 1 ? Math.max(0, cards[1].offsetLeft - cards[0].offsetLeft - cardWidth) : 0; 230 const fullWidth = cardWidth + gap; 231 if (!fullWidth) { 232 return 1; 233 } 234 235 return Math.max(1, Math.floor((carousel.clientWidth + gap) / fullWidth)); 236 } 237 238 function alignCarouselToCard(carousel, index, behavior) { 239 const cards = getCarouselCards(carousel); 240 if (!cards.length) { 241 return; 242 } 243 244 const cardsPerView = getCardsPerView(carousel); 245 const maxStartIndex = Math.max(0, cards.length - cardsPerView); 246 const safeIndex = Math.max(0, Math.min(index, maxStartIndex)); 247 carousel.scrollTo({ 248 left: cards[safeIndex].offsetLeft, 249 behavior: behavior || "smooth" 250 }); 251 } 252 253 function bindCards(widget) { 254 const mode = widget.dataset.mode || "internal"; 255 const clickUrl = widget.dataset.clickUrl || ""; 256 const viewUrl = widget.dataset.viewUrl || ""; 257 const carousel = widget.querySelector(".publio-carousel"); 258 if (!carousel) { 259 return; 260 } 261 262 const observer = new IntersectionObserver(function (entries) { 263 entries.forEach(function (entry) { 264 const card = entry.target; 265 266 if (entry.isIntersecting) { 267 applySingleImageBackground(card); 268 } 269 270 if (entry.isIntersecting && entry.intersectionRatio >= 0.5) { 271 if (card.dataset.viewRegistered === "1") { 272 return; 273 } 274 275 card.dataset.viewRegistered = "1"; 276 sendTracking(viewUrl, card.dataset.adid); 277 } else if (!entry.isIntersecting) { 278 card.dataset.viewRegistered = "0"; 279 } 280 }); 281 }, { 282 root: carousel, 283 threshold: [0, 0.5] 284 }); 285 286 widget.querySelectorAll(".publio-card-track").forEach(function (card) { 287 if (card.dataset.bound === "1") { 288 return; 289 } 290 291 card.dataset.bound = "1"; 292 observer.observe(card); 293 applySingleImageLayout(card); 294 295 if (card.classList.contains("is-video-post")) { 296 card.addEventListener("mouseenter", function () { 297 playVideo(card, widget); 298 }); 299 card.addEventListener("mouseleave", function () { 300 stopVideo(card); 301 }); 302 } 303 304 const mainLink = card.querySelector(".publio-card__main-link"); 305 if (mainLink) { 306 mainLink.addEventListener("click", function (event) { 307 sendTracking(clickUrl, card.dataset.adid); 308 309 if (mode === "external") { 310 event.preventDefault(); 311 window.open(mainLink.href, "_blank", "noopener"); 312 } 313 }); 314 } 315 }); 316 } 317 318 function initWidget(widget) { 319 if (!widget || widget.dataset.widgetReady === "1") { 320 return; 321 } 322 323 widget.dataset.widgetReady = "1"; 324 325 const carousel = widget.querySelector(".publio-carousel"); 326 if (!carousel) { 327 return; 328 } 329 330 const prevButton = widget.querySelector('.publio-widget__nav[data-direction="prev"]'); 331 const nextButton = widget.querySelector('.publio-widget__nav[data-direction="next"]'); 332 const fetchUrl = widget.dataset.fetchUrl || ""; 333 const idAdvertiser = widget.dataset.idAdvertiser || ""; 334 const regionId = widget.dataset.regionId || ""; 335 const useUserCityPreferences = widget.dataset.useUserCityPreferences === "true"; 336 const prioritize = widget.dataset.prioritizeSelfAdvertiser === "true"; 337 const usePersonalFeed = widget.dataset.usePersonalFeed !== "fal
337se"; 338 const urlOrigin = widget.dataset.urlOrigin || ""; 339 let loading = false; 340 let hasReachedEnd = false; 341 let firstLoad = true; 342 let queueInitialPreload = false; 343 344 function scrollByDirection(direction) { 345 const currentIndex = getFirstVisibleCardIndex(carousel); 346 const targetIndex = currentIndex + (direction * 3); 347 alignCarouselToCard(carousel, targetIndex, "smooth"); 348 } 349 350 if (prevButton) { 351 prevButton.addEventListener("click", function () { 352 scrollByDirection(-1); 353 }); 354 } 355 356 if (nextButton) { 357 nextButton.addEventListener("click", function () { 358 scrollByDirection(1); 359 }); 360 } 361 362 async function loadMore() { 363 if (loading || hasReachedEnd || !fetchUrl) { 364 return; 365 } 366 367 const cards = carousel.querySelectorAll(".publio-card-track"); 368 const lastCard = cards[cards.length - 1]; 369 if (!lastCard) { 370 return; 371 } 372 373 loading = true; 374 375 try { 376 const params = new URLSearchParams({ 377 lastDateStart: lastCard.dataset.unixtimestamp || "0", 378 lastId: lastCard.dataset.id || "0", 379 size: "6" 380 }); 381 382 if (idAdvertiser) { 383 params.set("idAdvertiser", idAdvertiser); 384 } 385 386 if (regionId) { 387 params.set("regionId", regionId); 388 } 389 390 if (useUserCityPreferences) { 391 params.set("useUserCityPreferences", "true"); 392 } 393 394 if (prioritize) { 395 params.set("prioritizeSelfAdvertiser", "true"); 396 } 397 398 params.set("usePersonalFeed", usePersonalFeed ? "true" : "false"); 399 400 if (urlOrigin) { 401 params.set("urlOrigin", urlOrigin); 402 } 403 404 const response = await fetch(fetchUrl + "?" + params.toString(), { 405 credentials: "same-origin" 406 }); 407 408 if (!response.ok) { 409 throw new Error("Impossible de charger plus de publications."); 410 } 411 412 const html = await response.text(); 413 if (!html.trim()) { 414 hasReachedEnd = true; 415 return; 416 } 417 418 const temp = document.createElement("div"); 419 temp.innerHTML = html; 420 while (temp.firstChild) { 421 carousel.appendChild(temp.firstChild); 422 } 423 424 bindCards(widget); 425 postWidgetResize(); 426 427 if (firstLoad) { 428 firstLoad = false; 429 queueInitialPreload = true; 430 } 431 } catch (error) { 432 hasReachedEnd = true; 433 } finally { 434 loading = false; 435 if (queueInitialPreload && !hasReachedEnd) { 436 queueInitialPreload = false; 437 loadMore(); 438 } 439 } 440 } 441 442 carousel.addEventListener("scroll", function () { 443 if (carousel.scrollLeft + carousel.clientWidth >= carousel.scrollWidth - 200) { 444 loadMore(); 445 } 446 }); 447 448 bindCards(widget); 449 window.setTimeout(function () { 450 postWidgetResize(); 451 loadMore(); 452 }, 0); 453 } 454 455 const debouncedResize = debounce(postWidgetResize, 120); 456 window.addEventListener("resize", debouncedResize); 457 document.addEventListener("DOMContentLoaded", function () { 458 document.querySelectorAll('[data-publio-widget="general"]').forEach(initWidget); 459 postWidgetResize(); 460 }); 461})();
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.