1// var TxtRotate = function(el, toRotate, period) { 2// this.toRotate = toRotate; 3// this.el = el; 4// this.loopNum = 0; 5// this.period = parseInt(period, 10) || 2000; 6// this.txt = ''; 7// this.tick(); 8// this.isDeleting = false; 9// }; 10 11// TxtRotate.prototype.tick = function() { 12// var i = this.loopNum % this.toRotate.length; 13// var fullTxt = this.toRotate[i]; 14 15// if (this.isDeleting) { 16// this.txt = fullTxt.substring(0, this.txt.length - 1); 17// } else { 18// this.txt = fullTxt.substring(0, this.txt.length + 1); 19// } 20 21// this.el.innerHTML = '<span class="wrap">'+this.txt+'</span>'; 22 23// var that = this; 24// var delta = 300 - Math.random() * 100; 25 26// if (this.isDeleting) { delta /= 2; } 27 28// if (!this.isDeleting && this.txt === fullTxt) { 29// delta = this.period; 30// this.isDeleting = true; 31// } else if (this.isDeleting && this.txt === '') { 32// this.isDeleting = false; 33// this.loopNum++; 34// delta = 500; 35// } 36 37// setTimeout(function() { 38// that.tick(); 39// }, delta); 40// }; 41 42// window.onload = function() { 43// var elements = document.getElementsByClassName('txt-rotate'); 44// for (var i=0; i<elements.length; i++) { 45// var toRotate = elements[i].getAttribute('data-rotate'); 46// var period = elements[i].getAttribute('data-period'); 47// if (toRotate) { 48// new TxtRotate(elements[i], JSON.parse(toRotate), period); 49// } 50// } 51// // INJECT CSS 52// var css = document.createElement("style"); 53// css.type = "text/css"; 54// css.innerHTML = ".txt-rotate > .wrap { border-right: 0.08em solid #666 }"; 55// document.body.appendChild(css); 56// }; 57 58// //SmoothScroll Initialisation 59// var scroll = new SmoothScroll('a[href*="#"]', { 60// speed: 1000 61// }); 62 63// $(document).ready(function(){ 64// // Add smooth scrolling to all links 65// $("a").on('click', function(event) { 66 67// // Make sure this.hash has a value before overriding default behavior 68// if (this.hash !== "") { 69// // Prevent default anchor click behavior 70// event.preventDefault(); 71 72// // Store hash 73// var hash = this.hash; 74 75// // Using jQuery's animate() method to add smooth page scroll 76// // The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area 77// $('html, body').animate({ 78// scrollTop: $(hash).offset().top 79// }, 800, function(){ 80 81// // Add hash (#) to URL when done scrolling (default click behavior) 82// window.location.hash = hash; 83// }); 84// } // End if 85// }); 86// }); 87 88// Lightbox Functionality 89const lightbox = document.getElementById('lightbox'); 90const lightboxImage = document.getElementById('lightboxImage'); 91const lightboxClose = document.getElementById('lightboxClose'); 92 93function openLightbox(src, alt) { 94 lightboxImage.src = src; 95 lightboxImage.alt = alt; 96 lightbox.classList.add('active'); 97 document.body.style.overflow = 'hidden'; 98} 99 100function closeLightbox() { 101 lightbox.classList.remove('active'); 102 document.body.style.overflow = ''; 103} 104 105lightboxClose.addEventListener('click', closeLightbox); 106 107lightbox.addEventListener('click', (e) => { 108 if (e.target === lightbox) { 109 closeLightbox(); 110 } 111}); 112 113document.addEventListener('keydown', (e) => { 114 if (e.key === 'Escape' && lightbox.classList.contains('active')) { 115 closeLightbox(); 116 } 117}); 118 119// Theme Toggle Functionality 120const themeToggle = document.getElementById('themeToggle'); 121const html = document.documentElement; 122 123// Check for saved theme preference or default to system preference 124const getPreferredTheme = () => { 125 const savedTheme = localStorage.getItem('theme'); 126 if (savedTheme) { 127 return savedTheme; 128 } 129 return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; 130}; 131 132// Apply theme 133const setTheme = (theme) => { 134 if (theme === 'dark') { 135 html.setAttribute('data-theme', 'dark'); 136 } else { 137 html.removeAttribute('data-theme'); 138 } 139 localStorage.setItem('theme', theme); 140}; 141 142// Initialize theme 143setTheme(getPreferredTheme()); 144 145// Toggle theme on button click 146themeToggle.addEventListener('click', () => { 147 const currentTheme = html.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'; 148 const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; 149 setTheme(newTheme); 150}); 151 152// Listen for system theme changes 153window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { 154 if (!localStorage.getItem('theme')) { 155 setTheme(e.matches ? 'dark' : 'light'); 156 } 157}); 158 159// Fade in animation on scroll 160const fadeElements = document.querySelectorAll('.fade-in'); 161 162const observerOptions = { 163 threshold: 0.1, 164 rootMargin: '0px 0px -50px 0px' 165}; 166 167const observer = new IntersectionObserver((entries) => {
168 entries.forEach(entry => { 169 if (entry.isIntersecting) { 170 entry.target.classList.add('visible'); 171 } 172 }); 173}, observerOptions); 174 175fadeElements.forEach(el => observer.observe(el)); 176 177// Trigger initial fade-in for elements already in view 178window.addEventListener('load', () => { 179 fadeElements.forEach(el => { 180 const rect = el.getBoundingClientRect(); 181 if (rect.top < window.innerHeight) { 182 el.classList.add('visible'); 183 } 184 }); 185});
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.