1//window.onscroll = function () { scrollFunction() }; 2//function scrollFunction() { 3// let styleWidth = "200px"; 4// if (document.body.scrollTop > 25 || document.documentElement.scrollTop > 25) { 5// styleWidth = "135px"; 6// } 7// document.getElementById("lgLogo").style.width = styleWidth; 8//} 9 10const urlRegex = /(https?:\/\/[-A-Z0-9+&@@#\/%?=~_|!:,.;(]*[-A-Z0-9+&@@#\/%=~_|)])/ig; 11 12function setCookie(name, value, seconds) { 13 var expires = ""; 14 if (seconds) { 15 var date = new Date(); 16 date.setTime(date.getTime() + (seconds * 1000)); 17 expires = "; expires=" + date.toUTCString(); 18 } 19 document.cookie = name + "=" + (truncateByBytes(encodeURIComponent(value), 4096) || "") + expires + "; path=/"; 20} 21function getCookie(name) { 22 var nameEQ = name + "="; 23 var ca = document.cookie.split(';'); 24 for (var i = 0; i < ca.length; i++) { 25 var c = ca[i]; 26 while (c.charAt(0) == ' ') c = c.substring(1, c.length); 27 if (c.indexOf(nameEQ) == 0) return decodeURIComponent(c.substring(nameEQ.length, c.length)); 28 } 29 return null; 30} 31 32function cacheInServerMemory(name, value, seconds) { 33 $.ajax({ 34 type: "POST", 35 url: '/api/cacheinservermemory', 36 data: { 37 "name": name, 38 "value": value, 39 "seconds": seconds 40 } 41 }); 42} 43 44function getCacheInServerMemory(name) { 45 return $.ajax({ 46 type: "GET", 47 url: '/api/getcacheinservermemory', 48 data: { 49 "name": name 50 } 51 }); 52} 53
54function invalidateCacheInServerMemory(name) { 55 $.ajax({ 56 type: "POST", 57 url: '/api/invalidatecacheinservermemory', 58 data: { 59 "name": name 60 } 61 }); 62} 63 64function byteCount(string) { 65 // UTF8 66 return encodeURI(string).split(/%..|./).length - 1; 67} 68 69function truncateByBytes(string, byteSize) { 70 // UTF8 71 if (byteCount(string) > byteSize) { 72 const charsArray = string.split(''); 73 let truncatedStringArray = []; 74 let bytesCounter = 0; 75 for (let i = 0; i < charsArray.length; i++) { 76 bytesCounter += byteCount(charsArray[i]); 77 if (bytesCounter <= byteSize) { 78 truncatedStringArray.push(charsArray[i]); 79 } else { 80 break; 81 } 82 } 83 return truncatedStringArray.join(''); 84 } 85 return string; 86} 87 88function linkify(c, l = 50) { 89 return c.replace(urlRegex, function (url) { 90 return '<a href="' + url + '" target="_blank">' + truncateString(url, l) + '</a>'; 91 }); 92} 93 94function truncateString(str, num) { 95 if (str.length > num) 96 return str.slice(0, num) + "..."; 97 else 98 return str; 99} 100 101// Following misc code will execute whenever a form across the entire website is submitted 102$('form').submit(function () { 103 104 // Disable button after form submission to prevent double posting 105 // Button will only disable if _ValidationScriptsPartial.cshtml is not imported or it is imported and the validation succeeds 106 if (typeof validationScriptsPartialImported === 'undefined' || $(this).valid()) { 107 $(this).find("input[type='submit']").prop('disabled', true); 108 } 109}); 110 111function stripQueryParameters(url) { 112 return url.split("?")[0] 113} 114 115// Remove empty search query parameter (?q=) from URL if search textbox is empty. 116// Don't worry: this solution makes no extra requests... It simply intercepts the form submission and redirects to the appropriate URL. 117// It also doesn't affect pagination 118$("#searchForm").on("submit", function (e) { 119 e.preventDefault(); 120 let queryParam = $("#searchForm input").val(); 121 if (queryParam) { 122 window.location.href = stripQueryParameters(window.location.href) + `?q=${queryParam}`; 123 } else { 124 window.location.href = stripQueryParameters(window.location.href); 125 } 126}); 127 128function subscribeToEmailingList() { 129 let email = $("#emailSubscriberField").val(); 130 if (email) { 131 $.ajax({ 132 type: "POST", 133 url: '/api/subscribetoemailinglist', 134 data: { 135 "email": email 136 }, 137 success: function (data) { 138 if (data != null) { 139 if (data.result === "True") { 140 $("#emailResult").text("Subscribed"); 141 $("#emailResult").css("color", "lawngreen"); 142 } 143 else if (data.result === "Invalid") { 144 $("#emailResult").text("Invalid email address"); 145 $("#emailResult").css("color", "orange"); 146 } 147 else { 148 $("#emailResult").text("Something broke. Probably not your fault."); 149 $("#emailResult").css("color", "orange"); 150 } 151 } 152 } 153 }); 154 } 155 else { 156 $("#emailResult").text("Please enter email address"); 157 $("#emailResult").css("color", "orange"); 158 } 159} 160 161$("#submitEmailSubscriber").on("click", function () { 162 subscribeToEmailingList(); 163}); 164 165$("#emailSubscriberField").keyup(function (e) { 166 // Check if user pressed enter key 167 if (e.keyCode == 13) { 168 subscribeToEmailingList(); 169 } 170}); 171 172window.onload = function () {
173 let cbs = document.getElementsByClassName('bd-checkbox'); 174 for (let i = 0; i < cbs.length; i++) { 175 let cb = cbs[i]; 176 let cbInput = cb.querySelector('input'); 177 cb.onclick = function () { 178 cbInput.checked = !cbInput.checked; 179 if (cbInput.checked) { 180 cb.querySelector('#selectedText').style.display = 'block'; 181 cb.querySelector('#clickToSelectText').style.display = 'none'; 182 cb.classList.add('bd-checkbox-checked'); 183 } else { 184 cb.querySelector('#selectedText').style.display = 'none'; 185 cb.querySelector('#clickToSelectText').style.display = 'block'; 186 cb.classList.remove('bd-checkbox-checked'); 187 } 188 //console.log(cbInput.checked); 189 } 190 } 191} 192 193document.querySelectorAll('oembed[url]').forEach(element => { 194 let ele = document.createElement('div'); 195 ele.className = 'embed-responsive embed-responsive-16by9 mt-0 mb-3'; 196 let ifr = document.createElement('iframe'); 197 ifr.className = 'embed-responsive-item'; 198 199 let url = element.getAttribute('url'); 200 201 // Fix malformed YouTube URLs with double question marks 202 if (url.includes('youtube.com/watch?v=') && (url.match(/\?/g) || []).length > 1) { 203 // Find the position of the second '?' and replace it with '&' 204 let firstQuestionMark = url.indexOf('?'); 205 let secondQuestionMark = url.indexOf('?', firstQuestionMark + 1); 206 if (secondQuestionMark > -1) { 207 url = url.substring(0, secondQuestionMark) + '&' + url.substring(secondQuestionMark + 1); 208 } 209 } 210 211 // Handle YouTube URLs with timestamp parameters 212 if (url.includes('youtube.com/watch?v=')) { 213 // Extract video ID and parameters 214 let videoIdMatch = url.match(/[?&]v=([^&]+)/); 215 let timeMatch = url.match(/[?&]t=([^&]+)/); 216 217 if (videoIdMatch) { 218 let videoId = videoIdMatch[1]; 219 let embedUrl = 'https://www.youtube.com/embed/' + videoId; 220 221 // Add timestamp if present 222 if (timeMatch) { 223 let timeValue = timeMatch[1]; 224 let seconds = 0; 225 226 // Parse different time formats 227 if (/^\d+$/.test(timeValue)) { 228 // Pure number (seconds): t=90 229 seconds = parseInt(timeValue); 230 } else if (/^\d+s$/.test(timeValue)) { 231 // Seconds only: t=42s 232 seconds = parseInt(timeValue.replace('s', '')); 233 } else if (/^(\d+)m(\d+)s$/.test(timeValue)) { 234 // Minutes and seconds: t=1m30s 235 let match = timeValue.match(/^(\d+)m(\d+)s$/); 236 seconds = (parseInt(match[1]) * 60) + parseInt(match[2]); 237 } else if (/^\d+m$/.test(timeValue)) { 238 // Minutes only: t=2m 239 seconds = parseInt(timeValue.replace('m', '')) * 60; 240 } 241 242 if (seconds > 0) { 243 embedUrl += '?start=' + seconds; 244 } 245 } 246 247 ifr.src = embedUrl; 248 } 249 } else if (url.includes('youtu.be/')) { 250 // Handle short YouTube URLs 251 let match = url.match(/youtu\.be\/([^?]+)(\?.*)?/); 252 if (match) { 253 let videoId = match[1]; 254 let params = match[2] || ''; 255 let embedUrl = 'https://www.youtube.com/embed/' + videoId; 256 257 // Check for time parameter 258 let timeMatch = params.match(/[?&]t=([^&]+)/); 259 if (timeMatch) { 260 let timeValue = timeMatch[1]; 261 let seconds = 0; 262 263 // Parse different time formats (same as above) 264 if (/^\d+$/.test(timeValue)) { 265 seconds = parseInt(timeValue); 266 } else if (/^\d+s$/.test(timeValue)) { 267 seconds = parseInt(timeValue.replace('s', '')); 268 } else if (/^(\d+)m(\d+)s$/.test(timeValue)) { 269 let match = timeValue.match(/^(\d+)m(\d+)s$/); 270 seconds = (parseInt(match[1]) * 60) + parseInt(match[2]); 271 } else if (/^\d+m$/.test(timeValue)) { 272 seconds = parseInt(timeValue.replace('m', '')) * 60; 273 } 274 275 if (seconds > 0) { 276 embedUrl += '?start=' + seconds; 277 } 278 } 279 280 ifr.src = embedUrl; 281 } 282 } else { 283 // Fallback for other embed types 284 ifr.src = url; 285 } 286 287 ifr.setAttribute('allowfullscreen', ''); 288 ele.appendChild(ifr); 289 element.parentElement.replaceWith(ele); 290}); 291 292const htmlAllowedInEditor = [ 293 { 294 name: 'blockquote', 295 classes: ['twitter-tweet', 'instagram-media', 'tiktok-embed', 'reddit-embed-bq'], 296 attributes: true 297 }, 298 { 299 name: 'script', 300 attributes: true 301 }, 302 { 303 name: 'iframe', 304 attributes: true, 305 styles: true, 306 classes: ['embed-responsive-item'] 307 }, 308 { 309 name: 'section' 310 }, 311 { 312 name: 'div', 313 classes: ['embed-responsive', 'embed-responsive-16by9', 'mt-0', 'mt-1', 'mt-2', 'mt-3', 'mt-4', 'mt-5', 'mb-0', 'mb-1', 'mb-2', 'mb-3', 'mb-4', 'mb-5'], 314 attributes: { 315 style: true 316 } 317 }, 318 { 319 name: 'p', 320 attributes: { 321 style: true 322 } 323 } 324]; 325 326// Show a preview for Giphy embeds so users can verify the link 327document.addEventListener('DOMContentLoaded', function () { 328 const inputs = document.querySelectorAll("input[name$='.EmbedLink']");
329 inputs.forEach(input => { 330 const preview = document.createElement('div'); 331 preview.className = 'mt-2'; 332 input.parentNode.insertBefore(preview, input.nextSibling); 333 334 const update = () => { 335 const url = input.value.trim(); 336 preview.innerHTML = ''; 337 if (!url) { 338 return; 339 } 340 341 const normalized = url.replace(/media[0-9]\.giphy\.com/, 'media.giphy.com'); 342 const gifMatch = normalized.match(/giphy\.com\/gifs\/([\w-]+)/i); 343 const mediaMatch = normalized.match(/media\.giphy\.com\/media\/([\w-]+)/i); 344 const id = gifMatch ? gifMatch[1] : (mediaMatch ? mediaMatch[1] : null); 345 346 if (id) { 347 const img = document.createElement('img'); 348 img.src = `https://media.giphy.com/media/${id}/giphy.gif`; 349 img.className = 'img-fluid mt-2'; 350 img.alt = 'Giphy preview'; 351 preview.appendChild(img); 352 } else { 353 preview.innerHTML = '<div class="text-danger">Invalid Giphy URL</div>'; 354 } 355 }; 356 357 input.addEventListener('input', update); 358 update(); 359 }); 360}); 361$(document).ready(function(){$(".mobile-dropdown-toggle").click(function(o){o.preventDefault(),$(this).next(".mobile-dropdown-menu").toggleClass("show")})});
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.