1/** 2* Template Name: Flattern - v4.7.0 3* Template URL: https://bootstrapmade.com/flattern-multipurpose-bootstrap-template/ 4* Author: BootstrapMade.com 5* License: https://bootstrapmade.com/license/ 6*/ 7(function() { 8 "use strict"; 9 10 /** 11 * Easy selector helper function 12 */ 13 const select = (el, all = false) => { 14 el = el.trim() 15 if (all) { 16 return [...document.querySelectorAll(el)] 17 } else { 18 return document.querySelector(el) 19 } 20 } 21 22 /** 23 * Easy event listener function 24 */ 25 const on = (type, el, listener, all = false) => { 26 let selectEl = select(el, all) 27 if (selectEl) { 28 if (all) { 29 selectEl.forEach(e => e.addEventListener(type, listener)) 30 } else { 31 selectEl.addEventListener(type, listener) 32 } 33 } 34 } 35 36 /** 37 * Easy on scroll event listener 38 */ 39 const onscroll = (el, listener) => { 40 el.addEventListener('scroll', listener) 41 } 42 43 /** 44 * Scrolls to an element with header offset 45 */ 46 const scrollto = (el) => { 47 let header = select('#header') 48 let offset = header.offsetHeight 49 50 if (!header.classList.contains('header-scrolled')) { 51 offset -= 16 52 } 53 54 let elementPos = select(el).offsetTop 55 window.scrollTo({ 56 top: elementPos - offset, 57 behavior: 'smooth' 58 }) 59 } 60 61 /** 62 * Header fixed top on scroll 63 */ 64 let selectHeader = select('#header') 65 if (selectHeader) { 66 let headerOffset = selectHeader.offsetTop 67 let nextElement = selectHeader.nextElementSibling 68 const headerFixed = () => { 69 if ((headerOffset - window.scrollY) <= 0) { 70 selectHeader.classList.add('fixed-top') 71 nextElement.classList.add('scrolled-offset') 72 } else { 73 selectHeader.classList.remove('fixed-top') 74 nextElement.classList.remove('scrolled-offset') 75 } 76 } 77 window.addEventListener('load', headerFixed) 78 onscroll(document, headerFixed) 79 } 80 81 /** 82 * Back to top button 83 */ 84 let backtotop = select('.back-to-top') 85 if (backtotop) { 86 const toggleBacktotop = () => { 87 if (window.scrollY > 100) { 88 backtotop.classList.add('active') 89 } else { 90 backtotop.classList.remove('active') 91 } 92 } 93 window.addEventListener('load', toggleBacktotop) 94 onscroll(document, toggleBacktotop) 95 } 96 97 /** 98 * Mobile nav toggle 99 */ 100 on('click', '.mobile-nav-toggle', function(e) { 101 select('#navbar').classList.toggle('navbar-mobile') 102 this.classList.toggle('bi-list') 103 this.classList.toggle('bi-x') 104 }) 105 106 /** 107 * Mobile nav dropdowns activate 108 */ 109 on('click', '.navbar .dropdown > a', function(e) { 110 if (select('#navbar').classList.contains('navbar-mobile')) { 111 e.preventDefault() 112 this.nextElementSibling.classList.toggle('dropdown-active') 113 } 114 }, true) 115 116 /** 117 * Scrool with ofset on links with a class name .scrollto 118 */ 119 on('click', '.scrollto', function(e) { 120 if (select(this.hash)) { 121 e.preventDefault() 122 123 let navbar = select('#navbar') 124 if (navbar.classList.contains('navbar-mobile')) { 125 navbar.classList.remove('navbar-mobile') 126 let navbarToggle = select('.mobile-nav-toggle') 127 navbarToggle.classList.toggle('bi-list') 128 navbarToggle.classList.toggle('bi-x') 129 } 130 scrollto(this.hash) 131 } 132 }, true) 133 134 /** 135 * Scroll with ofset on page load with hash links in the url 136 */ 137 window.addEventListener('load', () => { 138 if (window.location.hash) { 139 if (select(window.location.hash)) { 140 scrollto(window.location.hash) 141 } 142 } 143 }); 144 145 /** 146 * Hero carousel indicators 147 */ 148 let heroCarouselIndicators = select("#hero-carousel-indicators") 149 let heroCarouselItems = select('#heroCarousel .carousel-item', true) 150 151 heroCarouselItems.forEach((item, index) => { 152 (index === 0) ? 153 heroCarouselIndicators.innerHTML += "<li data-bs-target='#heroCarousel' data-bs-slide-to='" + index + "' class='active'></li>": 154 heroCarouselIndicators.innerHTML += "<li data-bs-target='#heroCarousel' data-bs-slide-to='" + index + "'></li>" 155 }); 156 157 /** 158 * Skills animation 159 */ 160 let skilsContent = select('.skills-content'); 161 if (skilsContent) { 162 new Waypoint({ 163 element: skilsContent, 164 offset: '80%', 165 handler: function(direction) { 166 let progress = select('.progress .progress-bar', true); 167 progress.forEach((el) => { 168 el.style.width = el.getAttribute('aria-valuenow') + '%' 169 }); 170 } 171 }) 172 } 173 174 /** 175 * Porfolio isotope and filter 176 */ 177 window.addEventListener('load', () => { 178 let portfolioContainer = select('.portfolio-container'); 179 if (portfolioContainer) { 180 let portfolioIsotope = new Isotope(portfolioContainer, { 181 itemSelector: '.portfolio-item', 182 layoutMode: 'fitRows' 183 }); 184 185 let portfolioFilters = select('#portfolio-flters li', true); 186 187 on('click', '#portfolio-flters li', function(e) { 188 e.preventDefault();
189 portfolioFilters.forEach(function(el) { 190 el.classList.remove('filter-active'); 191 }); 192 this.classList.add('filter-active'); 193 194 portfolioIsotope.arrange({ 195 filter: this.getAttribute('data-filter') 196 }); 197 portfolioIsotope.on('arrangeComplete', function() { 198 AOS.refresh() 199 }); 200 }, true); 201 } 202 203 }); 204 205 /** 206 * Initiate portfolio lightbox 207 */ 208 const portfolioLightbox = GLightbox({ 209 selector: '.portfolio-lightbox' 210 }); 211 212 /** 213 * Portfolio details slider 214 */ 215 new Swiper('.portfolio-details-slider', { 216 speed: 400, 217 loop: true, 218 autoplay: { 219 delay: 5000, 220 disableOnInteraction: false 221 }, 222 pagination: { 223 el: '.swiper-pagination', 224 type: 'bullets', 225 clickable: true 226 } 227 }); 228 229 /** 230 * Animation on scroll 231 */ 232 window.addEventListener('load', () => { 233 AOS.init({ 234 duration: 1000, 235 easing: 'ease-in-out', 236 once: true, 237 mirror: false 238 }) 239 }); 240 241})()
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.