1jQuery(document).ready(function ($) { 2 3 const postsPerPage = 3; 4 5 $('.project-wrapper').each(function () { 6 const section = $(this); 7 const category = section.data('category'); 8 const uid = section.attr('id'); 9 10 let postsLoaded = 0; 11 12 // Load initial 13 loadProjects('init'); 14 15 // === Buttons === 16 section.find('.showMoreBtn').on('click', function () { 17 loadProjects('more'); 18 }); 19 section.find('.showAllBtn').on('click', function () { 20 loadProjects('all'); 21 }); 22 section.find('.showLessBtn').on('click', function () { 23 var locationEle = $(this).data('location'); 24 loadProjects('less',locationEle); 25 }); 26 27 // === Function: Load Projects === 28 function loadProjects(type,target = '') { 29 let offsetToSend = 0; 30 31 let perPageToSend = postsPerPage; 32 33 if (type === 'more') { 34 offsetToSend = postsLoaded; 35 } else if (['less', 'init'].includes(type)) { 36 offsetToSend = 0; 37 } else if (type === 'all') { 38 offsetToSend = 0; 39 perPageToSend = -1; 40 } 41 42 var headerHeight = $('#main-header').outerHeight(); 43 44 $.ajax({ 45 url: projectCrousalAjax.ajax_url, 46 type: 'POST', 47 dataType: 'json', 48 data: { 49 action: 'load_projects_grid', 50 category: category, 51 type: type, 52 offset: offsetToSend, 53 per_page: perPageToSend, 54 55 }, 56 success: function (response) { 57 if (!response.success) return; 58 59 const data = response.data; 60 const cards = section.find('.projectCards'); 61 62 if (['less', 'init', 'all'].includes(type)) { 63 cards.html(data.html); 64 } else if (type === 'more') { 65 cards.append(data.html); 66 } 67 68 postsLoaded = data.loaded; 69 70 // Button logic 71 const btnMore = section.find('.showMoreBtn'); 72 const btnAll = section.find('.showAllBtn'); 73 const btnLess = section.find('.showLessBtn'); 74 75 if (['less', 'init'].includes(type)) { 76 btnMore.removeClass('d-none'); 77 btnAll.removeClass('d-none'); 78 btnLess.addClass('d-none'); 79 80 console.log(target); 81 if(target != ''){ 82 //$('[data-link="#'+target+'"]').trigger('click'); 83 var headerHeight = $('#main-header').outerHeight(); 84 $('html, body').animate({ 85 scrollTop: $('#'+target).offset().top - headerHeight - 100 86 }, 600); 87 } 88 89 } else if (type === 'more') { 90 if (data.all_loaded || !data.html.trim()) { 91 btnMore.addClass('d-none'); 92 btnAll.addClass('d-none'); 93 btnLess.removeClass('d-none'); 94 } else { 95 btnMore.removeClass('d-none'); 96 btnAll.addClass('d-none'); 97 btnLess.addClass('d-none'); 98 } 99 } else if (type === 'all') { 100 btnMore.addClass('d-none'); 101 btnAll.addClass('d-none'); 102 btnLess.removeClass('d-none'); 103 } 104 105 bindReadMore(); 106 } 107 }); 108 } 109 110 // === Function: Bind Read More Buttons === 111 function bindReadMore() { 112 section.find('.read-more-btn').off('click').on('click', function () { 113 const postID = $(this).data('id'); 114 openProjectPopup(postID); 115 }); 116 } 117 118 function openProjectPopup(postID){ 119 const modal = $('#modal_projects'); 120 $.ajax({ 121 url: projectCrousalAjax.ajax_url, 122 type: 'POST', 123 dataType: 'json', 124 data: { 125 action: 'load_project_details', 126 post_id: postID 127 }, 128 success: function (response) { 129 if (!response.success) return; 130 const data = response.data; 131
132 const modalBody = modal.find('.modal-body'); 133 134 // === Build Carousel === 135 let carouselHTML = ''; 136 if (data.images && data.images.length > 0) { 137 carouselHTML = ` 138 <div id="projectCarousel" class="carousel slide mb-4" data-bs-ride="carousel"> 139 <div class="carousel-inner"> 140 ${data.images.map((img, index) => ` 141 <div class="carousel-item ${index === 0 ? 'active' : ''}"> 142 <img src="${img}" class="d-block w-100 rounded" alt="Project Image"> 143 </div> 144 `).join('')} 145 </div> 146 147 ${ 148 data.images.length > 1 149 ? ` 150 <button class="carousel-control-prev" type="button" data-bs-target="#projectCarousel" data-bs-slide="prev"> 151 <span class="carousel-control-prev-icon" aria-hidden="true"></span> 152 </button> 153 <button class="carousel-control-next" type="button" data-bs-target="#projectCarousel" data-bs-slide="next"> 154 <span class="carousel-control-next-icon" aria-hidden="true"></span> 155 </button> 156 ` 157 : '' 158 } 159 </div> 160 `; 161 } else { 162 carouselHTML = '<div> <p class="text-center text-muted mb-4">No images available.</p>'; 163 } 164 165 // === Build Title + Content Section === 166 const detailsHTML = ` 167 <div class="project-info"> 168 <h4 class="fw-bold mb-2">${data.title}</h4> 169 <div class="project-description">${data.content}</div> 170 </div> 171 </div> 172 `; 173 174 modalBody.html(carouselHTML + detailsHTML); 175 176 const modalInstance = new bootstrap.Modal(modal[0], { 177 backdrop: true, // â Disable background overlay 178 //keyboard: true // (optional) still allow Esc to close 179 }); 180 modalInstance.show(); 181 } 182 }); 183 } 184 185 const projectId = window.location.hash.substring(1); 186 if (typeof projectId !== "undefined" && projectId !== null && projectId !== "") { 187 openProjectPopup(projectId); 188 } 189 $(document).on('click', '.project-page-read-more-btn', function(e) { 190 e.preventDefault(); // stop normal navigation 191 let postID = $(this).data('id'); 192 openProjectPopup(postID); 193 }); 194 }); 195 196 $('#modal_projects').on('hidden.bs.modal', function () { 197 $('body').css({ 198 'overflow': 'auto', 199 'padding-right': '0' 200 }); 201 }); 202});
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.