1 2/* =============== DOCUMENT READY =============== */ 3let skipScrollingAnimation = false; 4$(document).ready(function () { 5 /*Generate Blogs html from Json Data*/ 6 jsontoHtml(); 7 /* Generate JumpTo Section */ 8 if ($('.samBlog_PDP').length > 0 && $('.samBlog_PDP_Bio').length < 1) { 9 // Collect all <h2> elements 10 var headings = $('.samBlog_PDP_Article_Section h2'); 11 12 // Loop through each <h2> element 13 headings.each(function(index) { 14 var heading = $(this); 15 16 // Generate a unique ID for each <h2> if it doesn't already have one 17 var id = heading.attr('id') || 'heading-' + index; 18 heading.attr('id', id); 19 20 // Create an <li> tag containing an <a> tag pointing to the <h2>'s ID 21 var link = $('<a></a>') 22 .attr('href', '#' + id) 23 .text(heading.text()); 24 25 var listItem = $('<div class="jumpto_list"></div>').append(link); 26 27 // Add the <li> to the container 28 $(".samBlog_JumpTo .jumpto_list_container").append(listItem); 29 }); 30 31 // Smooth scrolling effect for the links 32 $('.samBlog_JumpTo a').on('click', function(event) { 33 event.preventDefault(); // Prevent the default anchor click behavior 34 35 var targetId = $(this).attr('href'); 36 var target = $(targetId); 37 var adjustTopScroll = 100; //Mobile 38 39 if (screen.width > 991) { 40 adjustTopScroll = 150; //Desktop 41 } 42 43 if (target.length) { 44 $('html, body').animate({ 45 scrollTop: target.offset().top - adjustTopScroll 46 }, 300); 47 } 48 }); 49 50 } 51 52 53 54 /* Toggle JumpTo Section (Author Page Only) */ 55 $(".samBlog.samBlog_PDP_Bio .jumpto_title").on("click", function () { 56 $(".samBlog.samBlog_PDP_Bio .jumpto_list").slideToggle(); 57 $(".samBlog.samBlog_PDP_Bio .samBlog_JumpTo").toggleClass('collapsed'); 58 }); 59 if (screen.width < 992) { 60 /* Collapsed by default on mobile */ 61 $(".samBlog.samBlog_PDP_Bio .jumpto_list").slideToggle(0); 62 $(".samBlog.samBlog_PDP_Bio .samBlog_JumpTo").toggleClass('collapsed'); 63 /* end */ 64 } 65 /* end */ 66 67 /* Toggle Sticky JumpTo_Sticky Section (PDP Only) */ 68 $(".samBlog_JumpTo_Sticky .jumpto_title").click(function (event) { 69 event.stopPropagation(); 70 $(".samBlog_JumpTo_Sticky").toggleClass("expand"); 71 }); 72 73 74 /* Instant Search and Pagination */ 75 // Store a reference to all items for global search 76 const allItems = $(".samIS_Product_Grid").children().clone(); 77 78 // Search Functionality 79 $(".samIS_SearchInput").on("keyup", function () { 80 const searchTerm = $(this).val().toLowerCase(); 81 82 // Filter items based on the search term 83 const filteredItems = allItems.filter(function () { 84 const keyword = $(this).data("keyword").toLowerCase(); 85 return keyword.includes(searchTerm); 86 }); 87 88 // Update the total number of items found 89 $(".samIS_SearchTotal").text(`${filteredItems.length} articles found`); 90 // if (searchTerm == '') { 91 // $(".samIS_SearchTotal").text(''); 92 // } 93 94 /* Reset Pagination with filtered items (itemsOverride) from Instant Search */ 95 samPagination_Start({ 96 gridSelector: ".samIS_Product_Grid", 97 paginationContainerSelector: ".samPaginationContainer", 98 itemsPerPage: 6, 99 dateSelector: ".samIS_Product_Date", 100 viewAllBtnSelector: ".samPC_ViewAllBtn", 101 prevBtnSelector: ".samPC_PrevBtn", 102 nextBtnSelector: ".samPC_NextBtn", 103 pageNumberContainerSelector: ".samPC_PageNumber", 104 itemsOverride: filteredItems, // Pass the filtered items for rendering from the Instant Search function 105 }); 106 107 skipScrollingAnimation = true; 108 samAddLazyLoadToImg(); // Add Lazy Load; 109 });
110 111 /* 112 - Initialize Pagination on page load 113 - itemsOverride is null because No Instant Search on page load 114 */ 115 samPagination_Start({ 116 gridSelector: ".samIS_Product_Grid", 117 paginationContainerSelector: ".samPaginationContainer", 118 itemsPerPage: 6, 119 dateSelector: ".samIS_Product_Date", 120 viewAllBtnSelector: ".samPC_ViewAllBtn", 121 prevBtnSelector: ".samPC_PrevBtn", 122 nextBtnSelector: ".samPC_NextBtn", 123 pageNumberContainerSelector: ".samPC_PageNumber", 124 }); 125 /* end */ 126 127 128 129 /* Read Length Calcuation (PDP Only)*/ 130 if ($('.samBlog_PDP').length > 0) { 131 // Get all paragraph texts 132 const paragraphTexts = $('p').map(function () { 133 return $(this).text(); // Extract text content 134 }).get(); // Convert jQuery object to a plain array 135 136 // Calculate reading time 137 let readingTime = samBlog_CalculateReadingTime(paragraphTexts); 138 readingTime = readingTime.toString().split('.')[0]; 139 if ($('.samBlog_Read_Duration').length > 0) { 140 141 if (readingTime.indexOf("seconds") >= 0) { 142 $('.samBlog_Read_Duration').html('Less than a minute read'); 143 } else { 144 $('.samBlog_Read_Duration').html(readingTime + ' min read'); 145 } 146 } 147 } 148 /* end */ 149 150 151 samAddLazyLoadToImg(); //Add Lazy Load; 152 153 154}); 155/* =============== END DOCUMENT READY =============== */ 156 157 158 159function samPagination_Start({ 160 gridSelector, 161 paginationContainerSelector, 162 itemsPerPage, 163 dateSelector, 164 viewAllBtnSelector, 165 prevBtnSelector, 166 nextBtnSelector, 167 pageNumberContainerSelector, 168 itemsOverride = null, // Allow overriding items for search 169}) { 170 const grid = $(gridSelector); 171 const paginationContainer = $(paginationContainerSelector); 172 const viewAllBtn = $(viewAllBtnSelector); 173 const prevBtn = $(prevBtnSelector); 174 const nextBtn = $(nextBtnSelector); 175 const pageNumberContainer = $(pageNumberContainerSelector); 176 177 // Use overridden items if provided, otherwise use all items from the grid 178 const items = itemsOverride || $(gridSelector).children(); 179 const sortedItems = items.sort((a, b) => { 180 const dateA = new Date($(a).find(dateSelector).text().replace("Publish: ", "")); 181 const dateB = new Date($(b).find(dateSelector).text().replace("Publish: ", "")); 182 return dateB - dateA; // Descending 183 }); 184 185 let currentPage = 1; 186 const totalPages = Math.ceil(sortedItems.length / itemsPerPage); 187 188 function renderItems(page) { 189 grid.empty(); 190 const start = (page - 1) * itemsPerPage; 191 const end = start + itemsPerPage; 192 193 const fragment = document.createDocumentFragment(); 194 sortedItems.slice(start, end).each(function () { 195 fragment.appendChild(this); 196 }); 197 grid.append(fragment); 198 } 199 200 function renderPagination() { 201 pageNumberContainer.empty(); 202 203 // Disable buttons if on first or last page 204 prevBtn.prop("disabled", currentPage === 1); 205 nextBtn.prop("disabled", currentPage === totalPages); 206 207 if (totalPages <= 5) { 208 for (let i = 1; i <= totalPages; i++) { 209 pageNumberContainer.append( 210 `<button class="btn btn-secondary btn-sm page-number${i === currentPage ? " active" : ""}" data-page="${i}">${i}</button>` 211 ); 212 } 213 } else { 214 const startPage = Math.max(currentPage - 2, 1); 215 const endPage = Math.min(startPage + 4, totalPages); 216 217 if (startPage > 1) { 218 pageNumberContainer.append(`<button class="btn btn-secondary btn-sm page-number" data-page="1">1</button>`); 219 if (startPage > 2) { 220 pageNumberContainer.append('<span class="dots">...</span>'); 221 } 222 } 223 224 for (let i = startPage; i <= endPage; i++) { 225 pageNumberContainer.append( 226 `<button class="btn btn-secondary btn-sm page-number${i === currentPage ? " active" : ""}" data-page="${i}">${i}</button>` 227 ); 228 } 229 230 if (endPage < totalPages) { 231 if (endPage < totalPages - 1) { 232 pageNumberContainer.append('<span class="dots">...</span>'); 233 } 234 pageNumberContainer.append( 235 `<button class="btn btn-secondary btn-sm page-number" data-page="${totalPages}">${totalPages}</button>` 236 ); 237 } 238 } 239 240 samAddLazyLoadToImg(); // Add Lazy Load; 241 242 } 243 244 function scrollToGrid() { 245 246 /* Skip scrolling if search function is used */
247 var scrollDelay = 300; 248 if (skipScrollingAnimation == true) { 249 scrollDelay = 0; 250 } 251 252 // console.log("TEST: " + scrollDelay); 253 showWait("B"); 254 $("html, body").animate( 255 { scrollTop: grid.offset().top - 220 }, 256 scrollDelay, 257 "swing", 258 function () { 259 hideWait(); 260 } 261 ); 262 263 } 264 265 pageNumberContainer.on("click", ".page-number", function () { 266 currentPage = parseInt($(this).data("page"), 10); 267 renderItems(currentPage); 268 renderPagination(); 269 scrollToGrid(); 270 }); 271 272 prevBtn.click(function () { 273 if (currentPage > 1) { 274 currentPage--; 275 renderItems(currentPage); 276 renderPagination(); 277 scrollToGrid(); 278 } 279 }); 280 281 nextBtn.click(function () { 282 if (currentPage < totalPages) { 283 currentPage++; 284 renderItems(currentPage); 285 renderPagination(); 286 scrollToGrid(); 287 } 288 }); 289 290 viewAllBtn.click(function () { 291 grid.empty(); 292 grid.append(sortedItems); // Show all items 293 paginationContainer.hide(); // Hide pagination 294 scrollToGrid(); 295 }); 296 297 // Initialize 298 renderItems(currentPage); 299 renderPagination(); 300} 301 302function samBlog_ToggleMenu() { 303 const menu = document.querySelector('.samBlog_Navigation .menu'); 304 menu.style.display = menu.style.display === 'flex' ? 'none' : 'flex'; 305} 306 307 308function samBlog_CalculateReadingTime(texts) { 309 const wordsPerMinute = 200; // Words per minute 310 let totalWords = 0; 311 312 // Loop through the array of texts and count words 313 texts.forEach(function (text) { 314 const wordCount = text.trim().split(/\s+/).length; // Count words 315 totalWords += wordCount; 316 }); 317 318 // Calculate the reading time in minutes 319 const readingTime = totalWords / wordsPerMinute; 320 321 // Format the reading time (e.g., "1.5 minutes" or "1 minute") 322 const formattedReadingTime = 323 readingTime < 1 324 ? Math.ceil(readingTime * 60) + ' seconds' 325 : readingTime.toFixed(1) + ' minutes'; 326 327 return formattedReadingTime; 328} 329function jsontoHtml(){ 330 if ($('.samBlog_PDP').length > 0) {return;}//Don't Execute on PDP! 331 if($('#json-blogs').length<1){return;} 332 if($('#json-categs').length<1){return;} 333 const jsonData = document.getElementById("json-blogs").textContent; 334 const blogs = JSON.parse(jsonData); 335 showWait(); 336 if(blogs.length < 1) $('.samIS_SearchTotal').html('No articles Found'); 337 if(blogs.length == 1) $('.samIS_SearchTotal').html(blogs.length + ' article'); 338 if(blogs.length > 1) $('.samIS_SearchTotal').html(blogs.length + ' articles'); 339 $('#blogsList').html(''); 340 const categsData = document.getElementById("json-categs").textContent; 341 const categories = JSON.parse(categsData); 342 for (const blog of blogs) { 343 344 // Get the template 345 var template = $('#blogTemplate').html(); 346 // Clone the template 347 var clonedItem = $(template); 348 349 // Adjust content of the cloned item 350 clonedItem.find('img').attr('src', $("#imgpath").val()+ '/' + blog.img); 351 clonedItem.find('img').attr('data-original', $("#imgpath").val()+ '/' + blog.img); 352 clonedItem.find('a').attr('href',buildCategoryUrl(categories,blog.bcno)+'/'+blog.url); 353 clonedItem.find('h5').text(blog.titl); 354 clonedItem.find('p').text(blog.metd); 355 clonedItem.attr('data-keyword',blog.titl+' '+blog.metd); 356 // Get current date 357 try{ 358 var dateString = blog.pbdt.toString(); 359 360 // Extract the parts of the date 361 var year = dateString.substring(0, 4); 362 var month = dateString.substring(4, 6) - 1; // Months are 0-indexed, so subtract 1 363 var day = dateString.substring(6, 8); 364 var date = new Date(year, month, day); 365 var formattedDate = new Intl.DateTimeFormat('en-US', { 366 month: 'long', // Full month name (e.g., "February") 367 day: '2-digit', // 2-digit day (e.g., "04") 368 year: 'numeric' // Full year (e.g., "2025") 369 }).format(date); 370 clonedItem.find('span').text("Published: " +formattedDate); 371 }catch(e){ 372 clonedItem.find('span').text("Published: " +blog.pbdt); 373 } 374 $('#blogsList').append(clonedItem); 375 376 } 377 378 //Paint categories: 379 let middlemenu = $("#blogmiddlemenu"); 380 let parentCatg = $("#parentCategory").val(); 381 382 $( "#blogCategories" ).hide(); 383 for (const categ of categories) { 384 if(categ.bcnp==parentCatg || categ.bcnp==null && parentCatg==''){ 385 386 middlemenu.append('<a href="'+buildCategoryUrl(categories,categ.bcno)+ 387 '" class="btn btn-secondary btn-sm"><span>'+categ.desc+'</span></a>'); 388 $( "#blogCategories" ).show(); 389 } 390 } 391 392 hideWait(); 393 } 394 395 function buildCategoryUrl(categories, bcno) { 396 const categoryMap = new Map(categories.map(cat => [cat.bcno, cat])); 397 398 let path = []; 399 let current = categoryMap.get(bcno); 400 401 while (current) { 402 path.unshift(current.url); // Add category name to the beginning 403 current = categoryMap.get(current.bcnp); // Move to parent 404 } 405 406 if(path.length>0) 407 return '/blog/' + path.join('/'); // Construct URL path 408 else 409 return '/blog' ; // Construct URL path 410 } 411
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.