1/* ---------------------------------- */ 2 3/* 4 * WeAreGorilla.co 5 * 2018 6 * 7 * application.js 8 * 9 */ 10 11/* JSHint */ 12/* globals console, jQuery, Vimeo, YT, alert */ 13/* jshint esversion: 6, loopfunc: true, curly: false, esnext: true */ 14 15 16/* ---------------------------------- */ 17 18/* Initialize */ 19jQuery(function ($) { 20 $.HTML = $('html'); 21 $.Body = $('body'); 22 $.Window = $(window); 23 $.Document = $(document); 24 25 $('[data-controller]').Instantiate(); 26 27 28 29 // Close menu on first visit (if no intentional hover) 30 if( Cookies.get('g409jg092j-iojboijvaln') === undefined ) { 31 32 // Setup hover listener 33 var nav_temp_to = 0, 34 has_visited_timeout = 0; 35 $('nav').one('mouseenter.cancel_close', function() { 36 nav_temp_to = setTimeout( function() { 37 clearTimeout( has_visited_timeout ); 38 }, 1000 ); 39 }).one('mouseleave.cancel_cancel_close', function() { 40 clearTimeout( nav_temp_to ); 41 }); 42 43 // Open nav 44 $.Body.addClass('nav-open'); 45 46 // Setup close if no hover 47 has_visited_timeout = setTimeout( function() { 48 $.Body.removeClass('nav-open'); 49 50 // If we are running "animate nav" don't save 51 Cookies.set('g409jg092j-iojboijvaln', true, { expires: 1 }); 52 53 }, 3000 ); 54 55 } 56 57 // Note: Hover is detected with @media (hover:hover) even though firefox doesn't support it 58 if( !(matchMedia('(hover: none)').matches) ) { 59 document.body.classList.add('can-hover'); 60 } 61 62 63 if( window.location.hash === "#reset-nav-flash" ) { 64 Cookies.remove('g409jg092j-iojboijvaln'); 65 } 66 67 68 // For testing 69 localStorage.removeItem( 'has_visited' ); 70 71 72 // Video hover 73 let video, v_to; 74 $('.c-grid-post.video-on-hover').on('mouseenter', function() { 75 video = $(this).find('video')[0]; 76 video.play(); 77 }).on('mouseleave', function() { 78 video.pause(); 79 }); 80 81}); 82 83 84 85// av2 functions necessary for lazyload controller 86const _ = { 87 88 on_window_load: callback => { 89 90 if (document.readyState === 'complete') { 91 callback(); 92 } else { 93 window.addEventListener("load", callback); 94 } 95 96 }, 97 98 load_image: (img, callback) => { 99 100 // Make sure image isn't broken 101 if( ! img ) return; 102 103 // Only if it is setup to be lazy loaded or has not already been loaded 104 if( ! img.dataset.src ) { 105 if( ! _.is_loaded(img) ) { 106 img.addEventListener('load', () => callback( img ) ); 107 } else { 108 callback( img ) 109 } 110 return; 111 } 112 113 // If there is a callback, run it after image is loaded 114 if( callback ) img.addEventListener('load', () => callback( img ) ); 115 116 img.src = img.dataset.src; 117 img.removeAttribute('data-src'); 118 img.srcset = img.dataset.srcset; 119 img.removeAttribute('data-srcset'); 120 img.classList.add('loaded'); 121 122 }, 123 124}; 125 126 127 128/* ---------------------------------- */ 129 130/* Auto Instantiate 131 NOTE: This function loads a 'plugin' for each data-controller */ 132 133(function($) { 134 'use strict'; 135 $.fn.Instantiate = function(settings) { 136 var config = {}; 137 if (settings) {$.extend(config, settings);} 138 this.each(function() { 139 var $self = $(this), 140 $controller = $self.data('controller'); 141 142 if ($self[$controller]){ $self[$controller](); } 143 }); 144 }; 145}(jQuery)); 146 147 148 149 150 151 152 153/* ---------------------------------- */ 154 155/* gravity_forms */ 156 157(function($) { 158 'use strict'; 159 $.fn.gravity_forms = function() { 160 this.each(function() { 161 162 const el = $(this).get(0); 163 164 // ****************************** 165 // RECAPTCHA 166 // ****************************** 167 grecaptcha.ready(function() { 168 grecaptcha.execute( RecaptchaKeys.site, {action: 'submit'}).then(function(token) { 169 170 let g_recaptcha_input = el.querySelector('.g-recaptcha-token input[type="hidden"]'); 171 if( g_recaptcha_input === null ) { 172 console.error('Google reCAPTCHA field not found. Please ensure classes are setup.'); 173 // const input = document.createElement('input'); 174 // input.classList.add('g-recaptcha-token'); 175 // input.type = 'hidden'; 176 // input.name = 'g-recaptcha-token'; 177 // input.value = token; 178 // el.querySelector('.gform_fields').appendChild(input); 179 } else { 180 g_recaptcha_input.value = token; 181 } 182 183 }); 184 }); 185 186 }); 187 }; 188}(jQuery)); 189 190 191/* ---------------------------------- */ 192
193/* LargeListHoverImage */ 194 195(function($) { 196 'use strict'; 197 $.fn.LargeListHoverImage = function() { 198 this.each(function() { 199 var $self = $(this), 200 $a = $self.find('li > a, li > span'), 201 doit = function() { 202 $self.toggleClass('over'); 203 }; 204 205 $a.on( 'mouseenter', doit ).on( 'mouseleave', doit ); 206 207 }); 208 }; 209}(jQuery)); 210 211 212 213/* ---------------------------------- */ 214 215/* NavTrigger */ 216 217(function($) { 218 'use strict'; 219 $.fn.NavTrigger = function() { 220 this.each(function() { 221 var $self = $(this), 222 $nav = $('nav'), 223 t = 0, 224 nav_open = function(e){ 225 e.preventDefault(); 226 227 t = setTimeout( function(){ 228 $.Body.toggleClass('nav-open'); 229 }, 250 ); 230 }, 231 nav_cancel = function() { 232 clearTimeout( t ); 233 }, 234 nav_close = function(e) { 235 e.preventDefault(); 236 t = setTimeout( function(){ 237 $.Body.removeClass('nav-open'); 238 }, 250 ); 239 }; 240 241 242 // Open close mini menu 243 $self.on( 'mouseenter touchstart', nav_open ).on( 'mouseleave', nav_cancel ); 244 $nav.on( 'mouseleave', nav_close ).on( 'mouseenter', nav_cancel ); 245 }); 246 }; 247}(jQuery)); 248 249 250 251/* ---------------------------------- */ 252 253/* HeroScrollingText */ 254 255(function($) { 256 'use strict'; 257 $.fn.HeroScrollingText = function() { 258 this.each(function() { 259 260 const scroller = document.getElementById('scroller'); 261 document.getElementsByTagName('video')[0].addEventListener( 'loadeddata', function() { 262 scroller.classList.add('in'); 263 }); 264 265 266 // Fallback in case loaddata doesn't load 267 setTimeout( function() { 268 if( scroller.classList.length === 0 ) { 269 scroller.classList.add('in'); 270 } 271 }, 3000 ); 272 273 }); 274 }; 275}(jQuery)); 276 277 278 279/* ---------------------------------- */ 280 281/* HomepageVideoHeight */ 282 283(function($) { 284 'use strict'; 285 $.fn.HomepageVideoHeight = function() { 286 this.each(function() { 287 288 const $this = $(this); 289 290 $.Window.on( 'resize.videoHeight', function() { 291 292 $this.height( $.Window.height() - ( 88*2 ) ); // <= 88 is top and bottom margin 293 294 }).trigger( 'resize.videoHeight' ); 295 296 }); 297 }; 298}(jQuery)); 299 300 301 302/* ---------------------------------- */ 303 304/* LazyLoad */ 305 306(function($) { 307 'use strict'; 308 $.fn.LazyLoad = function() { 309 this.each(function() { 310 311 const el = this; 312 const type = el.dataset.lazytype; 313 314 // Default is scroll to (default lazy load behavior) 315 if( type === 'custom' ) { 316 317 // Loaded on a custom event don't do anything 318 return; 319 320 } else if( type === 'deferred' ) { 321 322 // Deferred is used for non in view on load, but need to be quickly 323 _.on_window_load( () => _.load_image( el ) ); 324 325 } else { // <= default... scroll in view 326 327 // Type = scroll to intersect 328 const img_observer = new IntersectionObserver((entries, img_observer) => { 329 entries.forEach(entry => { 330 331 if( entry.target.classList.contains('lazy-debug') ) console.log(entry.target, entry.isIntersecting); 332 333 if ( ! entry.isIntersecting) return; 334 335 if( type === 'video_poster' ) { 336 el.poster = el.dataset.poster; 337 el.removeAttribute('data-poster'); 338 } else { 339 _.load_image( entry.target ); 340 } 341 342 img_observer.unobserve( entry.target ); 343 }); 344 }, { threshold: 0, rootMargin: "1000px 0px 1000px 0px" }); 345 346 // Observe it 347 img_observer.observe(el); 348 349 } 350 351 }); 352 }; 353}(jQuery)); 354 355 356 357 358/* ---------------------------------- */ 359 360/* Video */ 361 362(function($) { 363 'use strict'; 364 $.fn.Video = function() { 365 this.each(function() { 366 367 const $self = $(this), 368 vids = { 369 local: $self.find('.local-video'), 370 vimeo: $self.find('.vimeo-video'), 371 youtube: $self.find('.youtube-video') 372 }, 373 // $local_video = $self.find('.local-video'), 374 // $vimeo_video = $self.find('.vimeo-video'), 375 // $youtube_video = , 376 service = vids.local.length > 0 ? 'local' : vids.vimeo.length > 0 ? 'vimeo' : 'youtube', 377 $video = vids[ service ], 378 location = $self.hasClass('modal') ? 'modal' : 'in-place'; 379 380 let player = 0; 381 382 // Click listener 383 $self.on('click.playvideo', function(e) { 384 e.preventDefault(); 385 386 if( 387 ( location === 'modal' && ! $video.hasClass('video-ready') ) || // <= modal and video not ready 388 // ( location !== 'modal' && $self.hasClass('video-ready') ) || // <= not sure what this one does. testing
389 e.target.nodeName === 'BUTTON' ) { // <= if close 390 // Add reset video here if needed 391 return; 392 } 393 394 if( location === 'modal' ) { 395 396 let closing = false; 397 const $modal = $self.find('.modal-content'), 398 $close_button = $modal.find('.close-modal'), 399 do_close = () => { 400 $modal.removeClass('in'); 401 $video.removeClass('video-on').removeClass('playing'); 402 $self.removeClass('video-on'); 403 $.HTML.removeClass('modal-in'); 404 405 // Pause video 406 if( service === 'local' ) { 407 player = $video.find('video')[0]; 408 player.pause(); 409 } else if( service === 'vimeo' ) { 410 player = $video.data('vimeo_player'); 411 player.pause(); 412 } else if( service === 'youtube' ) { 413 player = $video.data('yt_player'); 414 player.pauseVideo(); 415 } 416 417 $close_button.off('click.close-modal'); 418 $modal.off('click.close-modal'); 419 }; 420 421 422 // ##################### 423 // Close listener 424 $close_button.on('click.close-modal', function(t) { 425 t.preventDefault(); 426 do_close(); 427 }); 428 429 430 // ##################### 431 // Activation classes 432 if( ! closing ) { 433 $.HTML.addClass('modal-in'); 434 $self.addClass('video-on'); 435 $video.addClass('video-on'); 436 437 $modal.addClass('in'); 438 $video.addClass('video-on'); 439 } 440 441 } 442 443 if( ! $video.hasClass('playing') ) { 444 445 // Play video 446 $self.addClass('video-on'); 447 $video.addClass('video-on').addClass('playing'); 448 449 if( service === 'local' ) { 450 player = $video.find('video')[0]; 451 player.play(); 452 } else if( service === 'vimeo' ) { 453 player = $video.data('vimeo_player'); 454 player.play(); 455 } else if( service === 'youtube' ) { 456 player = $video.data('yt_player'); 457 player.playVideo(); 458 } 459 460 } else { 461 462 // Play video 463 // $self.removeClass('video-on'); 464 $video.removeClass('playing').removeClass('video-on'); 465 // console.log('service', service); 466 467 if( service === 'local' ) { 468 player = $video.find('video')[0]; 469 player.pause(); 470 } else if( service === 'vimeo' ) { 471 player = $video.data('vimeo_player'); 472 player.pause(); 473 } else if( service === 'youtube' ) { 474 player = $video.data('yt_player'); 475 player.pauseVideo(); 476 } 477 478 } 479 480 481 // ############################## 482 // Close modal if click outside of video 483 if( location === 'modal' && e.target.classList.contains('modal-content') ) $self.find('.modal-content .close-modal').trigger('click.close-modal') 484 485 }); 486 487 }); 488 }; 489}(jQuery)); 490 491 492 493/* ---------------------------------- */ 494 495/* Vimeo */ 496 497(function($) { 498 'use strict'; 499 $.fn.Vimeo = function() { 500 this.each(function() { 501 502 const $self = $(this), 503 $placeholder = $self.siblings('img, video').first(), 504 options = { 505 url: $self.data('url'), 506 height: $placeholder.height(), 507 width: $placeholder.width() 508 }; 509 510 // Only run once 511 if( ! $.HTML.hasClass('vimeo-loaded') ) { 512 513 // Add notice 514 $.HTML.addClass('vimeo-loaded'); 515 516 // Load YouTube Frame API 517 const tag = document.createElement('script'); 518 519 tag.src = "https://player.vimeo.com/api/player.js"; 520 const firstScriptTag = document.getElementsByTagName('script')[0]; 521 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 522 523 } 524 525 526 // Listen for vimeo being loaded 527 var c = 0; 528 var i = setInterval( function() { 529 530 // Vimeo is loaded 531 if( typeof( Vimeo ) !== 'undefined' ) { 532 clearInterval( i ); 533 534 // Run it 535 onVimeoJSAPIReady(); 536 } 537 538 // Bail if too long 539 if( c >= 20 ) { 540 clearInterval( i ); 541 } else { 542 c++; 543 } 544 545 }, 100 ); 546 547 548 function onVimeoJSAPIReady() { 549 550 // Vars 551 const player = new Vimeo.Player( $self.attr('id'), options); 552 let $iframe = { 553 length:0 554 }; 555 556 // Resize 557 $.Window.on( 'resize.video-size', function() { 558 if( $iframe.length !== 0 ) { 559 $iframe 560 .height( $placeholder.height() ) 561 .width( $placeholder.width() ); 562 } 563 }); 564 565 // On loaded, set the $iframe 566 player.on( 'loaded', function() {
567 $iframe = $self.find('iframe'); 568 569 $.Window.trigger('resize.video-size'); 570 }); 571 572 // Set flags 573 $self.closest('.video').addClass('video-ready'); 574 $self.data('vimeo_player', player ); 575 576 }; 577 578 }); 579 }; 580}(jQuery)); 581 582 583 584/* ---------------------------------- */ 585 586/* YouTube */ 587 588(function($) { 589 'use strict'; 590 $.fn.YouTube = function() { 591 this.each(function() { 592 593 var $self = $(this), 594 $video = $self.children('div').first(), 595 $placeholder = $self.siblings('img, video').first(), 596 $iframe = {}, 597 options = { 598 videoId: $self.data('videoid'), 599 height: $placeholder.height(), 600 width: $placeholder.width(), 601 events: { 602 onReady: function() { 603 604 $iframe = $self.find('iframe'); 605 $.Window.on( 'resize.youtube', function() { 606 607 $iframe 608 .height( $placeholder.height() ) 609 .width( $placeholder.width() ); 610 611 }).trigger( 'resize.youtube' ); 612 613 // Allow click 614 $self.closest('.video').addClass('video-ready'); 615 616 }, 617 onStateChange: function( r ) { 618 if( r.data === 1 ) { 619 // playing, so pause all others 620 $('.youtube-video').not( $self ).each( function() { 621 var player = $(this).data( 'yt_player' ); 622 player.pauseVideo(); 623 }); 624 } 625 } 626 } 627 }; 628 629 // Only run once 630 if( ! $.HTML.hasClass('youtube-loaded') ) { 631 632 // Add notice 633 $.HTML.addClass('youtube-loaded'); 634 635 // Load YouTube Frame API 636 var tag = document.createElement('script'); 637 638 tag.src = "https://www.youtube.com/iframe_api"; 639 var firstScriptTag = document.getElementsByTagName('script')[0]; 640 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 641 642 // Instantiate global 643 $.Youtube_Players = []; 644 645 } 646 647 648 // Save our callbacks for when YouTube API is ready 649 $.Youtube_Players.push( function() { 650 const player = new YT.Player( $video.attr('id'), options); 651 652 // Save for future use 653 $self.data( 'yt_player', player ); 654 655 }); 656 657 }); 658 }; 659}(jQuery)); 660 661// Run callbacks when the api is ready 662function onYouTubeIframeAPIReady() { // jshint ignore:line 663 // Loop each of our youtube players 664 $.each( $.Youtube_Players, function( i, callback ) { callback(); }); 665}
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.