1/** 2 * Archivo: assets/js/colabwp-frontend.js 3 * Descripción: Scripts especÃficos para el frontend 4 */ 5 6jQuery(document).ready(function($) { 7 //console.log('colabwp-frontend.js cargado'); 8 9 // Obtener traducciones 10 var i18n = window.colabwp_i18n || { 11 showing: 'Showing', 12 of: 'of', 13 show_more_posts: 'Show more posts', 14 hide_posts: 'Hide Posts', 15 view_posts: 'View Posts', 16 no_image: 'No image', 17 loading: 'Loading...', 18 error_loading: 'Error loading posts', 19 posts: 'posts', 20 post: 'post', 21 collaborated: 'collaborated' 22 }; 23 24 // Solo inicializar posts si hay contenedores en la página 25 function initializePostsContainers() { 26 var $containers = $('.colabwp-posts-container'); 27 28 if ($containers.length > 0) { 29 //console.log('Contenedores de posts encontrados:', $containers.length); 30 $containers.each(function() { 31 initColaboradorPosts($(this)); 32 }); 33 } 34 } 35 36 // Función para inicializar posts de un colaborador 37 function initColaboradorPosts($container) { 38 var postsData = $container.attr('data-posts'); 39 var totalPosts = parseInt($container.attr('data-total') || '0'); 40 var uniqueId = $container.attr('data-unique-id'); 41 42 if (!postsData || totalPosts === 0) { 43 return; 44 } 45 46 var posts = []; 47 try { 48 posts = JSON.parse(postsData); 49 } catch (e) { 50 console.error('Error parsing posts JSON:', e); 51 return; 52 } 53 54 var postsPerPage = 10; 55 var currentPage = 0; 56 var showingCount = 0; 57 58 var $grid = $('#posts-grid-' + uniqueId); 59 var $loadMoreBtn = $('#load-more-' + uniqueId); 60 var $progressInfo = $('#progress-' + uniqueId); 61 var $loadMoreContainer = $loadMoreBtn.parent(); 62 63 // Ocultar controles si hay pocos posts 64 if (totalPosts <= postsPerPage) { 65 $progressInfo.hide(); 66 $loadMoreContainer.hide(); 67 } 68 69 // Función para crear HTML de post 70 function createPostHTML(post) { 71 var imageHTML = ''; 72 if (post.image && post.image !== '') { 73 imageHTML = '<img src="' + post.image + '" alt="' + escapeHtml(post.title) + '">'; 74 } else { 75 imageHTML = '<div class="no-image">
75' + i18n.no_image + '</div>'; 76 } 77 78 return '<a href="' + post.url + '" class="colabwp-post-item" rel="nofollow noreferrer noopener">' + 79 '<div class="colabwp-post-image' + (post.image ? '' : ' no-image') + '">' + 80 imageHTML + 81 '</div>' + 82 '<div class="colabwp-post-content">' + 83 '<p class="colabwp-post-title">' + escapeHtml(post.title) + '</p>' + 84 '</div>' + 85 '</a>'; 86 } 87 88 // Función para escapar HTML 89 function escapeHtml(text) { 90 if (!text) return ''; 91 var map = { 92 '&': '&', 93 '<': '<', 94 '>': '>', 95 '"': '"', 96 "'": ''' 97 }; 98 return String(text).replace(/[&<>"']/g, function(m) { return map[m]; }); 99 } 100 101 // Función para mostrar posts 102 function showPosts() { 103 var startIndex = currentPage * postsPerPage; 104 var endIndex = Math.min(startIndex + postsPerPage, posts.length); 105 106 for (var i = startIndex; i < endIndex; i++) { 107 if (posts[i]) { 108 var postHTML = createPostHTML(posts[i]); 109 $grid.append(postHTML); 110 } 111 } 112 113 showingCount = endIndex; 114 updateProgress(); 115 116 if (endIndex >= posts.length) { 117 $loadMoreContainer.hide(); 118 } 119 120 currentPage++; 121 } 122 123 // Función para actualizar progreso 124 function updateProgress() { 125 if (totalPosts <= postsPerPage) return; 126 127 var percentage = Math.round((showingCount / totalPosts) * 100); 128 129 $progressInfo.find('.current-count').text(showingCount); 130 $progressInfo.find('.colabwp-progress-fill').css('width', percentage + '%'); 131 } 132 133 // Event listener para botón mostrar más 134 $loadMoreBtn.on('click', function(e) { 135 e.preventDefault(); 136 showPosts(); 137 }); 138 139 // Mostrar primeros posts 140 showPosts(); 141 } 142 143 // Scroll suave para badges de posts 144 $(document).on('click', '.colabwp-scroll-to-posts', function(e) { 145 e.preventDefault(); 146 var target = $($(this).attr('href')); 147 if (target.length) { 148 $('html, body').animate({ 149 scrollTop: target.offset().top - 50 150 }, 800); 151 } 152 }); 153 154 // Inicializar al cargar 155 initializePostsContainers(); 156 157 // Re-inicializar si se añaden nuevos elementos dinámicamente 158 window.reinitColabwpPosts = function() { 159 initializePostsContainers(); 160 }; 161}); 162 163// Función global para inicializar carrusel 164window.colabwpInitCarousel = function(carouselId) { 165 var $ = jQuery; 166 var $wrapper = $('#' + carouselId); 167 if (!$wrapper.length || $wrapper.data('carousel-initialized')) return; 168 169 var $container = $wrapper.find('.colabwp-carousel-container'); 170 var $track = $wrapper.find('.colabwp-carousel-track'); 171 var $inner = $wrapper.find('.colabwp-carousel-inner'); 172 var $items = $wrapper.find('.colabwp-carousel-item'); 173 var $prevBtn = $wrapper.find('.colabwp-carousel-prev'); 174 var $nextBtn = $wrapper.find('.colabwp-carousel-next'); 175 var $dots = $('#dots-' + carouselId); 176 var $dotButtons = $dots.find('.colabwp-carousel-dot'); 177 178 if ($items.length === 0) return; 179 180 var currentIndex = 0; 181 var itemsToShow = 3; 182 var itemsToScroll = 1; 183 var maxIndex = 0; 184 var isMobile = false; 185 186 function calculateItemsToShow() { 187 var windowWidth = $(window).width(); 188 if (windowWidth <= 480) { 189 itemsToShow = 1; 190 isMobile = true; 191 } else if (windowWidth <= 768) { 192 itemsToShow = 2; 193 isMobile = true; 194 } else if (windowWidth <= 992) { 195 itemsToShow = 2; 196 isMobile = false;
197 } else { 198 itemsToShow = 3; 199 isMobile = false; 200 } 201 202 maxIndex = Math.max(0, $items.length - itemsToShow); 203 204 if (currentIndex > maxIndex) { 205 currentIndex = maxIndex; 206 } 207 208 updateNavigationVisibility(); 209 updateDotsVisibility(); 210 } 211 212 function updateNavigationVisibility() { 213 if (isMobile) return; 214 215 if ($items.length <= itemsToShow) { 216 $prevBtn.addClass('hidden'); 217 $nextBtn.addClass('hidden'); 218 return; 219 } 220 221 if (currentIndex === 0) { 222 $prevBtn.addClass('hidden'); 223 } else { 224 $prevBtn.removeClass('hidden'); 225 } 226 227 if (currentIndex >= maxIndex) { 228 $nextBtn.addClass('hidden'); 229 } else { 230 $nextBtn.removeClass('hidden'); 231 } 232 } 233 234 function updateDotsVisibility() { 235 if (!$dots.length) return; 236 237 $dotButtons.hide().removeClass('active'); 238 239 var dotsNeeded = Math.ceil($items.length / itemsToShow); 240 for (var i = 0; i < dotsNeeded; i++) { 241 $dotButtons.eq(i).show(); 242 } 243 244 var activeDotIndex = Math.floor(currentIndex / itemsToShow); 245 $dotButtons.eq(activeDotIndex).addClass('active'); 246 } 247 248 function updateCarousel() { 249 var itemWidth = $items.first().outerWidth(); 250 var gap = parseInt($inner.css('gap')) || 25; 251 var translateX = -(currentIndex * (itemWidth + gap)); 252 253 $inner.css('transform', 'translateX(' + translateX + 'px)'); 254 255 updateNavigationVisibility(); 256 updateDots(); 257 } 258 259 function updateDots() { 260 if (!$dots.length) return; 261 262 $dotButtons.removeClass('active'); 263 264 var activeDotIndex = Math.floor(currentIndex / itemsToShow); 265 $dotButtons.eq(activeDotIndex).addClass('active'); 266 } 267 268 $prevBtn.on('click', function() { 269 if (currentIndex > 0) { 270 currentIndex -= itemsToScroll; 271 if (currentIndex < 0) currentIndex = 0; 272 updateCarousel(); 273 } 274 }); 275 276 $nextBtn.on('click', function() { 277 if (currentIndex < maxIndex) { 278 currentIndex += itemsToScroll; 279 if (currentIndex > maxIndex) currentIndex = maxIndex; 280 updateCarousel(); 281 } 282 }); 283 284 $dotButtons.on('click', function() { 285 var dotIndex = $(this).data('index'); 286 287 if (isMobile) { 288 currentIndex = dotIndex * itemsToShow; 289 if (currentIndex > maxIndex) currentIndex = maxIndex; 290 } else { 291 currentIndex = dotIndex; 292 } 293 294 updateCarousel(); 295 }); 296 297 var touchStartX = 0; 298 var touchEndX = 0; 299 var isDragging = false; 300 301 $track.on('touchstart', function(e) { 302 touchStartX = e.originalEvent.touches[0].clientX; 303 isDragging = true; 304 }); 305 306 $track.on('touchmove', function(e) { 307 if (!isDragging) return; 308 touchEndX = e.originalEvent.touches[0].clientX; 309 }); 310 311 $track.on('touchend', function(e) { 312 if (!isDragging) return; 313 isDragging = false; 314 315 var swipeDistance = touchStartX - touchEndX; 316 var threshold = 50; 317 318 if (Math.abs(swipeDistance) > threshold) { 319 if (swipeDistance > 0 && currentIndex < maxIndex) { 320 if (isMobile) { 321 currentIndex = Math.min(currentIndex + itemsToShow, maxIndex); 322 } else { 323 currentIndex = Math.min(currentIndex + itemsToScroll, maxIndex); 324 } 325 updateCarousel(); 326 } else if (swipeDistance < 0 && currentIndex > 0) { 327 if (isMobile) { 328 currentIndex = Math.max(currentIndex - itemsToShow, 0); 329 } else { 330 currentIndex = Math.max(currentIndex - itemsToScroll, 0); 331 } 332 updateCarousel(); 333 } 334 } 335 }); 336 337 $(document).on('keydown', function(e) { 338 if (isMobile) return; 339 340 var carouselTop = $wrapper.offset().top; 341 var carouselBottom = carouselTop + $wrapper.height(); 342 var viewportTop = $(window).scrollTop(); 343 var viewportBottom = viewportTop + $(window).height(); 344 345 if (carouselBottom > viewportTop && carouselTop < viewportBottom) { 346 if (e.key === 'ArrowLeft' && currentIndex > 0) { 347 e.preventDefault(); 348 currentIndex -= itemsToScroll; 349 if (currentIndex < 0) currentIndex = 0; 350 updateCarousel(); 351 } else if (e.key === 'ArrowRight' && currentIndex < maxIndex) { 352 e.preventDefault(); 353 currentIndex += itemsToScroll; 354 if (currentIndex > maxIndex) currentIndex = maxIndex; 355 updateCarousel(); 356 } 357 } 358 }); 359 360 var resizeTimer; 361 $(window).on('resize', function() { 362 clearTimeout(resizeTimer); 363 resizeTimer = setTimeout(function() { 364 calculateItemsToShow(); 365 updateCarousel(); 366 }, 250); 367 }); 368 369 calculateItemsToShow(); 370 updateCarousel(); 371 372 if ($prevBtn.data('initial-hidden') === true && currentIndex === 0) { 373 $prevBtn.addClass('hidden'); 374 } 375 376 $wrapper.data('carousel-initialized', true); 377};
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.