1/** 2 * @package EmbedPress 3 * @author EmbedPress <[email protected]> 4 * @copyright Copyright (C) 2023 EmbedPress. All rights reserved. 5 * @license GPLv2 or later 6 * @since 1.7.0 7 */ 8 9 10 11let epGlobals = {}; 12 13(function ($) { 14 'use strict'; 15 // function equivalent to jquery ready() 16 function ready(fn) { 17 if (document.readyState !== 'loading') { 18 fn(); 19 } else { 20 document.addEventListener('DOMContentLoaded', fn); 21 } 22 } 23 24 ready(function () { 25 let option = { 26 forceObject: true, 27 }; 28 let selector = document.querySelectorAll('.embedpress-embed-document-pdf'); 29 if (selector.length) { 30 selector.forEach((function (value, index, thisArg) { 31 let id = value.dataset['emid']; 32 let src = value.dataset['emsrc']; 33 PDFObject?.embed(src, "." + id, option); 34 })); 35 } 36 if (typeof epGlobals.youtubeChannelGallery === 'function') { 37 epGlobals.youtubeChannelGallery(); 38 } 39 }); 40 41 /** 42 * 43 * Make embeds responsive so they don't overflow their container. 44 */ 45 46 /** 47 * Add max-width & max-height to <iframe> elements, depending on their width & height props. 48 * 49 * 50 * @return {void} 51 */ 52 function embedPressResponsiveEmbeds() { 53 var proportion, parentWidth; 54 55 // Loop iframe elements. 56 document.querySelectorAll('iframe').forEach(function (iframe) { 57 // Only continue if the iframe has a width & height defined. 58 if (iframe.width && iframe.height) { 59 // Calculate the proportion/ratio based on the width & height. 60 proportion = parseFloat(iframe.width) / parseFloat(iframe.height); 61 // Get the parent element's width. 62 parentWidth = parseFloat(window.getComputedStyle(iframe.parentElement, null).width.replace('px', '')); 63 // Set the max-width & height. 64 iframe.style.maxWidth = '100%'; 65 iframe.style.maxHeight = Math.round(parentWidth / proportion).toString() + 'px'; 66 } 67 }); 68 } 69 70 epGlobals.handlePosterImageLoad = function () { 71 var posterImages = document.querySelectorAll(".plyr__poster"); 72 var videoWrappers = document.querySelectorAll("[data-playerid]"); 73 74 // If no poster images found, make all players visible immediately 75 if (!posterImages.length) { 76 videoWrappers.forEach(function (videoWrapper) { 77 videoWrapper.style.opacity = "1"; 78 }); 79 return; 80 } 81 82 posterImages.forEach(function (posterImage) { 83 if (posterImage) { 84 videoWrappers.forEach(function (videoWrapper) { 85 // Check if already visible via computed style 86 var posterImageStyle = window.getComputedStyle(posterImage); 87 if (posterImageStyle.getPropertyValue('background-image') !== 'none') { 88 videoWrapper.style.opacity = "1"; 89 return; 90 } 91 92 var observer = new MutationObserver(function (mutationsList, observer) { 93 var posterImageStyle = window.getComputedStyle(posterImage); 94 if (posterImageStyle.getPropertyValue('background-image') !== 'none') { 95 setTimeout(function () { 96 videoWrapper.style.opacity = "1"; 97 }, 200); 98 observer.disconnect(); 99 } 100 }); 101 102 observer.observe(posterImage, { attributes: true, attributeFilter: ['style'] }); 103 104 // Fallback timeout to ensure player becomes visible 105 setTimeout(function () { 106 observer.disconnect(); 107 videoWrapper.style.opacity = "1"; 108 }, 5000); 109 }); 110 } 111 }); 112 } 113 114 // Run on initial load. 115 embedPressResponsiveEmbeds(); 116 117 // Run on resize. 118 window.onresize = embedPressResponsiveEmbeds; 119 120 121 function hasClass(ele, cls) { 122 return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)")); 123 } 124 125 function addClass(ele, cls) { 126 if (!hasClass(ele, cls)) ele.className += " " + cls; 127 } 128 129 function removeClass(ele, cls) { 130 if (hasClass(ele, cls)) { 131 var reg = new RegExp("(\\s|^)" + cls + "(\\s|$)"); 132 ele.className = ele.className.replace(reg, " "); 133 } 134 } 135 if (!Element.prototype.matches) { 136 Element.prototype.matches = 137 Element.prototype.matchesSelector || 138 Element.prototype.webkitMatchesSelector || 139 Element.prototype.mozMatchesSelector || 140 Element.prototype.msMatchesSelector || 141 Element.prototype.oMatchesSelector || 142 function (s) { 143 var matches = (this.document || this.ownerDocument).querySelectorAll(s), 144 i = matches.length; 145 while (--i >= 0 && matches.item(i) !== this) { } 146 return i > -1; 147 }; 148 } 149 var delegate = function (el, evt, sel, handler) { 150 el.addEventListener(evt, function (event) { 151 var t = event.target; 152 while (t && t !== this) { 153 if (t.matches(sel)) { 154 handler.call(t, event); 155 } 156 t = t.parentNode; 157 } 158 }); 159 }; 160 161 function sendRequest(url, postData, callback) { 162 var req = createXMLHTTPObject(); 163 if (!req) return; 164 var method = postData ? "POST" : "GET"; 165 req.open(method, url, true); 166 if (postData) { 167 req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 168 } 169 req.onreadystatechange = function () { 170 if (req.readyState != 4) return; 171 if (req.status != 200 && req.status != 304) { 172 return; 173 } 174 callback(req); 175 }; 176 if (req.readyState == 4) return; 177 req.send(postData); 178 } 179 180 var XMLHttpFactories = [ 181 function () { 182 return new XMLHttpRequest(); 183 }, 184 function () { 185 return new ActiveXObject("Msxml3.XMLHTTP"); 186 }, 187 function () { 188 return new ActiveXObject("Msxml2.XMLHTTP.6.0"); 189 }, 190 function () { 191 return new ActiveXObject("Msxml2.XMLHTTP.3.0"); 192 }, 193 function () { 194 return new ActiveXObject("Msxml2.XMLHTTP"); 195 }, 196 function () { 197 return new ActiveXObject("Microsoft.XMLHTTP"); 198 }, 199 ]; 200 201 function createXMLHTTPObject() { 202 var xmlhttp = false;
203 for (var i = 0; i < XMLHttpFactories.length; i++) { 204 try { 205 xmlhttp = XMLHttpFactories[i](); 206 } catch (e) { 207 continue; 208 } 209 break; 210 } 211 return xmlhttp; 212 } 213 214 epGlobals.youtubeChannelGallery = function () { 215 var playerWraps = document.getElementsByClassName("ep-player-wrap"); 216 if (playerWraps && playerWraps.length) { 217 for (var i = 0, im = playerWraps.length; im > i; i++) { 218 youtubeChannelEvents(playerWraps[i]) 219 } 220 } 221 } 222 223 function youtubeChannelEvents(playerWrap) { 224 225 delegate(playerWrap, "click", ".item", function (event) { 226 var embed = "https://www.youtube.com/embed/"; 227 var vid = this.getAttribute("data-vid"); 228 var iframe = playerWrap.getElementsByTagName("iframe"); 229 230 console.log 231 232 if (vid) { 233 if (iframe) { 234 var vidSrc = iframe[0]?.src.replace(/(.*\/embed\/)([^\?&"'>]+)(.+)?/, `\$1${vid}\$3`); 235 if (vidSrc.indexOf('autoplay') > 0) { 236 vidSrc = vidSrc.replace('autoplay=0', 'autoplay=1'); 237 } 238 else { 239 vidSrc += '&autoplay=1'; 240 } 241 iframe[0].src = vidSrc; 242 playerWrap.scrollIntoView(); 243 } 244 } 245 }); 246 247 var currentPage = 1; 248 249 // The new layout-queue uses a different shell (.ep-yt-queue) with its 250 // own JS in ep-yt-queue.js, so .ep-youtube__content__block won't exist 251 // and we should bail out of the legacy channel-gallery pagination/click 252 // wiring instead of throwing. 253 let epContentBlock = playerWrap.querySelector('.ep-youtube__content__block'); 254 if (!epContentBlock) return; 255 let nearestEpContentId = epContentBlock.getAttribute('data-unique-id'); 256 let parentElement = epContentBlock.parentElement; 257 258 // Get the value of data-channel-url attribute from a sibling 259 let channelUrlEl = parentElement.querySelector('[data-channel-url]'); 260 let channelUrl = channelUrlEl ? channelUrlEl.getAttribute('data-channel-url') : ''; 261 262 263 delegate(playerWrap, "click", ".ep-next, .ep-prev", function (event) { 264 const totalPages = event.target.closest('.ose-youtube').getAttribute('data-total-pages'); 265 const closestClass = event.target.closest('.ose-youtube').classList; 266 267 const activePage = document.querySelector(`.${closestClass[1]} .embedpress-page-active`); 268 if (activePage) { 269 document.querySelector(`.${closestClass[1]} .embedpress-page-active`).classList.remove('embedpress-page-active'); 270 } 271 272 273 274 var isNext = this.classList.contains("ep-next"); 275 276 if (isNext) { 277 currentPage++; 278 } else { 279 currentPage--; 280 } 281 282 var data = { 283 action: "youtube_rest_api", 284 playlistid: this.getAttribute("data-playlistid"), 285 pagetoken: this.getAttribute("data-pagetoken"), 286 pagesize: this.getAttribute("data-pagesize"), 287 channelUrl: channelUrl, 288 currentpage: currentPage 289 }; 290 291 var formBody = []; 292 for (var property in data) { 293 var encodedKey = encodeURIComponent(property); 294 var encodedValue = encodeURIComponent(data[property]); 295 formBody.push(encodedKey + "=" + encodedValue); 296 } 297 formBody = formBody.join("&"); 298 299 var galleryWrapper = playerWrap.getElementsByClassName( 300 "ep-youtube__content__block" 301 ); 302 303 playerWrap.setAttribute('data-current-page', currentPage); 304 305 306 let x = 1; 307 308 sendRequest(embedpressFrontendData.ajaxurl, formBody, function (request) { 309 if (galleryWrapper && galleryWrapper[0] && request.responseText) { 310 var response = JSON.parse(request.responseText); 311 galleryWrapper[0].outerHTML = response.html; 312 313 var currentPageNode = 314 galleryWrapper[0].getElementsByClassName("current-page"); 315 if (currentPageNode && currentPageNode[0]) { 316 currentPageNode[0].textContent = currentPage; 317 318 } 319 } 320 }); 321 322 const intervalID = setInterval(() => { 323 x++ 324 325 if (playerWrap.querySelector('.ep-youtube__content__block')) { 326 const newNearestEpContentId = playerWrap 327 .querySelector('.ep-youtube__content__block') 328 .getAttribute('data-unique-id'); 329 330 if (newNearestEpContentId !== nearestEpContentId && playerWrap.querySelector(`[data-
330page="${currentPage}"]`)) { 331 playerWrap.querySelector(`[data-page="${currentPage}"]`).classList.add('embedpress-page-active'); 332 nearestEpContentId = newNearestEpContentId; 333 clearInterval(intervalID); 334 } 335 } 336 337 if (x > 100) { 338 clearInterval(intervalID); 339 } 340 }, 100); 341 342 }); 343 } 344 345 //Load more for OpenaSea collection 346 const epLoadMore = () => { 347 348 $('.embedpress-gutenberg-wrapper .ep-nft-gallery-wrapper').each(function () { 349 let selctorEl = `[data-nftid='${$(this).data('nftid')}']`; 350 351 let loadmorelabel = $(selctorEl).data('loadmorelabel'); 352 let iconcolor = $(selctorEl + " .nft-loadmore").data('iconcolor'); 353 354 let spinicon = `<svg width="18" height="18" fill="${iconcolor || '#fff'}" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_GuJz{transform-origin:center;animation:spinner_STY6 1.5s linear infinite}@keyframes spinner_STY6{100%{transform:rotate(360deg)}}</style><g class="spinner_GuJz"><circle cx="3" cy="12" r="2"/><circle cx="21" cy="12" r="2"/><circle cx="12" cy="21" r="2"/><circle cx="12" cy="3" r="2"/><circle cx="5.64" cy="5.64" r="2"/><circle cx="18.36" cy="18.36" r="2"/><circle cx="5.64" cy="18.36" r="2"/><circle cx="18.36" cy="5.64" r="2"/></g></svg>`; 355 356 $(selctorEl + ` .ep_nft_item`).slice(0, $(selctorEl).data('itemparpage')).show(); 357 $('.embedpress-gutenberg-wrapper .ep-nft-gallery-wrapper .ep-loadmore-wrapper button').css('display', 'flex'); 358 359 $(selctorEl + " .nft-loadmore").click(function (e) { 360 //change the text of the button 361 $(this).html(loadmorelabel + spinicon); 362 //disable the button 363 $(this).prop("disabled", true); 364 //wait for 1 seconds 365 setTimeout(function () { 366 //change the text back 367 $(selctorEl + " .nft-loadmore").text(loadmorelabel); 368 //enable the button 369 $(selctorEl + " .nft-loadmore").prop("disabled", false); 370 $(selctorEl + " .ep_nft_item:hidden").slice(0, $(selctorEl).data('itemparpage')).fadeIn("slow"); 371 if ($(selctorEl + " .ep_nft_item:hidden").length == 0) { 372 $(selctorEl + " .nft-loadmore").fadeOut("slow"); 373 } 374 }, 500); 375 }); 376 }); 377 }; 378 379 if ($('.embedpress-gutenberg-wrapper .ep-nft-gallery-wrapper').length > 0) { 380 epLoadMore(); 381 } 382 383 // Content protection system function 384 const unlockSubmitHander = (perentSel, that) => { 385 var ep_client_id = jQuery(that).closest('form').find('input[name="ep_client_id"]').val(); 386 var password = jQuery(`input[name="pass_${ep_client_id}"]`).val(); 387 var post_id = jQuery(`input[name="post_id"]`).val(); 388 const buttonText = jQuery(that).closest('.password-form-container').find('input[type="submit"]').val(); 389 const unlokingText = jQuery(that).data('unlocking-text'); 390 391 392 var data = { 393 'action': 'lock_content_form_handler', 394 'client_id': ep_client_id, 395 'password': password, 396 'post_id': post_id, 397 }; 398 399 jQuery('#' + perentSel + '-' + ep_client_id + ' .password-form input[type="submit"]').val(unlokingText); 400 401 jQuery.post(embedpressFrontendData.ajaxurl, data, function (response) { 402 if (response.success) { 403 if (!response.embedHtml) { 404 jQuery('#' + perentSel + '-' + ep_client_id + ' .password-form input[type="submit"]').val(buttonText); 405 jQuery('#' + perentSel + '-' + ep_client_id + ' .password-form input[type="password"]').val(''); 406 jQuery(that).closest('.password-form-container').find('.error-message').removeClass('hidden'); 407 } 408 else { 409 // Replace the content inside the wrapper, keeping the wrapper itself 410 const wrapperEl = jQuery('#' + perentSel + '-' + ep_client_id); 411 const parentWrapper = wrapperEl.parent('.ep-embed-content-wraper'); 412 413 if (parentWrapper.length > 0) { 414 // If there's a parent .ep-embed-content-wraper, replace its content 415 parentWrapper.html(response.embedHtml); 416 } else { 417 // Otherwise replace the wrapper content directly 418 wrapperEl.html(response.embedHtml); 419 } 420 421 if (jQuery('#' + perentSel + '-' + ep_client_id + ' .ose-youtube').length > 0) { 422 epGlobals.youtubeChannelGallery(); 423 } 424 425 if ($('.embedpress-gutenberg-wrapper .ep-nft-gallery-wrapper').length > 0) { 426 epLoadMore(); 427 } 428 429 // Custom player initialization when content protection enabled 430 const targetEl = parentWrapper.length > 0 ? parentWrapper[0] : wrapperEl[0]; 431 targetEl?.classList?.remove('plyr-initialized'); 432 433 if (typeof initPlayer === 'function') { 434 initPlayer(targetEl); 435 } 436 if (embedpressFrontendData.isProPluginActive) { 437 const adIdEl = document.querySelector('#' + perentSel + '-' + ep_client_id + ' [data-sponsored-id]'); 438 if (typeof adInitialization === 'function') { 439 adInitialization(adIdEl, adIdEl?.getAttribute('data-ad-index')); 440 } 441 } 442 443 } 444 } else { 445 jQuery('#password-error_' + ep_client_id).html(response.form); 446 jQuery('#password-error_' + ep_client_id).show(); 447 } 448 }, 'json'); 449 } 450 451 // unlockSubmitHander called for gutentberg 452 jQuery('.ep-gutenberg-content .password-form').submit(function (e) { 453 e.preventDefault(); // Prevent the default form submission 454 unlockSubmitHander('ep-gutenberg-content', this); 455 }); 456 457 jQuery('.ep-shortcode-content .password-form').submit(function (e) { 458 e.preventDefault(); // Prevent the default form submission 459 unlockSubmitHander('ep-shortcode-content', this); 460 }); 461 462 window.addEventListener('load', function (e) {
463 const urlParams = new URLSearchParams(window.location.search); 464 const hash = urlParams.get('hash'); 465 466 // find the element with the matching id 467 const element = document.getElementById(hash); 468 469 if (element) { 470 element.scrollIntoView({ behavior: 'smooth' }); 471 } 472 473 }); 474 475 // Get the insta-gallery container element 476 const getPopupTemplate = (instPost, hashtag = '', accountType) => { 477 478 let instaPostData = JSON.parse(instPost); 479 480 481 let likeIcon = '<svg aria-label="Like" class="x1lliihq x1n2onr6" color="#262626" fill="#262626" height="24" viewBox="0 0 24 24" width="24"><path d="M16.792 3.904A4.989 4.989 0 0 1 21.5 9.122c0 3.072-2.652 4.959-5.197 7.222-2.512 2.243-3.865 3.469-4.303 3.752-.477-.309-2.143-1.823-4.303-3.752C5.141 14.072 2.5 12.167 2.5 9.122a4.989 4.989 0 0 1 4.708-5.218 4.21 4.21 0 0 1 3.675 1.941c.84 1.175.98 1.763 1.12 1.763s.278-.588 1.11-1.766a4.17 4.17 0 0 1 3.679-1.938m0-2a6.04 6.04 0 0 0-4.797 2.127 6.052 6.052 0 0 0-4.787-2.127A6.985 6.985 0 0 0 .5 9.122c0 3.61 2.55 5.827 5.015 7.97.283.246.569.494.853.747l1.027.918a44.998 44.998 0 0 0 3.518 3.018 2 2 0 0 0 2.174 0 45.263 45.263 0 0 0 3.626-3.115l.922-.824c.293-.26.59-.519.885-.774 2.334-2.025 4.98-4.32 4.98-7.94a6.985 6.985 0 0 0-6.708-7.218Z"/></svg>'; 482 483 if (instaPostData.like_count > 0) { 484 likeIcon = '<svg aria-label="Unlike" class="x1lliihq x1n2onr6" color="#FF3040" fill="#FF3040" height="24" viewBox="0 0 48 48" width="24"><path d="M34.6 3.1c-4.5 0-7.9 1.8-10.6 5.6-2.7-3.7-6.1-5.5-10.6-5.5C6 3.1 0 9.6 0 17.6c0 7.3 5.4 12 10.6 16.5.6.5 1.3 1.1 1.9 1.7l2.3 2c4.4 3.9 6.6 5.9 7.6 6.5.5.3 1.1.5 1.6.5s1.1-.2 1.6-.5c1-.6 2.8-2.2 7.8-6.8l2-1.8c.7-.6 1.3-1.2 2-1.7C42.7 29.6 48 25 48 17.6c0-8-6-14.5-13.4-14.5z"/></svg>'; 485 } 486 487 const commentsIcon = '<svg aria-label="Comment" class="x1lliihq x1n2onr6" color="#000" height="24" viewBox="0 0 24 24" width="24"><path d="M20.656 17.008a9.993 9.993 0 1 0-3.59 3.615L22 22Z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="2"/></svg>'; 488 489 const shareIcon = '<svg width="20" height="20" viewBox="0 0 0.6 0.6" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg"><path stroke-width="1" d="m.543.282-.2-.2A.025.025 0 0 0 .3.1v.089a.275.275 0 0 0-.25.274V.5a.025.025 0 0 0 .045.015.3.3 0 0 1 .197-.101L.3.413V.5a.025.025 0 0 0 .043.018l.2-.2a.025.025 0 0 0 0-.035M.35.44V.388A.025.025 0 0 0 .325.363L.286.365a.35.35 0 0 0-.185.074.225.225 0 0 1 .224-.201A.025.025 0 0 0 .35.213V.16L.49.3Z"/></svg>'; 490 491 const instaIcon = '<svg width="18" height="18" viewBox="0 0 0.338 0.338" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M.248.079H.27M.102.012h.135a.09.09 0 0 1 .09.09v.135a.09.09 0 0 1-.09.09H.102a.09.09 0 0 1-.09-.09V.102a.09.09 0 0 1 .09-.09ZM.17.237a.068.068 0 1 1 0-.135.068.068 0 0 1 0 .135Z" stroke="#000" stroke-width=".032"/></svg>'; 492 493 494 495 const instaUserInfo = instPost.user_info; 496 497 let getDate = new Date(instaPostData.timestamp); 498 getDate = getDate.toLocaleString('en-US', { day: 'numeric', month: 'short', year: 'numeric' }); 499 500 let getTime = new Date(instaPostData.timestamp); 501 getTime = getTime.toLocaleString('en-US', { hour12: false, hour: 'numeric', minute: 'numeric', second: 'numeric' }); 502 503 let captionText = instaPostData.caption ? instaPostData.caption : ''; 504 const tagRegex = /(#\w+)/g; 505 506 const wrapTag = (match) => { 507 const tag = match.substring(1); // Remove the '#' character 508 const tagUrl = `https://www.instagram.com/explore/tags/${tag}`; 509 return `<span class="tag-wrapper"><a target="_blank" href="${tagUrl}">${match}</a></span>`; 510 }; 511 512 captionText = captionText.replace(tagRegex, wrapTag); 513 514 let carouselTemplate = ''; 515 if (instaPostData.media_type === 'CAROUSEL_ALBUM') { 516 carouselTemplate += `<div class="popup-carousel"><div class="cg-carousel__track js-carousel__track">`; 517 518 instaPostData.children.data?.map((item) => { 519 if (item.media_type?.toLowerCase() === 'video') { 520 carouselTemplate += `<video width="630" class="popup-media-image cg-carou
520sel__slide js-carousel__slide" controls src="${item.media_url || ''}" alt="${item.caption || ''}" controlsList="nodownload"></video>`; 521 } 522 else { 523 carouselTemplate += `<img width="630" class="popup-media-image cg-carousel__slide js-carousel__slide" src="${item.media_url || ''}" alt="${item.caption || ''}" />`; 524 } 525 }); 526 527 carouselTemplate += `</div></div>`; 528 529 carouselTemplate += `<div class="cg-carousel__btns"> 530 <button type="button" class="cg-carousel__btn js-carousel__prev-1" aria-label="Previous"><svg aria-hidden="true" focusable="false" width="20" height="30" viewBox="-5 0 23 23" xmlns="http://www.w3.org/2000/svg"><path d="M11.24.29.361 10.742l-.06.054a.97.97 0 0 0-.301.642v.124a.97.97 0 0 0 .3.642l.054.044L11.239 22.71a1.061 1.061 0 0 0 1.459 0 .964.964 0 0 0 0-1.402l-10.15-9.746 10.15-9.87a.964.964 0 0 0 0-1.402 1.061 1.061 0 0 0-1.459 0Z" fill="#fff"/></svg></button> 531 532 <button type="button" class="cg-carousel__btn js-carousel__next-1" aria-label="Next"><svg aria-hidden="true" focusable="false" width="20" height="30" viewBox="-5 0 23 23" xmlns="http://www.w3.org/2000/svg"><path d="m1.76.29 10.879 10.452.06.054a.97.97 0 0 1 .301.642v.124a.97.97 0 0 1-.3.642l-.054.044L1.761 22.71a1.061 1.061 0 0 1-1.459 0 .964.964 0 0 1 0-1.402l10.15-9.746-10.15-9.87a.964.964 0 0 1 0-1.402 1.061 1.061 0 0 1 1.459 0Z" fill="#fff"/></svg></button> 533 </div>` 534 } 535 else { 536 if (instaPostData.media_type?.toLowerCase() === 'video') { 537 carouselTemplate += `<video width="630" class="popup-media-image" controls src="${instaPostData.media_url || ''}" alt="${instaPostData.caption || ''}"></video>`; 538 } 539 else { 540 carouselTemplate += `<img width="630" class="popup-media-image" src="${instaPostData.media_url || ''}" alt="${instaPostData.caption || ''}" />`; 541 } 542 } 543 544 let srcUrl = `https://www.instagram.com/${instaPostData.username}/`; 545 546 if (hashtag) { 547 instaPostData.username = '#' + hashtag; 548 srcUrl = `https://www.instagram.com/explore/tags/${hashtag}/`; 549 } 550 551 552 let likeComments = ''; 553 554 if (embedpressFrontendData.isProPluginActive) { 555 if (instaPostData.show_likes_count == 'true') { 556 likeComments += ` 557 <div class="embedpress-inline popup-like-button"><a target="_blank" href="${instaPostData.permalink}">${likeIcon} ${instaPostData.like_count || 0}</a></div> 558 `; 559 } 560 if (instaPostData.show_comments_count == 'true') { 561 likeComments += ` 562 <div class="embedpress-inline"><a target="_blank" href="${instaPostData.permalink}">${commentsIcon} ${instaPostData.comments_count || 0}</a></div> 563 `; 564 } 565 } 566 567 568 let followBtn = ''; 569 if (instaPostData.popup_follow_button_text == 'false') { 570 instaPostData.popup_follow_button_text = ''; 571 } 572 if (instaPostData.popup_follow_button == 'true' || instaPostData.popup_follow_button == 'yes') { 573 followBtn = `<div class="insta-followbtn"> 574 <a target="_new" href="${srcUrl}" type="button" class="btn btn-primary">${instaPostData.popup_follow_button_text}</a> 575 </div>`; 576 } 577 578 let popupHtml = ''; 579 popupHtml += ` 580 <div class="popup-container"> 581 <div class="popup-md-9 white"> 582 <div class="embedpress-popup-block embedpress-popup-img" id="post-${instaPostData.id}"> 583 ${carouselTemplate} 584 </div> 585 </div> 586 <div class="popup-md-3 red"> 587 <div class="embedpress-popup-block embedpress-popup-info"> 588 <div class="embedpress-popup-header"> 589 <div class="embedpress-popup-header-img"> <a target="_blank" href="${srcUrl}" 590 target="_blank" class="embedpress-href"> 591 <img decoding="async" loading="lazy" class="embedpress-popup-round" src="${instaPostData.profile_picture_url}" width="30" height="30"> <span class="embedpress-popup-username">${instaPostData.username}</span> 592 </a> 593 </div> 594 ${followBtn} 595 </div> 596 <div class="embedpress-popup-text">${captionText}</div> 597 <div class="embedpress-popup-stats"> 598 ${likeComments} 599 <div class="embedpress-inline"> 600 <div class="embedpress-popup-share-buttons"> <a 601 href="https://www.facebook.com/sharer/sharer.php?u=${instaPostData.permalink}" target="_blank">
602 <span class="dashicons dashicons-facebook"></span></a> <a 603 href="https://twitter.com/intent/tweet?url=${instaPostData.permalink}" 604 target="_blank"><span> 605 <svg viewBox="0 0 18 18" aria-hidden="true" class="r-4qtqp9 r-yyyyoo r-dnmrzs r-bnwqim r-1plcrui r-lrvibr r-lrsllp r-18jsvk2 r-16y2uox r-8kz0gk" width="18" height="18"><path d="M13.683 1.688h2.481l-5.42 6.195 6.377 8.43h-4.993L8.217 11.2l-4.474 5.113H1.26l5.798-6.626L.941 1.688H6.06l3.535 4.673zm-.871 13.14h1.375L5.313 3.095H3.838z"/></svg> 606 </span></a> 607 <a href="https://www.linkedin.com/shareArticle?mini=true&url=${instaPostData.permalink}" 608 target="_blank"><span class="dashicons dashicons-linkedin"></span></a> <a 609 href="https://pinterest.com/pin/create/button/?url=${instaPostData.permalink}" 610 target="_blank"><span class="dashicons dashicons-pinterest"></span></a></div> 611 <div class="embedpress-href embedpress-popup-share">${shareIcon}</div> 612 </div><div class="embedpress-inline embedpress-popup-instagram-buttons"><a 613 href="${instaPostData.permalink}" target="_blank" 614 class="embedpress-href">${instaIcon}</a></div> 615 </div> 616 617 </div> 618 </div> 619 </div> 620 `; 621 622 // INIT CAROUSEL 623 624 625 return popupHtml; 626 } 627 628 // Add a click event listener to the insta-gallery container 629 epGlobals.instaPopup = (container) => { 630 container?.addEventListener('click', function (event) { 631 // Check if the clicked element has the class insta-gallery-item 632 const instaItem = event.target.closest('.insta-gallery-item'); 633 634 if (instaItem) { 635 636 const postData = instaItem.dataset.postdata; 637 638 const postid = instaItem.getAttribute('data-insta-postid'); 639 const accountType = container?.closest('.instagram-container')?.getAttribute('data-connected-acc-type'); 640 641 let hashtag = ''; 642 643 if (instaItem.closest('.instagram-container').getAttribute('data-hashtag')) { 644 hashtag = instaItem?.closest('.instagram-container')?.getAttribute('data-hashtag'); 645 } 646 647 const closestPopup = event.target.closest('.ose-instagram-feed')?.querySelector('.insta-popup'); 648 649 if (closestPopup) { 650 closestPopup.style.display = 'block'; 651 } 652 653 654 var feedElement = event.target.closest('.ose-instagram-feed'); 655 if (feedElement) { 656 var popupElement = feedElement.querySelector('.popup-is-initialized'); 657 if (popupElement) { 658 popupElement.innerHTML = getPopupTemplate(postData, hashtag, accountType); 659 } 660 } 661 662 if (!document.querySelector(`#post-${postid}`)?.classList.contains('carousel-is-initialized')) { 663 const carousel = new CgCarousel(`#post-${postid}`, { slidesPerView: 1, loop: true }, {}); 664 665 const next = document.querySelector(`#post-${postid} .js-carousel__next-1`); 666 next?.addEventListener('click', () => carousel.next()); 667 668 const prev = document.querySelector(`#post-${postid} .js-carousel__prev-1`); 669 prev?.addEventListener('click', () => carousel.prev()); 670 671 document.querySelector(`#post-${postid}`)?.classList.add('carousel-is-initialized'); 672 } 673 674 } 675 }); 676 } 677 678 679 const instaContainers = document.querySelectorAll('.embedpress-gutenberg-wrapper .insta-gallery'); 680 if (instaContainers.length > 0) {
681 instaContainers.forEach((container) => { 682 epGlobals.instaPopup(container); 683 }); 684 } 685 686 $('.popup-close').click(function (e) { 687 // Hide the popup by setting display to none 688 $('.insta-popup').hide(); 689 $('.popup-container').remove(); 690 }); 691 692 $(document).on('click', function (e) { 693 if (e.target.classList.contains('popup-wrapper')) { 694 $('.insta-popup').hide(); 695 $('.popup-container').remove(); 696 } 697 }); 698 699 700 const instafeeds = document.querySelectorAll('.ose-instagram-feed'); 701 702 epGlobals.initializeTabs = (containerEl) => { 703 704 // Initial tab selection 705 showItems('ALL'); 706 707 containerEl.addEventListener('click', function (event) { 708 const clickedElement = event.target; 709 if (!clickedElement) { 710 return; // No element clicked, ignore the event 711 } 712 713 if (containerEl.querySelector('.load-more-button-container') && (clickedElement.getAttribute('data-media-type') === 'VIDEO' || clickedElement.getAttribute('data-media-type') === 'CAROUSEL_ALBUM')) { 714 containerEl.querySelector('.load-more-button-container').style.display = 'none'; 715 } 716 else if (containerEl.querySelector('.load-more-button-container') && (clickedElement.getAttribute('data-media-type') === 'ALL')) { 717 containerEl.querySelector('.load-more-button-container').style.display = 'flex'; 718 } 719 720 // Handle tab click 721 if (clickedElement.matches('.tabs li')) { 722 if (clickedElement.classList.contains('active')) { 723 return; 724 } else { 725 const mediaType = clickedElement.getAttribute('data-media-type'); 726 showItems(mediaType); 727 728 const tabs = containerEl.querySelectorAll('.tabs li');
729 tabs.forEach(t => t.classList.remove('active')); 730 clickedElement.classList.add('active'); 731 } 732 } 733 734 }); 735 736 function showItems(mediaType) { 737 const items = containerEl.getElementsByClassName('insta-gallery-item'); 738 for (let i = 0; i < items.length; i++) { 739 const item = items[i]; 740 if (mediaType === 'ALL' || item.getAttribute('data-media-type') === mediaType) { 741 item.style.display = 'block'; 742 } else { 743 item.style.display = 'none'; 744 } 745 } 746 } 747 } 748 749 epGlobals.instaLoadMore = () => { 750 // Unbind any previously bound click event to avoid multiple bindings 751 $('.insta-load-more-button').off('click').on('click', function (e) { 752 const that = $(this); 753 const loadmoreBtn = that.closest('.load-more-button-container'); 754 const loadmoreKey = loadmoreBtn.data('loadmorekey'); 755 const connectedAccount = that.closest('.instagram-container').data('connected-acc-type'); 756 const feedType = that.closest('.instagram-container').data('feed-type'); 757 const hashtagId = that.closest('.instagram-container').data('hashtag-id'); 758 const userId = that.closest('.instagram-container').data('uid'); 759 let loadedPosts = loadmoreBtn.data('loaded-posts') || 0; 760 let postsPerPage = loadmoreBtn.data('posts-per-page') || 0; 761 const params = JSON.stringify(that.closest('.instagram-container').data('params')); 762 763 764 const instaContainer = that.closest('.instagram-container'); 765 766 const spinicon = `<svg class="insta-loadmore-spinicon" width="18" height="18" fill="${'#fff'}" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_GuJz{transform-origin:center;animation:spinner_STY6 1.5s linear infinite}@keyframes spinner_STY6{100%{transform:rotate(360deg)}}</style><g class="spinner_GuJz"><circle cx="3" cy="12" r="2"/><circle cx="21" cy="12" r="2"/><circle cx="12" cy="21" r="2"/><circle cx="12" cy="3" r="2"/><circle cx="5.64" cy="5.64" r="2"/><circle cx="18.36" cy="18.36" r="2"/><circle cx="5.64" cy="18.36" r="2"/><circle cx="18.36" cy="5.64" r="2"/></g></svg>`; 767 768 // Check if no spinicon exists 769 if (instaContainer.find('.insta-loadmore-spinicon').length === 0) { 770 that.append(spinicon); 771 } 772 773 that.attr('disabled', true); 774 775 var data = { 776 'action': 'loadmore_data_handler', 777 'user_id': userId, 778 'loaded_posts': loadedPosts, 779 'posts_per_page': postsPerPage, 780 'feed_type': feedType, 781 'connected_account_type': connectedAccount,
782 'loadmore_key': loadmoreKey, 783 'params': params, 784 '_nonce': embedpressFrontendData.nonce 785 }; 786 787 if (feedType === 'hashtag_type') { 788 data.hashtag_id = hashtagId; 789 } 790 791 jQuery.post(embedpressFrontendData.ajaxurl, data, function (response) { 792 if (response.total_feed_posts >= response.next_post_index) { 793 var $responseHtml = $(response.html); 794 795 instaContainer.find('.insta-gallery').append($responseHtml); 796 that.removeAttr('disabled'); 797 798 instaContainer.find('.insta-loadmore-spinicon').remove(); 799 800 loadedPosts = response.next_post_index; 801 802 loadmoreBtn.data('loaded-posts', loadedPosts); 803 804 // After loading more items, reinitialize the tabs for the specific container 805 const containerEl = loadmoreBtn.closest('.ose-instagram-feed')[0]; 806 epGlobals.initializeTabs(containerEl); 807 808 if (response.total_feed_posts === response.next_post_index) { 809 loadmoreBtn.remove(); 810 } 811 } else { 812 loadmoreBtn.remove(); 813 } 814 }); 815 }); 816 } 817 818 819 if (instafeeds.length > 0) { 820 instafeeds.forEach(function (feed) { 821 epGlobals.initializeTabs(feed); 822 }); 823 } 824 825 if ($('.embedpress-gutenberg-wrapper .ose-instagram-feed').length > 0) { 826 epGlobals.instaLoadMore(); 827 } 828 829 $(document).on({ 830 mouseenter: function () { 831 $('.embedpress-popup-share-buttons').addClass('show'); 832 }, 833 mouseleave: function () { 834 var buttons = $('.embedpress-popup-share-buttons'); 835 setTimeout(function () { 836 if (!buttons.is(':hover')) buttons.removeClass('show'); 837 }, 200); 838 } 839 }, '.embedpress-href.embedpress-popup-share, .embedpress-popup-share-buttons'); 840 841 $(document).on({ 842 mouseenter: function () { 843 $(this).addClass('show'); 844 }, 845 mouseleave: function () { 846 $(this).removeClass('show'); 847 } 848 }, '.embedpress-popup-share-buttons'); 849 850 851 852 853 854})(jQuery); 855 856 857 858document.addEventListener('DOMContentLoaded', function () { 859 860 epGlobals.initCarousel = (carouselSelector, options, carouselId) => { 861 862 const carouselOptions = { 863 slidesPerView: options.slideshow, 864 spacing: options.spacing, 865 loop: options.loop, 866 autoplay: options.autoplay, 867 transitionSpeed: options.transitionspeed, 868 autoplaySpeed: options.autoplayspeed, 869 arrows: options.arrows, 870 breakpoints: { 871 0: { 872 slidesPerView: 1 873 }, 874 768: { 875 slidesPerView: Math.max(1, parseInt(options.slideshow, 10) - 1) 876 }, 877 1024: { 878 slidesPerView: Math.max(1, parseInt(options.slideshow, 10)) 879 } 880 } 881 }; 882 883 // INIT CAROUSEL 884 const carousel = new CgCarousel(carouselSelector, carouselOptions, {}); 885 886 // Navigation 887 const next = document.querySelector(`[data-carouselid="${carouselId}"] #js-carousel__next-1`); 888 next?.addEventListener('click', () => carousel.next()); 889 890 const prev = document.querySelector(`[data-carouselid="${carouselId}"] #js-carousel__prev-1`); 891 prev?.addEventListener('click', () => carousel.prev()); 892 } 893 894 const instaWrappers = document.querySelectorAll('.ep-embed-content-wraper'); 895 896 if (instaWrappers.length > 0) { 897 instaWrappers.forEach((wrapper) => { 898 const carouselId = wrapper.getAttribute('data-carouselid'); 899 900 if (!carouselId) return; 901 902 let options = wrapper.getAttribute(`data-carousel-options`); 903 904 options = JSON.parse(options); 905 const carouselSelector = `[data-carouselid="${carouselId}"] .embedpress-insta-container`; 906 907 if (options.arrows) { 908 document.querySelector(`[data-carouselid="${carouselId}
908"] .cg-carousel__btns`).classList.remove('hidden'); 909 } 910 911 epGlobals.initCarousel(carouselSelector, options, carouselId); 912 913 }); 914 } 915 916 // Youtube Channel Carousel 917 918 const youtubeCarouselWraper = document.querySelectorAll('[data-youtube-channel-carousel]'); 919 920 if (youtubeCarouselWraper.length > 0) { 921 youtubeCarouselWraper.forEach((wrapper) => { 922 const carouselId = wrapper.getAttribute('data-youtube-channel-carousel'); 923 if (!carouselId) return; 924 925 // let options = wrapper.getAttribute(`data-carousel-options`); 926 927 // options = JSON.parse(options); 928 929 const carouselSelector = `[data-youtube-channel-carousel="${carouselId}"] .youtube__content__body`; 930 931 // if (options.arrows) { 932 // document.querySelector(`[data-youtube-channel-carousel="${carouselId}"] .cg-carousel__btns`).classList.remove('hidden'); 933 // } 934 935 const options = { 936 slidesPerView: 2, 937 autoplay: true, 938 loop: true, 939 breakpoints: { 940 768: { 941 slidesPerView: 2 942 }, 943 1024: { 944 slidesPerView: 4 945 } 946 } 947 } 948 949 // epGlobals.initCarousel(carouselSelector, options, {}); 950 951 }); 952 } 953 954 955 956}); 957 958document.addEventListener('DOMContentLoaded', () => { 959 const carousel = document.querySelector('.youtube-carousel'); 960 961 if (!carousel) { 962 return; 963 } 964 965 const items = document.querySelectorAll('.item'); 966 const prevButton = document.querySelector('.preview'); 967 const nextButton = document.querySelector('.next'); 968 969 let itemsToShow = getItemsToShow(); // Determine items to show based on screen width 970 971 const totalItems = items.length; 972 let currentIndex = 0; 973 974 function updateCarousel() { 975 const offset = -currentIndex * (100 / itemsToShow); 976 carousel.style.transform = `translateX(${offset}%)`; 977 } 978 979 function nextSlide() { 980 const remainingItems = totalItems - (currentIndex + itemsToShow); 981 if (remainingItems >= itemsToShow) { 982 currentIndex += itemsToShow; 983 } else if (remainingItems > 0) { 984 currentIndex += remainingItems; 985 } else { 986 currentIndex = 0; 987 } 988 updateCarousel(); 989 } 990 991 function prevSlide() { 992 if (currentIndex > 0) { 993 currentIndex -= itemsToShow; 994 if (currentIndex < 0) { 995 currentIndex = 0; 996 } 997 } else { 998 currentIndex = totalItems - itemsToShow; 999 } 1000 updateCarousel(); 1001 } 1002 1003 nextButton?.addEventListener('click', nextSlide); 1004 prevButton?.addEventListener('click', prevSlide); 1005 1006 // Optional: Autoplay 1007 let autoplay = false; 1008 const autoplayInterval = 3000; // Change the time as needed 1009 let autoplayId; 1010 1011 function startAutoplay() { 1012 autoplayId = setInterval(nextSlide, autoplayInterval); 1013 } 1014 1015 function stopAutoplay() { 1016 clearInterval(autoplayId); 1017 } 1018 1019 if (autoplay) { 1020 startAutoplay(); 1021 1022 // Stop autoplay on mouseover, resume on mouseout 1023 carousel.addEventListener('mouseover', stopAutoplay); 1024 carousel.addEventListener('mouseout', startAutoplay); 1025 } 1026 1027 // Handle responsive behavior 1028 window.addEventListener('resize', () => { 1029 itemsToShow = getItemsToShow(); 1030 updateCarousel(); 1031 1032 }); 1033 1034 function getItemsToShow() { 1035 const width = window.innerWidth; 1036 if (width >= 1024) { 1037 return 3; 1038 } else if (width >= 768) { 1039 return 2; 1040 } else { 1041 return 1; 1042 } 1043 } 1044}); 1045 1046 1047 1048 1049jQuery(window).on("elementor/frontend/init", function () { 1050 1051 var filterableGalleryHandler = function ($scope, $) { 1052 1053 // Get the Elementor unique selector for this widget 1054 let classes = $scope[0].className; 1055 let selectorEl = '.' + classes.split(' ').join('.'); 1056 1057 const epElLoadMore = () => { 1058 1059 const spinicon = '<svg width="18" height="18" fill="#fff" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_GuJz{transform-origin:center;animation:spinner_STY6 1.5s linear infinite}@keyframes spinner_STY6{100%{transform:rotate(360deg)}}</style><g class="spinner_GuJz"><circle cx="3" cy="12" r="2"/><circle cx="21" cy="12" r="2"/><circle cx="12" cy="21" r="2"/><circle cx="12" cy="3" r="2"/><circle cx="5.64" cy="5.64" r="2"/><circle cx="18.36" cy="18.36" r="2"/><circle cx="5.64" cy="18.36" r="2"/><circle cx="18.36" cy="5.64" r="2"/></g></svg>'; 1060 1061 $('.elementor-widget-embedpres_elementor .ep-nft-gallery-wrapper').each(function () { 1062 let selctorEl = `.elementor-widget-embedpres_elementor [data-nftid='${$(this).data('nftid')}
1062']`; 1063 let loadmorelabel = $(selctorEl).data('loadmorelabel'); 1064 $(selctorEl + ` .ep_nft_item`).slice(0, $(selctorEl).data('itemparpage')).show(); 1065 $('.elementor-widget-embedpres_elementor .ep-nft-gallery-wrapper .ep-loadmore-wrapper button').css('display', 'flex'); 1066 1067 $(selctorEl + " .nft-loadmore").click(function (e) { 1068 //change the text of the button 1069 $(this).html(loadmorelabel + spinicon); 1070 1071 //disable the button 1072 $(this).prop("disabled", true); 1073 //wait for 1 seconds 1074 setTimeout(function () { 1075 //change the text back 1076 $(selctorEl + " .nft-loadmore").text(loadmorelabel); 1077 //enable the button 1078 $(selctorEl + " .nft-loadmore").prop("disabled", false); 1079 $(selctorEl + " .ep_nft_item:hidden").slice(0, $(selctorEl).data('itemparpage')).fadeIn("slow"); 1080 if ($(selctorEl + " .ep_nft_item:hidden").length == 0) { 1081 $(selctorEl + " .nft-loadmore").fadeOut("slow"); 1082 } 1083 }, 500); 1084 }); 1085 }); 1086 }; 1087 1088 if ($('.elementor-widget-embedpres_elementor .ep-nft-gallery-wrapper').length > 0) { 1089 epElLoadMore(); 1090 } 1091 1092 // Content protection system function 1093 const unlockElSubmitHander = (perentSel, that) => { 1094 var ep_client_id = jQuery(that).closest('form').find('input[name="ep_client_id"]').val(); 1095 var password = jQuery(`input[name="pass_${ep_client_id}"]`).val(); 1096 var post_id = jQuery(`input[name="post_id"]`).val(); 1097 const buttonText = jQuery(that).closest('.password-form-container').find('input[type="submit"]').val(); 1098 const unlokingText = jQuery(that).data('unlocking-text'); 1099 1100 var data = { 1101 'action': 'lock_content_form_handler', 1102 'client_id': ep_client_id, 1103 'password': password, 1104 'post_id': post_id, 1105 }; 1106 1107 jQuery('#' + perentSel + '-' + ep_client_id + ' .password-form input[type="submit"]').val(unlokingText); 1108 1109 jQuery.post(embedpressFrontendData.ajaxurl, data, function (response) { 1110 if (response.success) { 1111 if (!response.embedHtml) { 1112 jQuery('#' + perentSel + '-' + ep_client_id + ' .password-form input[type="submit"]').val(buttonText); 1113 jQuery('#' + perentSel + '-' + ep_client_id + ' .password-form input[type="password"]').val(''); 1114 jQuery(that).closest('.password-form-container').find('.error-message').removeClass('hidden'); 1115 } 1116 else { 1117 if ($('.ep-content-locked').has('#' + perentSel + '-' + ep_client_id).length) { 1118 $('.ep-content-locked').removeClass('ep-content-locked'); 1119 } 1120 1121 jQuery('#' + perentSel + '-' + ep_client_id + ' .ep-embed-content-wraper').html(response.embedHtml); 1122 1123 $('#' + perentSel + '-' + ep_client_id).removeClass('ep-content-protection-enabled'); 1124 1125 if (jQuery('#' + perentSel + '-' + ep_client_id + ' .ose-youtube').length > 0) { 1126 epGlobals.youtubeChannelGallery(); 1127 } 1128 1129 if ($('.elementor-widget-embedpres_elementor .ep-nft-gallery-wrapper').length > 0) { 1130 epElLoadMore(); 1131 } 1132 } 1133 } else { 1134 jQuery('#password-error_' + ep_client_id).html(response.form); 1135 jQuery('#password-error_' + ep_client_id).show(); 1136 } 1137 }, 'json'); 1138 } 1139 1140 // unlockElSubmitHander called for Elementor 1141 jQuery('.ep-elementor-content .password-form').submit(function (e) { 1142 e.preventDefault(); // Prevent the default form submission 1143 unlockElSubmitHander('ep-elementor-content', this); 1144 }); 1145 1146 1147 const instaWrappers = document.querySelectorAll('.ep-embed-content-wrapper'); 1148 1149 if (instaWrappers.length > 0) { 1150
1151 instaWrappers.forEach((wrapper) => { 1152 wrapper.classList.add('class-content-wrapper'); 1153 const carouselId = wrapper.getAttribute('data-carouselid'); 1154 1155 if (!carouselId) return; 1156 1157 let options = wrapper.getAttribute(`data-carousel-options`); 1158 1159 options = JSON.parse(options); 1160 const carouselSelector = `[data-carouselid="${carouselId}"] .embedpress-insta-container`; 1161 1162 1163 if (options.arrows) { 1164 document.querySelector(`[data-carouselid="${carouselId}"] .cg-carousel__btns`).classList.remove('hidden'); 1165 } 1166 1167 epGlobals.initCarousel(carouselSelector, options, carouselId); 1168 1169 }); 1170 } 1171 1172 1173 const instaFeed = document.querySelector(`${selectorEl} .ose-instagram-feed`); 1174 const instaGallery = document.querySelector(`${selectorEl} .insta-gallery`); 1175 if (instaFeed) { 1176 epGlobals.initializeTabs(instaFeed); 1177 } 1178 if (instaGallery) { 1179 epGlobals.instaPopup(instaGallery); 1180 1181 $('.popup-close').click(function (e) { 1182 // Hide the popup by setting display to none 1183 $('.insta-popup').hide(); 1184 $('.popup-container').remove(); 1185 }); 1186 1187 } 1188 1189 if ($('.elementor-widget-embedpres_elementor .ose-instagram-feed').length > 0) { 1190 epGlobals.instaLoadMore(); 1191 } 1192 1193 }; 1194 1195 const adsHandler = function ($scope, $) { 1196 window.epAdIndex = typeof (window.epAdIndex) === 'undefined' ? 0 : window.epAdIndex + 1; 1197 let classes = $scope[0].className; 1198 let classJoint = '.' + classes.split(' ').join('.'); 1199 const selectorEl = document.querySelector(classJoint + ' [data-sponsored-id]'); 1200 1201 if (jQuery('body').hasClass('elementor-editor-active') && embedpressFrontendData.isProPluginActive) { 1202 if (typeof adInitialization === 'function') { 1203 adInitialization(selectorEl, window.epAdIndex); 1204 } 1205 } 1206 1207 } 1208 1209 elementorFrontend.hooks.addAction("frontend/element_ready/embedpres_elementor.default", filterableGalleryHandler); 1210 elementorFrontend.hooks.addAction("frontend/element_ready/embedpress_pdf.default", filterableGalleryHandler); 1211 elementorFrontend.hooks.addAction("frontend/element_ready/embedpres_document.default", filterableGalleryHandler); 1212 elementorFrontend.hooks.addAction("frontend/element_ready/embedpres_elementor.default", adsHandler); 1213 elementorFrontend.hooks.addAction("frontend/element_ready/embedpres_elementor.default", epGlobals.handlePosterImageLoad); 1214 1215 // Re-initialize custom player when Elementor widget becomes ready 1216 var customPlayerHandler = function ($scope, $) { 1217 var wrappers = $scope[0].querySelectorAll('.ep-embed-content-wraper'); 1218 if (typeof initPlayer === 'function') { 1219 wrappers.forEach(function (wrapper) { 1220 var playerId = wrapper.getAttribute('data-playerid'); 1221 1222 // Destroy existing player instance so initPlayer can re-create it 1223 if (playerId && wrapper.classList.contains('plyr-initialized')) { 1224 if (typeof playerInit !== 'undefined' && playerInit[playerId]) { 1225 try { 1226 playerInit[playerId].destroy(); 1227 } catch (e) { 1228 // Player may already be detached 1229 } 1230 delete playerInit[playerId]; 1231 } 1232 wrapper.classList.remove('plyr-initialized'); 1233 } 1234 1235 if (playerId) { 1236 initPlayer(wrapper); 1237 } 1238 }); 1239 } else { 1240 // Fallback: ensure embeds are visible even if Plyr scripts failed to load 1241 wrappers.forEach(function (wrapper) { 1242 if (wrapper.hasAttribute('data-playerid')) { 1243 wrapper.style.opacity = '1'; 1244 } 1245 }); 1246 } 1247 1248 // Re-initialize lazy loaded iframes for this widget 1249 if (typeof window.epReinitLazyLoad === 'function') { 1250 window.epReinitLazyLoad(); 1251 } 1252 }; 1253 elementorFrontend.hooks.addAction("frontend/element_ready/embedpres_elementor.default", customPlayerHandler); 1254}); 1255 1256 1257function presentationModeForIOS(iframes) { 1258 iframes?.forEach(function (iframe) { 1259 iframe.onload = function () { 1260 var iframeDoc = iframe.contentDocument || iframe.contentWindow.document; 1261 var button = iframeDoc?.querySelector('#presentationMode.presentationMode'); 1262 button?.addEventListener('click', function () { 1263 iframe.classList.toggle('presentationModeEnabledIosDevice'); 1264 }); 1265 iframeDoc?.addEventListener('keydown', function (event) { 1266 if (event.keyCode === 27) { 1267 iframe.classList.remove('presentationModeEnabledIosDevice'); 1268 } 1269 }); 1270 }; 1271 }); 1272} 1273 1274function isIOSDevice() { 1275 return /iPhone|iPad|iPod/i.test(navigator.userAgent); 1276} 1277 1278if (isIOSDevice()) { 1279 var iframes = document.querySelectorAll('.embedpress-embed-document-pdf'); 1280 presentationModeForIOS(iframes) 1281} 1282 1283document.addEventListener("DOMContentLoaded", epGlobals.handlePosterImageLoad); 1284 1285 1286jQuery(document).ready(function ($) { 1287
1288 let currentIndex = -1; 1289 1290 function createVideoPopup() { 1291 const videoPopupHtml = ` 1292 <div id="videoPopup" class="video-popup"> 1293 <div class="video-popup-content"> 1294 <span class="close">×</span> 1295 <div class="video-popup-inner-content"> 1296 <iframe id="videoIframe" frameborder="0" allowfullscreen allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"></iframe> 1297 <div id="videoDescription"></div> 1298 </div> 1299 <div class="popup-controls"> 1300 <span id="prevVideo" class="nav-icon prev-icon">❮</span> 1301 <span id="nextVideo" class="nav-icon next-icon">❯</span> 1302 </div> 1303 </div> 1304 </div>`; 1305 return $(videoPopupHtml).appendTo('body'); 1306 } 1307 1308 function openVideoPopup(index) { 1309 const items = $('.layout-grid .item, .layout-list .item, .layout-carousel .item'); 1310 if (index >= 0 && index < items.length) { 1311 // Remove any existing video popup before creating a new one 1312 $('#videoPopup').remove(); 1313 1314 currentIndex = index; 1315 const videoId = $(items[currentIndex]).data('vid'); 1316 const videoPopup = createVideoPopup(); 1317 const videoIframe = videoPopup.find('#videoIframe'); 1318 const videoDescriptionContainer = videoPopup.find('#videoDescription'); 1319 const closeBtn = videoPopup.find('.close'); 1320 const nextBtn = videoPopup.find('#nextVideo'); 1321 const prevBtn = videoPopup.find('#prevVideo'); 1322 1323 if (videoId) { 1324 fetchVideoData(videoId, videoIframe, videoDescriptionContainer); 1325 videoPopup.show(); 1326 updateNavigationButtons(nextBtn, prevBtn, items); 1327 1328 closeBtn.on('click', () => { 1329 closeVideoPopup(videoPopup); 1330 }); 1331 1332 $(window).on('click', function (event) { 1333 if ($(event.target).is(videoPopup)) { 1334 closeVideoPopup(videoPopup); 1335 } 1336 }); 1337 1338 nextBtn.on('click', function () { 1339 if (currentIndex >= 0 && currentIndex < items.length - 1) { 1340 openVideoPopup(currentIndex + 1); 1341 } 1342 }); 1343 1344 prevBtn.on('click', function () { 1345 if (currentIndex > 0) { 1346 openVideoPopup(currentIndex - 1); 1347 } 1348 }); 1349 } 1350 } 1351 } 1352 1353 1354 function closeVideoPopup(videoPopup) { 1355 videoPopup.remove(); 1356 currentIndex = -1; // Reset the index 1357 } 1358 1359 function updateNavigationButtons(nextBtn, prevBtn, items) { 1360 prevBtn.toggle(currentIndex > 0); 1361 nextBtn.toggle(currentIndex < items.length - 1); 1362 } 1363 1364 function fetchVideoData(videoId, videoIframe, videoDescriptionContainer) { 1365 const data = { 1366 action: 'fetch_video_description', 1367 vid: videoId 1368 }; 1369 1370 $.post(embedpressFrontendData.ajaxurl, data, function (response) { 1371 if (response.success) { 1372 videoIframe.attr('src', `https://www.youtube.com/embed/${videoId}?autoplay=1`); 1373 videoDescriptionContainer.html(response.data.description); 1374 } else { 1375 console.error('Error fetching video data:', response?.data?.error); 1376 } 1377 }); 1378 } 1379 1380 $(document).on('click', '.layout-grid .item, .layout-list .item, .layout-carousel .item', function () { 1381 const items = $('.layout-grid .item, .layout-list .item, .layout-carousel .item'); 1382 const index = items.index(this); 1383 openVideoPopup(index); 1384 }); 1385}); 1386jQuery(document).ready(function ($) { 1387 let currentIndex = 0; 1388 // Recomputed on each open so galleries rendered after this point 1389 // (e.g. inside an Elementor popup or loaded via AJAX) are handled too. 1390 let $photos = $(); 1391 1392 function createPopupGooglePhotos() { 1393 if ($('#ep-popup-overlay').length === 0) { 1394 const photoPopup = ` 1395 <div class="popup-overlay" id="ep-popup-overlay" style="display: none!important"> 1396 1397 <div class="popup">
1398 <span class="close-btn" id="close-btn"> 1399 <svg width="20" height="20" viewBox="0 0 0.6 0.6" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M.132.132a.025.025 0 0 1 .035 0L.3.265.432.133a.025.025 0 1 1 .035.035L.335.3l.132.132a.025.025 0 0 1-.035.035L.3.335.168.467A.025.025 0 0 1 .133.432L.265.3.132.168a.025.025 0 0 1 0-.035" fill="#fff"/></svg> 1400 </span> 1401 <button type="button" class="prev-btn" id="prev-btn" aria-label="Previous"> 1402 <svg aria-hidden="true" focusable="false" width="20" height="20" viewBox="0 0 0.6 0.6" data-name="Flat Color" xmlns="http://www.w3.org/2000/svg" class="icon flat-color"><path d="M.525.275h-.39L.268.143A.025.025 0 1 0 .233.108L.058.283a.025.025 0 0 0 0 .035l.175.175a.025.025 0 0 0 .035 0 .025.025 0 0 0 0-.035L.135.325h.39a.025.025 0 0 0 0-.05" style="fill:#fff"/></svg> 1403 </button> 1404 <div id="popup-content" class="loading"> 1405 <div class="photo-loader"></div> 1406 <img id="popup-image" src="" style="display:none;" loading="lazy" /> 1407 </div> 1408 <button type="button" class="next-btn" id="next-btn" aria-label="Next"> 1409 <svg aria-hidden="true" focusable="false" width="20" height="20" viewBox="0 0 0.6 0.6" data-name="Flat Color" xmlns="http://www.w3.org/2000/svg" class="icon flat-color"><path d="M.543.282.368.107a.025.025 0 0 0-.035.035l.133.132H.075a.025.025 0 0 0 0 .05h.39L.332.456a.025.025 0 0 0 0 .035.025.025 0 0 0 .035 0L.542.316a.025.025 0 0 0 0-.035" style="fill:#fff"/></svg> 1410 </button> 1411 </div> 1412 </div>`; 1413 $('body').append(photoPopup); 1414 1415 // Loader spinner CSS (can be moved to your CSS file) 1416 const spinnerStyles = ` 1417 <style> 1418 .popup #popup-content .photo-loader { 1419 display: none; 1420 } 1421 .popup #popup-content.loading .photo-loader { 1422 width: 40px; 1423 height: 40px; 1424 border: 4px solid #fff;
1425 border-top: 4px solid transparent; 1426 border-radius: 50%; 1427 animation: spin 1s linear infinite; 1428 margin: 40px auto; 1429 display: block; 1430 } 1431 @keyframes spin { 1432 0% { transform: rotate(0deg); } 1433 100% { transform: rotate(360deg); } 1434 } 1435 </style>`; 1436 $('head').append(spinnerStyles); 1437 1438 // Events 1439 $('#ep-popup-overlay').on('click', function (e) { 1440 if ($(e.target).is('#ep-popup-overlay') || $(e.target).is('.popup')) { 1441 $('#ep-popup-overlay').hide(); 1442 } 1443 }); 1444 1445 $('#close-btn').on('click', function () { 1446 $('#ep-popup-overlay').hide(); 1447 }); 1448 1449 $('#prev-btn').on('click', function () { 1450 currentIndex = (currentIndex - 1 + $photos.length) % $photos.length; 1451 updatePopupImage(); 1452 }); 1453 1454 $('#next-btn').on('click', function () { 1455 currentIndex = (currentIndex + 1) % $photos.length; 1456 updatePopupImage(); 1457 }); 1458 } 1459 } 1460 1461 function updatePopupImage() { 1462 const imgSrc = $photos.eq(currentIndex).find('img').attr('data-photo-src'); 1463 const $popupImage = $('#popup-image'); 1464 const $popupContent = $('#popup-content'); 1465 1466 $popupContent.addClass('loading'); 1467 $popupImage.hide(); 1468 1469 const preload = new Image(); 1470 preload.src = imgSrc; 1471 1472 preload.onload = function () { 1473 $popupImage.attr('src', imgSrc); 1474 $popupContent.removeClass('loading'); 1475 $popupImage.fadeIn(); 1476 }; 1477 } 1478 1479 // Delegated binding: works for `.photo-item` elements that are added to the 1480 // DOM after page load â e.g. an EmbedPress gallery placed inside an Elementor 1481 // popup, which Elementor injects only when the popup is opened. A direct 1482 // `$('.photo-item').on('click', ...)` bound here would miss those elements. 1483 $(document).on('click', '.photo-item', function () { 1484 // Scope navigation (prev/next) to the gallery that was actually clicked, 1485 // so multiple galleries on the same page don't get mixed together. 1486 var $gallery = $(this).closest('.photos-gallery-grid, .photos-gallery-justify, .photos-gallery-masonary'); 1487 $photos = $gallery.length ? $gallery.find('.photo-item') : $('.photo-item'); 1488 currentIndex = $photos.index(this); 1489 createPopupGooglePhotos(); 1490 updatePopupImage(); 1491 $('#ep-popup-overlay').show(); 1492 }); 1493}); 1494 1495 1496// pause audio/video 1497 1498jQuery(document).ready(function () { 1499 const players = jQuery('.enabled-auto-pause audio, .enabled-auto-pause video'); 1500 1501 function pauseAllExcept(currentPlayer) { 1502 players.each(function () { 1503 if (this !== currentPlayer[0]) { 1504 this.pause(); 1505 } 1506 }); 1507 } 1508 1509 players.on('play', function () { 1510 pauseAllExcept(jQuery(this)); 1511 }); 1512}); 1513 1514// Meetup Events Load More 1515jQuery(document).on('click', '.ep-load-more-button', function(e) { 1516 e.preventDefault(); 1517 1518 const button = jQuery(this); 1519 const container = button.closest('.embedpress-meetup-events'); 1520 const eventsContainer = container.find('.embedpress-meetup-events-list'); 1521 1522 // Get data attributes 1523 const embedId = button.data('embed-id'); 1524 const currentPage = parseInt(container.data('page')) || 1; 1525 const perPage = parseInt(container.data('per-page')) || 10; 1526 const nextPage = currentPage + 1; 1527 1528 // Show loading state 1529 const loadingText = button.find('.ep-load-more-text'); 1530 const spinner = button.find('.ep-load-more-spinner'); 1531 loadingText.hide(); 1532 spinner.show(); 1533 button.prop('disabled', true); 1534 1535 // Make AJAX request 1536 jQuery.ajax({ 1537 url: embedpressFrontendData.ajaxurl, 1538 type: 'POST', 1539 data: { 1540 action: 'embedpress_meetup_load_more', 1541 nonce: embedpressFrontendData.nonce, 1542 embed_id: embedId, 1543 page: nextPage, 1544 per_page: perPage 1545 }, 1546 success: function(response) { 1547 if (response.success) { 1548 // Append new events 1549 eventsContainer.append(response.data.html); 1550 1551 // Update page number 1552 container.data('page', nextPage); 1553 1554 // Trigger custom event for timezone conversion 1555 document.dispatchEvent(new Event('embedpress:meetup:loaded')); 1556 1557 // Hide button if no more events 1558 if (!response.data.has_more) { 1559 button.closest('.ep-events-load-more').fadeOut(); 1560 } else { 1561 loadingText.show(); 1562 spinner.hide(); 1563 button.prop('disabled', false); 1564 } 1565 } else { 1566 alert(response.data.message || 'Error loading more events'); 1567 loadingText.show(); 1568 spinner.hide(); 1569 button.prop('disabled', false); 1570 } 1571 }, 1572 error: function() { 1573 alert('Error loading more events'); 1574 loadingText.show(); 1575 spinner.hide(); 1576 button.prop('disabled', false); 1577 } 1578 }); 1579}); 1580
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.