1/** 2 * Instagram Feed Slider and Popup Functionality 3 * 4 * Handles: 5 * - Responsive slider/carousel initialization 6 * - Popup modal for post details 7 * - Masonry grid layout 8 * - Media type handling (images, videos, carousels) 9 * 10 * @since 1.0.0 11 * @package DiviSocialFeed 12 */ 13 14// Initialize Instagram sliders with responsive settings 15jQuery(document).ready(function($) { 16 $('.dsf_ig_slider_wrapper').each(function() { 17 let $this = $(this); 18 19 /** 20 * Get spacing values from data attributes 21 * Default to 20px if not specified or invalid 22 */ 23 let spacingDesktop = parseInt($this.data('spacing-desktop')) || 20; 24 let spacingTablet = parseInt($this.data('spacing-tablet')) || 20; 25 let spacingMobile = parseInt($this.data('spacing-mobile')) || 20; 26 27 /** 28 * Get column count settings from data attributes 29 * These will be used in the responsive configuration 30 */ 31 let columnDesktop = $this.data('desktop-column'); 32 let columnTablet = $this.data('tablet-column'); 33 let columnPhone = $this.data('phone-column'); 34 35 /** 36 * Initialize Owl Carousel with responsive settings 37 */ 38 $this.find('.owl-carousel.dsf_ig_slider').owlCarousel({ 39 items: 1, // Default number of items 40 loop: true, // Infinite looping 41 nav: true, // Show navigation arrows 42 dots: true, // Show pagination dots 43 autoplay: false, // Disable auto-play by default 44 autoplayTimeout: 3000, // Auto-play interval if enabled 45 navText: ['<span class="prev-arrow">â¹</span>', '<span class="next-arrow">âº</span>'], // Custom arrow icons 46 47 /** 48 * Responsive breakpoint configuration 49 */ 50 responsive: { 51 // Phone viewport 52 0: { 53 items: columnPhone || 1, // Default to 1 item on phone 54 margin: spacingMobile // Use mobile spacing 55 }, 56 // Tablet viewport 57 768: { 58 items: columnTablet || 2, // Default to 2 items on tablet 59 margin: spacingTablet // Use tablet spacing 60 }, 61 // Desktop viewport 62 981: { 63 items: columnDesktop || 3, // Default to 3 items on desktop 64 margin: spacingDesktop // Use desktop spacing 65 } 66 } 67 }); 68 }); 69}); 70 71// Store the next page cursor per container 72let nextCursor = {}; 73 74/** 75 * Instagram Popup Modal Functionality 76 * 77 * Handles: 78 * - Post click events 79 * - Media type detection and rendering 80 * - Popup content population 81 * - Popup show/hide functionality 82 */ 83jQuery(document).ready(function ($) { 84 /** 85 * Event delegation for post clicks (works with dynamically added posts) 86 */ 87 $(document).on("click", ".dsf_ig_feed_item", function () { 88 // Get post identification data 89 let postId = $(this).data("id"); 90 let postObject = $(this).data("object"); 91 92 // Validate post data object exists 93 if (typeof window[postObject] === "undefined") { 94 console.error("Instagram data object not found:", postObject); 95 return; 96 } 97 98 // Find the specific post data 99 let postData = window[postObject].media.find(post => String(post.id) === String(postId)); 100 101 if (!postData) { 102 console.error("Post data not found for ID:", postId); 103 return; 104 } 105 106 /** 107 * Cache DOM elements for popup 108 */ 109 110 let popupSelector = "." + postObject + " .dsf_ig_popup"; 111 112 let popup = $(popupSelector); 113 let popupLeft = popup.find(".dsf_ig_popup_left"); 114 let popupRight = popup.find(".dsf_ig_popup_right"); 115 let popupImage = popupLeft.find("img"); 116 let popupVideoContainer = popupLeft.find(".dsf_popup_video_container"); 117 let carousel = popupLeft.find(".dsf_popup_carousel"); 118 119 // Clear previous content 120 popupVideoContainer.empty().hide(); 121 popupImage.hide(); 122 carousel.empty().hide(); 123 124 /** 125 * Handle different media types 126 */ 127 128 // Carousel Album (multiple media items) 129 if (postData.media_type === "CAROUSEL_ALBUM" && postData.carousel_items.length > 0) { 130 // Create slides for each carousel item
131 postData.carousel_items.forEach(item => { 132 let slideContent = (item.media_type === "VIDEO") 133 ? `<video controls><source src="${item.media_url}" type="video/mp4"></video>` 134 : `<img src="${item.media_url}" alt="Carousel Image">`; 135 136 carousel.append(`<div class="dsf_popup_slide">${slideContent}</div>`); 137 }); 138 139 // Destroy previous Owl Carousel instance if exists 140 if (carousel.hasClass("owl-loaded")) { 141 carousel.trigger("destroy.owl.carousel").removeClass("owl-loaded"); 142 } 143 144 // Initialize new Owl Carousel for the carousel album 145 carousel.owlCarousel({ 146 items: 1, // Single item visible 147 loop: true, // Infinite looping 148 nav: true, // Show navigation arrows 149 dots: true // Show pagination dots 150 }); 151 152 carousel.show(); 153 154 } 155 // Video post 156 else if (postData.media_type === "VIDEO") { 157 popupVideoContainer.append(` 158 <video controls autoplay> 159 <source src="${postData.media_url}" type="video/mp4"> 160 </video> 161 `).show(); 162 163 } 164 // Single image post 165 else { 166 popupImage.attr("src", postData.media_url).show(); 167 } 168 169 /** 170 * Update post details in the popup 171 */ 172 173 // User information 174 popupRight.find(".dsf_ig_popup_username").text(postData.username || ""); 175 popupRight.find(".dsf_ig_popup_date").text(postData.timestamp || ""); 176 177 let caption = postData.caption || ""; 178 caption = caption.replace(/\n/g, "<br>"); 179 180 popupRight.find(".dsf_ig_popup_caption").html(caption); 181 182 // Engagement metrics 183 popupRight.find(".dsf_ig_like_count .like-count") 184 .text(postData.like_count ?? "0"); 185 186 popupRight.find(".dsf_ig_comment_count .comment-count") 187 .text(postData.comments_count ?? "0"); 188 189 // Show the popup 190 popup.fadeIn(function () { 191 $("body").addClass("dsf-popup-open"); //Add class when popup opens 192 }); 193 }); 194 195 /** 196 * Popup close handlers 197 */ 198 $(document).on("click", ".dsf_ig_popup_close", function () { 199 $(this).closest(".dsf_ig_popup").dsfClosePopup(); 200 }); 201 202 $(document).on("click", function (e) { 203 if ($(e.target).hasClass("dsf_ig_popup")) { 204 $(e.target).dsfClosePopup(); 205 } 206 }); 207}); 208 209 210 jQuery(document).ready(function ($) { 211 $(".dsf_ig_post_caption").each(function () { 212 let text = $(this).text(); 213 // Replace the literal <br /> (or <br>) text with actual line breaks 214 text = text.replace(/<br\s*\/?>/gi, "<br>"); 215 $(this).html(text); 216 }); 217}); 218 219/** 220 * Masonry Grid Layout Initialization 221 * 222 * Sets up the masonry layout for grid displays 223 */ 224 225jQuery(document).ready(function ($) { 226 var $grid = $('.dsf_ig_grid_masonry'); 227 228 // wait until images are loaded 229 $grid.imagesLoaded(function () { 230 $grid.masonry({ 231 itemSelector: '.dsf_ig_feed_item', 232 columnWidth: '.grid-sizer', 233 gutter: '.gutter-sizer', 234 percentPosition: true 235 }); 236 }); 237}); 238 239jQuery(document).ready(function ($) { 240 $.fn.dsfClosePopup = function () { 241 return this.each(function () { 242 let $popup = $(this); 243 244 // Stop all videos inside this popup 245 $popup.find("video").each(function () { 246 this.pause(); 247 this.currentTime = 0; 248 }); 249 250 // Close popup 251 $popup.fadeOut(function () { 252 $("body").removeClass("dsf-popup-open"); 253 }); 254 }); 255 }; 256});
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.