1/** 2 * Activello theme scripts. 3 * 4 * Plain DOM APIs -- no jQuery. The two globals (ActivelloIsMobile and 5 * generateMobileMenu) are kept on window because child themes may call them. 6 */ 7( function () { 8 'use strict'; 9 10 /** 11 * Run a callback once the DOM is ready. 12 * 13 * @param {Function} fn Callback. 14 */ 15 function ready( fn ) { 16 if ( document.readyState !== 'loading' ) { 17 fn(); 18 } else { 19 document.addEventListener( 'DOMContentLoaded', fn ); 20 } 21 } 22 23 /** 24 * Add class names to every element matching a selector. 25 * 26 * @param {string} selector CSS selector. 27 * @param {Array} classes Class names to add. 28 */ 29 function addClasses( selector, classes ) { 30 document.querySelectorAll( selector ).forEach( function ( el ) { 31 el.classList.add.apply( el.classList, classes ); 32 } ); 33 } 34 35 /** 36 * jQuery's "swing" easing, so the scroll-to-top motion is unchanged. 37 * 38 * @param {number} p Progress from 0 to 1. 39 * @return {number} Eased progress. 40 */ 41 function swing( p ) { 42 return 0.5 - Math.cos( p * Math.PI ) / 2; 43 } 44 45 function prefersReducedMotion() { 46 return window.matchMedia && window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches; 47 } 48 49 /** 50 * The display value jQuery's .show() would restore for an element. 51 * 52 * @param {Element} el Target element. 53 * @return {string} CSS display value. 54 */ 55 function defaultDisplay( el ) { 56 if ( el.tagName === 'TABLE' ) { 57 return 'table'; 58 } 59 60 if ( el.tagName === 'SELECT' ) { 61 return 'inline-block'; 62 } 63 64 return 'block'; 65 } 66 67 /** 68 * Fade an element in or out, matching jQuery's fadeIn()/fadeOut(). 69 * 70 * @param {Element} el Target element. 71 * @param {boolean} into True to fade in, false to fade out. 72 * @param {number} duration Animation length in ms. 73 */ 74 function fade( el, into, duration ) { 75 if ( ! el || el.dataset.activelloFading === String( into ) ) { 76 return; 77 } 78 79 el.dataset.activelloFading = String( into ); 80 81 if ( prefersReducedMotion() ) { 82 el.style.opacity = into ? '1' : ''; 83 el.style.display = into ? defaultDisplay( el ) : 'none'; 84 return; 85 } 86 87 var start = null; 88 var from = parseFloat( window.getComputedStyle( el ).opacity ); 89 90 if ( isNaN( from ) ) { 91 from = into ? 0 : 1; 92 } 93 94 if ( into ) { 95 el.style.display = defaultDisplay( el ); 96 } 97 98 function step( ts ) { 99 if ( start === null ) { 100 start = ts; 101 } 102 103 var p = Math.min( ( ts - start ) / duration, 1 ); 104 var v = from + ( ( into ? 1 : 0 ) - from ) * swing( p ); 105 106 el.style.opacity = String( v ); 107 108 if ( p < 1 ) { 109 window.requestAnimationFrame( step ); 110 } else if ( ! into ) { 111 el.style.display = 'none'; 112 el.style.opacity = ''; 113 } 114 } 115 116 window.requestAnimationFrame( step ); 117 } 118 119 /** 120 * Detect a mobile user agent. 121 * 122 * Kept as-is (including the UA sniff) because the mobile menu styling below 123 * depends on it and child themes may call it. 124 * 125 * @return {boolean} True on a mobile user agent. 126 */ 127 window.ActivelloIsMobile = function () { 128 return ( 129 navigator.userAgent.match( /Android/i ) || 130 navigator.userAgent.match( /webOS/i ) || 131 navigator.userAgent.match( /iPhone/i ) || 132 navigator.userAgent.match( /iPod/i ) || 133 navigator.userAgent.match( /iPad/i ) || 134 navigator.userAgent.match( /BlackBerry/ ) 135 ); 136 }; 137 138 /** 139 * Toggle the tap-friendly menu class on touch devices at tablet width and up. 140 */ 141 window.generateMobileMenu = function () { 142 var menu = document.querySelector( '#masthead .site-navigation-inner .navbar-collapse > ul.nav' ); 143 144 if ( ! menu ) { 145 return; 146 } 147 148 if ( window.ActivelloIsMobile() && window.innerWidth > 768 ) { 149 menu.classList.add( 'activello-mobile-menu' ); 150 } else { 151 menu.classList.remove( 'activello-mobile-menu' ); 152 } 153 }; 154 155 /** 156 * Apply Bootstrap classes to markup WordPress generates, then reveal the 157 * elements style.css keeps hidden until they have been dressed up. 158 */ 159 function styleCoreMarkup() { 160 addClasses( '.widget_rss ul', [ 'media-list' ] ); 161 addClasses( '.postform', [ 'form-control' ] ); 162 addClasses( 'table#wp-calendar', [ 'table', 'table-striped' ] ); 163 164 document.querySelectorAll( '.widget_rss ul, .postform, table#wp-calendar' ).forEach( function ( el ) { 165 // 200ms matches the jQuery .show('fast') this replaced. 166 fade( el, true, 200 ); 167 } ); 168 } 169 170 /** 171 * Scroll-to-top button: reveal past 100px, and smooth-scroll on click. 172 */ 173 function initScrollToTop() { 174 var button = document.querySelector( '.scroll-to-top' ); 175 176 if ( ! button ) { 177 return; 178 } 179 180 function onScroll() { 181 fade( button, ( window.pageYOffset || document.documentElement.scrollTop ) > 100, 400 ); 182 } 183 184 window.addEventListener( 'scroll', onScroll, { passive: true } ); 185 onScroll(); 186 187 button.addEventListener( 'click', function ( event ) { 188 event.preventDefault(); 189 190 var from = window.pageYOffset || document.documentElement.scrollTop; 191 192 if ( ! from ) { 193 return; 194 } 195 196 if ( prefersReducedMotion() ) { 197 window.scrollTo( 0, 0 ); 198 return; 199 } 200 201 var duration = 800; 202 var start = null; 203 204 function step( ts ) { 205 if ( start === null ) { 206 start = ts; 207 } 208 209 var p = Math.min( ( ts - start ) / duration, 1 ); 210 211 window.scrollTo( 0, from * ( 1 - swing( p ) ) ); 212 213 if ( p < 1 ) { 214 window.requestAnimationFrame( step ); 215 } 216 } 217 218 window.requestAnimationFrame( step ); 219 } ); 220 } 221 222 /** 223 * "..." toggle for the extra-categories list, mobile user agents only. 224 */ 225 function initShowMoreCategories() { 226 document.querySelectorAll( '.show-more-categories' ).forEach( function ( el ) { 227 el.addEventListener( 'click', function () { 228 if ( window.ActivelloIsMobile() ) { 229 el.classList.toggle( 'active' ); 230 } 231 } ); 232 } ); 233 } 234 235 /** 236 * Sub-menu toggles the nav walker renders next to parent menu items. 237 */ 238 function initDropdowns() { 239 document.querySelectorAll( '.activello-dropdown' ).forEach( function ( el ) { 240 el.addEventListener( 'click', function () { 241 var parent = el.parentNode; 242 243 if ( ! parent ) { 244 return; 245 } 246 247 Array.prototype.forEach.call( parent.children, function ( child ) { 248 if ( child.tagName === 'UL' ) { 249 child.classList.toggle( 'active' ); 250 } 251 } ); 252 } ); 253 } ); 254 } 255 256 ready( function () { 257 styleCoreMarkup(); 258 initScrollToTop(); 259 initShowMoreCategories(); 260 initDropdowns(); 261 window.generateMobileMenu(); 262 263 window.addEventListener( 'resize', window.generateMobileMenu ); 264 } ); 265}() );
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.