1/* ----------------------------------------------------------------------------------------------- 2 Namespace 3--------------------------------------------------------------------------------------------------- */ 4 5var chaplin = chaplin || {}, 6 $ = jQuery; 7 8 9/* ----------------------------------------------------------------------------------------------- 10 Global variables 11--------------------------------------------------------------------------------------------------- */ 12 13var $doc = $( document ), 14 $win = $( window ), 15 winHeight = $win.height(), 16 winWidth = $win.width(); 17 18var viewport = {}; 19 viewport.top = $win.scrollTop(); 20 viewport.bottom = viewport.top + $win.height(); 21 22 23/* ----------------------------------------------------------------------------------------------- 24 Helper functions 25--------------------------------------------------------------------------------------------------- */ 26 27/* Output AJAX errors ------------------------ */ 28 29function chaplinAJAXErrors( jqXHR, exception ) { 30 var message = ''; 31 if ( jqXHR.status === 0 ) { 32 message = 'Not connect.n Verify Network.'; 33 } else if ( jqXHR.status == 404 ) { 34 message = 'Requested page not found. [404]'; 35 } else if ( jqXHR.status == 500 ) { 36 message = 'Internal Server Error [500].'; 37 } else if ( exception === 'parsererror' ) { 38 message = 'Requested JSON parse failed.'; 39 } else if ( exception === 'timeout' ) { 40 message = 'Time out error.'; 41 } else if ( exception === 'abort' ) { 42 message = 'Ajax request aborted.'; 43 } else { 44 message = 'Uncaught Error.n' + jqXHR.responseText; 45 } 46 console.log( 'AJAX ERROR:' + message ); 47} 48 49/* Toggle an attribute ----------------------- */ 50 51function chaplinToggleAttribute( $element, attribute, trueVal, falseVal ) { 52 53 if ( typeof trueVal === 'undefined' ) { trueVal = true; } 54 if ( typeof falseVal === 'undefined' ) { falseVal = false; } 55 56 if ( $element.attr( attribute ) !== trueVal ) { 57 $element.attr( attribute, trueVal ); 58 } else { 59 $element.attr( attribute, falseVal ); 60 } 61} 62 63 64/* ----------------------------------------------------------------------------------------------- 65 Interval Scroll 66--------------------------------------------------------------------------------------------------- */ 67 68chaplin.intervalScroll = { 69 70 init: function() { 71 72 didScroll = false; 73 74 // Check for the scroll event 75 $win.on( 'scroll load', function() { 76 didScroll = true; 77 } ); 78 79 // Once every 250ms, check if we have scrolled, and if we have, do the intensive stuff 80 setInterval( function() { 81 if ( didScroll ) { 82 didScroll = false; 83 84 // When this triggers, we know that we have scrolled 85 $win.triggerHandler( 'did-interval-scroll' ); 86 87 } 88 89 }, 250 ); 90 91 }, 92 93} // chaplin.intervalScroll 94 95 96/* ----------------------------------------------------------------------------------------------- 97 Resize End Event 98--------------------------------------------------------------------------------------------------- */ 99 100chaplin.resizeEnd = { 101 102 init: function() { 103 104 var resizeTimer; 105 106 $win.on( 'resize', function(e) { 107 108 clearTimeout( resizeTimer ); 109 110 resizeTimer = setTimeout( function() { 111 112 // Trigger this at the end of screen resizing 113 $win.triggerHandler( 'resize-end' ); 114 115 }, 250 ); 116 117 } ); 118 119 }, 120 121} // chaplin.resizeEnd 122 123 124/* ----------------------------------------------------------------------------------------------- 125 Toggles 126--------------------------------------------------------------------------------------------------- */ 127 128chaplin.toggles = { 129 130 init: function() { 131 132 // Do the toggle 133 chaplin.toggles.toggle(); 134 135 // Check for toggle/untoggle on resize 136 chaplin.toggles.resizeCheck(); 137 138 // Check for untoggle on escape key press 139 chaplin.toggles.untoggleOnEscapeKeyPress(); 140 141 }, 142 143 // Do the toggle 144 toggle: function() { 145 146 $( '*[data-toggle-target]' ).on( 'click', function( e ) { 147 148 // Get our targets 149 var $toggle = $( this ), 150 targetString = $( this ).data( 'toggle-target' ); 151 152 if ( targetString == 'next' ) { 153 var $target = $toggle.next(); 154 } else { 155 var $target = $( targetString ); 156 } 157 158 // Trigger events on the toggle targets before they are toggled 159 if ( $target.is( '.active' ) ) { 160 $target.trigger( 'toggle-target-before-active' ); 161 } else { 162 $target.trigger( 'toggle-target-before-inactive' ); 163 } 164 165 // Get the class to toggle, if specified 166 var classToToggle = $toggle.data( 'class-to-toggle' ) ? $toggle.data( 'class-to-toggle' ) : 'active'; 167 168 // For cover modals, set a short timeout duration so the class animations have time to play out 169 var timeOutTime = 0; 170 171 if ( $target.hasClass( 'cover-modal' ) ) { 172 var timeOutTime = 10; 173 } 174 175 setTimeout( function() { 176 177 // Toggle the target of the clicked toggle 178 if ( $toggle.data( 'toggle-type' ) == 'slidetoggle' ) { 179 var duration = $toggle.data( 'toggle-duration' ) ? $toggle.data( 'toggle-duration' ) : 250; 180 $target.slideToggle( duration ); 181 } else { 182 $target.toggleClass( classToToggle ); 183 } 184 185 // If the toggle target is 'next', only give the clicked toggle the active class 186 if ( targetString == 'next' ) { 187 $toggle.toggleClass( 'active' ) 188 189 // If not, toggle all toggles with this toggle target 190 } else { 191 $( '*[data-toggle-target="' + targetString + '"]' ).toggleClass( 'active' ); 192 } 193 194 // Toggle aria-expanded on the target 195 chaplinToggleAttribute( $target, 'aria-expanded', 'true', 'false' ); 196 197 // Toggle aria-pressed on the toggle 198 chaplinToggleAttribute( $toggle, 'aria-pressed', 'true', 'false' ); 199 200 // Toggle body class 201 if ( $toggle.data( 'toggle-body-class' ) ) { 202 $( 'body' ).toggleClass( $toggle.data( 'toggle-body-class' ) ); 203 } 204 205 // Check whether to lock the screen 206 if ( $toggle.data( 'lock-screen' ) ) { 207 chaplin.scrollLock.setTo( true ); 208 } else if ( $toggle.data( 'unlock-screen' ) ) { 209 chaplin.scrollLock.setTo( false ); 210 } else if ( $toggle.data( 'toggle-screen-lock' ) ) { 211 chaplin.scrollLock.setTo(); 212 } 213 214 // Check whether to set focus 215 if ( $toggle.data( 'set-focus' ) ) {
216 var $focusElement = $( $toggle.data( 'set-focus' ) ); 217 if ( $focusElement.length ) { 218 if ( $toggle.is( '.active' ) ) { 219 $focusElement.focus(); 220 } else { 221 $focusElement.blur(); 222 } 223 } 224 } 225 226 // Trigger the toggled event on the toggle target 227 $target.triggerHandler( 'toggled' ); 228 229 // Trigger events on the toggle targets after they are toggled 230 if ( $target.is( '.active' ) ) { 231 $target.trigger( 'toggle-target-after-active' ); 232 } else { 233 $target.trigger( 'toggle-target-after-inactive' ); 234 } 235 236 }, timeOutTime ); 237 238 return false; 239 240 } ); 241 }, 242 243 // Check for toggle/untoggle on screen resize 244 resizeCheck: function() { 245 246 if ( $( '*[data-untoggle-above], *[data-untoggle-below], *[data-toggle-above], *[data-toggle-below]' ).length ) { 247 248 $win.on( 'resize', function() { 249 250 var winWidth = $win.width(), 251 $toggles = $( '.toggle' ); 252 253 $toggles.each( function() { 254 255 $toggle = $( this ); 256 257 var unToggleAbove = $toggle.data( 'untoggle-above' ), 258 unToggleBelow = $toggle.data( 'untoggle-below' ), 259 toggleAbove = $toggle.data( 'toggle-above' ), 260 toggleBelow = $toggle.data( 'toggle-below' ); 261 262 // If no width comparison is set, continue 263 if ( ! unToggleAbove && ! unToggleBelow && ! toggleAbove && ! toggleBelow ) { 264 return; 265 } 266 267 // If the toggle width comparison is true, toggle the toggle 268 if ( 269 ( ( ( unToggleAbove && winWidth > unToggleAbove ) || 270 ( unToggleBelow && winWidth < unToggleBelow ) ) && 271 $toggle.hasClass( 'active' ) ) 272 || 273 ( ( ( toggleAbove && winWidth > toggleAbove ) || 274 ( toggleBelow && winWidth < toggleBelow ) ) && 275 ! $toggle.hasClass( 'active' ) ) 276 ) { 277 $toggle.trigger( 'click' ); 278 } 279 280 } ); 281 282 } ); 283 284 } 285 286 }, 287 288 // Close toggle on escape key press 289 untoggleOnEscapeKeyPress: function() { 290 291 $doc.keyup( function( e ) { 292 if ( e.key === "Escape" ) { 293 294 $( '*[data-untoggle-on-escape].active' ).each( function() { 295 if ( $( this ).hasClass( 'active' ) ) { 296 $( this ).trigger( 'click' ); 297 } 298 } ); 299 300 } 301 } ); 302 303 }, 304 305} // chaplin.toggles 306 307 308/* ----------------------------------------------------------------------------------------------- 309 Cover Modals 310--------------------------------------------------------------------------------------------------- */ 311 312chaplin.coverModals = { 313 314 init: function () { 315 316 if ( $( '.cover-modal' ).length ) { 317 318 // Handle cover modals when they're toggled 319 chaplin.coverModals.onToggle(); 320 321 // When toggled, untoggle if visitor clicks on the wrapping element of the modal 322 chaplin.coverModals.outsideUntoggle(); 323 324 // Close on escape key press 325 chaplin.coverModals.closeOnEscape(); 326 327 // Show a cover modal on load, if the query string says so 328 chaplin.coverModals.showOnLoadandClick(); 329 330 // Hide and show modals before and after their animations have played out 331 chaplin.coverModals.hideAndShowModals(); 332 333 } 334 335 }, 336 337 // Handle cover modals when they're toggled 338 onToggle: function() { 339 340 $( '.cover-modal' ).on( 'toggled', function() { 341 342 var $modal = $( this ), 343 $body = $( 'body' ); 344 345 if ( $modal.hasClass( 'active' ) ) { 346 $body.addClass( 'showing-modal' ); 347 } else { 348 $body.removeClass( 'showing-modal' ).addClass( 'hiding-modal' ); 349 350 // Remove the hiding class after a delay, when animations have been run 351 setTimeout ( function() { 352 $body.removeClass( 'hiding-modal' ); 353 }, 500 ); 354 } 355 } ); 356 357 }, 358 359 // Close modal on outside click 360 outsideUntoggle: function() { 361 362 $doc.on( 'click', function( e ) { 363 364 var $target = $( e.target ), 365 modal = '.cover-modal.active'; 366 367 if ( $target.is( modal ) ) { 368 369 chaplin.coverModals.untoggleModal( $target ); 370 371 } 372 373 } ); 374 375 }, 376 377 // Close modal on escape key press 378 closeOnEscape: function() { 379 380 $doc.keyup( function( e ) { 381 if ( e.key === "Escape" ) { 382 $( '.cover-modal.active' ).each( function() { 383 chaplin.coverModals.untoggleModal( $( this ) ); 384 } ); 385 } 386 } ); 387 388 }, 389 390 // Show modals on load 391 showOnLoadandClick: function() { 392 393 var key = 'modal'; 394 395 // Load based on query string 396 if ( window.location.search.indexOf( key ) !== -1 ) { 397 398 var modalTargetString = getQueryStringValue( key ), 399 $modalTarget = $( '#' + modalTargetString + '-modal' ); 400 401 if ( modalTargetString && $modalTarget.length ) { 402 setTimeout( function() { 403 $modalTarget.addClass( 'active' ).triggerHandler( 'toggled' ); 404 chaplin.scrollLock.setTo( true ); 405 }, 250 ); 406 } 407 } 408 409 // Check for modal matching querystring when clicking a link 410 // Format: www.url.com?modal=modal-id 411 $( 'a' ).on( 'click', function() { 412 413 // Load based on query string 414 if ( $( this ).attr( 'href' ) && $( this ).attr( 'href' ).indexOf( key ) !== -1 ) { 415 416 var modalTargetString = getQueryStringValue( key, $( this ).attr( 'href' ) ), 417 $modalTarget = $( '#' + modalTargetString ); 418 419 if ( modalTargetString && $modalTarget.length ) { 420 421 $modalTarget.addClass( 'active' ).triggerHandler( 'toggled' ); 422 chaplin.scrollLock.setTo( true ); 423 424 return false;
425 426 } 427 } 428 429 } ); 430 431 }, 432 433 // Hide and show modals before and after their animations have played out 434 hideAndShowModals: function() { 435 436 var $modals = $( '.cover-modal' ); 437 438 // Show the modal 439 $modals.on( 'toggle-target-before-inactive', function( e ) { 440 if ( e.target != this ) return; 441 442 $( this ).addClass( 'show-modal' ); 443 } ); 444 445 // Hide the modal after a delay, so animations have time to play out 446 $modals.on( 'toggle-target-after-inactive', function( e ) { 447 if ( e.target != this ) return; 448 449 var $modal = $( this ); 450 setTimeout( function() { 451 $modal.removeClass( 'show-modal' ); 452 }, 500 ); 453 } ); 454 455 }, 456 457 // Untoggle a modal 458 untoggleModal: function( $modal ) { 459 460 $modalToggle = false; 461 462 // If the modal has specified the string (ID or class) used by toggles to target it, untoggle the toggles with that target string 463 // The modal-target-string must match the string toggles use to target the modal 464 if ( $modal.data( 'modal-target-string' ) ) { 465 var modalTargetClass = $modal.data( 'modal-target-string' ), 466 $modalToggle = $( '*[data-toggle-target="' + modalTargetClass + '"]' ).first(); 467 } 468 469 // If a modal toggle exists, trigger it so all of the toggle options are included 470 if ( $modalToggle && $modalToggle.length ) { 471 $modalToggle.trigger( 'click' ); 472 473 // If one doesn't exist, just hide the modal 474 } else { 475 $modal.removeClass( 'active' ); 476 } 477 478 } 479 480} // chaplin.coverModals 481 482 483/* ----------------------------------------------------------------------------------------------- 484 Element In View 485--------------------------------------------------------------------------------------------------- */ 486 487chaplin.elementInView = { 488 489 init: function() { 490 491 $targets = $( '.do-spot' ); 492 chaplin.elementInView.run( $targets ); 493 494 // Rerun on AJAX content loaded 495 $win.on( 'ajax-content-loaded', function() { 496 $targets = $( '.do-spot' ); 497 chaplin.elementInView.run( $targets ); 498 } ); 499 500 }, 501 502 run: function( $targets ) { 503 504 if ( $targets.length ) { 505 506 // Add class indicating the elements will be spotted 507 $targets.each( function() { 508 $( this ).addClass( 'will-be-spotted' ); 509 } ); 510 511 chaplin.elementInView.handleFocus( $targets ); 512 } 513 514 }, 515 516 handleFocus: function( $targets ) { 517 518 // Get dimensions of window outside of scroll for performance 519 $win.on( 'load resize orientationchange', function() { 520 winHeight = $win.height(); 521 } ); 522 523 $win.on( 'resize orientationchange did-interval-scroll', function() { 524 525 var winTop = $win.scrollTop(); 526 winBottom = winTop + winHeight; 527 528 // Check for our targets 529 $targets.each( function() { 530 531 var $this = $( this ); 532 533 if ( chaplin.elementInView.isVisible( $this, checkAbove = true ) ) { 534 $this.addClass( 'spotted' ).triggerHandler( 'spotted' ); 535 } 536 537 } ); 538 539 } ); 540 541 }, 542 543 // Determine whether the element is in view 544 isVisible: function( $elem, checkAbove ) { 545 546 if ( typeof checkAbove === 'undefined' ) { 547 checkAbove = false; 548 } 549 550 var winHeight = $win.height(); 551 552 var docViewTop = $win.scrollTop(), 553 docViewBottom = docViewTop + winHeight, 554 docViewLimit = docViewBottom - 50; 555 556 var elemTop = $elem.offset().top, 557 elemBottom = $elem.offset().top + $elem.outerHeight(); 558 559 // If checkAbove is set to true, which is default, return true if the browser has already scrolled past the element 560 if ( checkAbove && ( elemBottom <= docViewBottom ) ) { 561 return true; 562 } 563 564 // If not, check whether the scroll limit exceeds the element top 565 return ( docViewLimit >= elemTop ); 566 567 } 568 569} // chaplin.elementInView 570 571 572/* ----------------------------------------------------------------------------------------------- 573 Fade Blocks 574--------------------------------------------------------------------------------------------------- */ 575 576chaplin.fadeBlocks = { 577 578 init: function() { 579 580 var scroll = window.requestAnimationFrame || 581 window.webkitRequestAnimationFrame || 582 window.mozRequestAnimationFrame || 583 window.msRequestAnimationFrame || 584 window.oRequestAnimationFrame || 585 // IE Fallback, you can even fallback to onscroll 586 function( callback ) { window.setTimeout( callback, 1000/60 ) }; 587 588 function loop() { 589 590 var windowOffset = window.pageYOffset; 591 592 if ( windowOffset < $win.outerHeight() ) { 593 $( '.fade-block' ).css({ 594 'opacity': 1 - ( windowOffset * 0.002 ) 595 } ); 596 } 597 598 scroll( loop ) 599 600 } 601 loop(); 602 603 }, 604 605} // chaplin.fadeBlocks 606 607 608/* ----------------------------------------------------------------------------------------------- 609 Smooth Scroll 610--------------------------------------------------------------------------------------------------- */ 611 612chaplin.smoothScroll = { 613 614 init: function() { 615 616 // Scroll to on-page elements by hash 617 $( 'body:not(.disable-smooth-scroll) a[href*="#"]' ).not( '[href="#"]' ).not( '[href="#0"]' ).not( '.do-not-smooth-scroll' ).on( 'click', function( e ) { 618 if ( location.pathname.replace(/^\//, '' ) == this.pathname.replace(/^\//, '' ) && location.hostname == this.hostname ) { 619 var $target = $( this.hash ).length ? $( this.hash ) : $( '[name=' + this.hash.slice(1) + ']' ); 620 chaplin.smoothScroll.scrollToTarget( $target, $( this ) ); 621 e.preventDefault(); 622 } 623 } ); 624 625 // Scroll to elements specified with a data attribute 626 $( 'body:not(.disable-smooth-scroll) *[data-scroll-to]' ).on( 'click', function( e ) { 627 var $target = $( $( this ).data( 'scroll-to' ) ); 628 chaplin.smoothScroll.scrollToTarget( $target, $( this ) ); 629 e.preventDefault(); 630 } ); 631 632 }, 633 634 // Scroll to target 635 scrollToTarget: function( $target, $clickElem ) { 636 637 if ( $target.length ) { 638 639 var additionalOffset = 0, 640 scrollSpeed = 500; 641 642 // Get options 643 if ( $clickElem && $clickElem.length ) { 644 additionalOffset = $clickElem.data( 'additional-offset' ) ? $clickElem.data( 'additional-offset' ) : additionalOffset, 645 scrollSpeed = $clickElem.data( 'scroll-speed' ) ? $clickElem.data( 'scroll-speed' ) : scrollSpeed; 646 } 647 648 // Determine offset 649 var originalOffset = $target.offset().top; 650 651 // Special handling of scroll offset when scroll locked 652 if ( $( 'html' ).attr( 'scroll-lock-top' ) ) { 653 var originalOffset = parseInt( $( 'html' ).attr( 'scroll-lock-top' ) ) + $target.offset().top; 654 } 655 656 // If the header is sticky, subtract its height from the offset 657 if ( $( '.header-inner.stick-me' ).length ) { 658 var originalOffset = originalOffset - $( '.header-inner.stick-me' ).outerHeight(); 659 } 660 661 // Close any parent modal before scrolling 662 if ( $clickElem.closest( '.cover-modal' ).length ) { 663 chaplin.coverModals.untoggleModal( $clickElem.closest( '.cover-modal' ) ); 664 } 665 666 // Add the additional offset 667 var scrollOffset = originalOffset + additionalOffset; 668 669 chaplin.smoothScroll.scrollToPosition( scrollOffset, scrollSpeed ); 670 671 } 672 673 }, 674 675 scrollToPosition: function( position, speed ) { 676 677 $( 'html, body' ).animate( { 678 scrollTop: position, 679 }, speed, function() { 680 $win.trigger( 'did-interval-scroll' ); 681 } ); 682 683 } 684 685} // chaplin.smoothScroll 686 687 688/* ----------------------------------------------------------------------------------------------- 689 Stick Me 690--------------------------------------------------------------------------------------------------- */ 691chaplin.stickMe = { 692 693 init: function() { 694 695 var $stickyElement = $( '.stick-me' ); 696 697 if ( $stickyElement.length ) { 698 699 var stickyClass = 'is-sticky', 700 stickyOffset = $stickyElement.scrollTop(); 701 702 // Our stand-in element for stickyElement while stickyElement is off on a scroll 703 if ( ! $( '.sticky-adjuster' ).length ) { 704 $stickyElement.before( '<div class="sticky-adjuster"></div>' ); 705 } 706 707 // Stick it on resize, scroll and load 708 $win.on( 'resize scroll load', function(){ 709 var stickyOffset = $( '.sticky-adjuster' ).offset().top; 710 chaplin.stickMe.stickIt( $stickyElement, stickyClass, stickyOffset ); 711 } ); 712 713 chaplin.stickMe.stickIt( $stickyElement, stickyClass, stickyOffset ); 714 715 } 716 717 }, 718 719 // Check whether to stick the element
720 stickIt: function ( $stickyElement, stickyClass, stickyOffset ) { 721 722 var winScroll = $win.scrollTop(); 723 724 if ( $stickyElement.css( 'display' ) != 'none' && winScroll > stickyOffset ) { 725 726 // If a sticky edge element exists and we've scrolled past it, stick it 727 if ( ! $stickyElement.hasClass( stickyClass ) ) { 728 $stickyElement.addClass( stickyClass ); 729 $( '.sticky-adjuster' ).height( $stickyElement.outerHeight() ).css( 'margin-bottom', parseInt( $stickyElement.css( 'marginBottom' ) ) ); 730 if ( $stickyElement.is( '.header-inner' ) ) { 731 $( 'body' ).addClass( 'header-is-sticky' ); 732 } 733 } 734 735 // If not, remove class and sticky-adjuster properties 736 } else { 737 chaplin.stickMe.unstickIt( $stickyElement, stickyClass ); 738 } 739 740 }, 741 742 unstickIt: function( $stickyElement, stickyClass ) { 743 744 $stickyElement.removeClass( stickyClass ); 745 $( '.sticky-adjuster' ).height( 0 ).css( 'margin-bottom', '0' ); 746 747 if ( $stickyElement.is( '.header-inner' ) ) { 748 $( 'body' ).removeClass( 'header-is-sticky' ); 749 } 750 751 } 752 753} // Stick Me 754 755 756/* ----------------------------------------------------------------------------------------------- 757 Intrinsic Ratio Embeds 758--------------------------------------------------------------------------------------------------- */ 759 760chaplin.instrinsicRatioVideos = { 761 762 init: function() { 763 764 chaplin.instrinsicRatioVideos.makeFit(); 765 766 $win.on( 'resize fit-videos', function() { 767 768 chaplin.instrinsicRatioVideos.makeFit(); 769 770 } ); 771 772 }, 773 774 makeFit: function() { 775 776 var vidSelector = "iframe, object, video"; 777 778 $( vidSelector ).each( function() { 779 780 var $video = $( this ), 781 $container = $video.parent(), 782 iTargetWidth = $container.width(); 783 784 // Skip videos we want to ignore 785 if ( $video.hasClass( 'intrinsic-ignore' ) || $video.parent().hasClass( 'intrinsic-ignore' ) ) { 786 return true; 787 } 788 789 if ( ! $video.attr( 'data-origwidth' ) ) { 790 791 // Get the video element proportions 792 $video.attr( 'data-origwidth', $video.attr( 'width' ) ); 793 $video.attr( 'data-origheight', $video.attr( 'height' ) ); 794 795 } 796 797 // Get ratio from proportions 798 var ratio = iTargetWidth / $video.attr( 'data-origwidth' ); 799 800 // Scale based on ratio, thus retaining proportions 801 $video.css( 'width', iTargetWidth + 'px' ); 802 $video.css( 'height', ( $video.attr( 'data-origheight' ) * ratio ) + 'px' ); 803 804 } ); 805 806 } 807 808} // chaplin.instrinsicRatioVideos 809 810 811/* ----------------------------------------------------------------------------------------------- 812 Scroll Lock 813--------------------------------------------------------------------------------------------------- */ 814 815chaplin.scrollLock = { 816 817 init: function() { 818 819 // Init variables 820 window.scrollLocked = false, 821 window.prevScroll = { 822 scrollLeft : $win.scrollLeft(), 823 scrollTop : $win.scrollTop() 824 }, 825 window.prevLockStyles = {}, 826 window.lockStyles = { 827 'overflow-y' : 'scroll', 828 'position' : 'fixed', 829 'width' : '100%' 830 }; 831 832 // Instantiate cache in case someone tries to unlock before locking 833 chaplin.scrollLock.saveStyles(); 834 835 }, 836 837 // Save context's inline styles in cache 838 saveStyles: function() { 839 840 var styleAttr = $( 'html' ).attr( 'style' ), 841 styleStrs = [], 842 styleHash = {}; 843 844 if ( ! styleAttr ) { 845 return; 846 } 847 848 styleStrs = styleAttr.split( /;\s/ ); 849 850 $.each( styleStrs, function serializeStyleProp( styleString ) { 851 if ( ! styleString ) { 852 return; 853 } 854 855 var keyValue = styleString.split( /\s:\s/ ); 856 857 if ( keyValue.length < 2 ) { 858 return; 859 } 860 861 styleHash[ keyValue[ 0 ] ] = keyValue[ 1 ]; 862 } ); 863 864 $.extend( prevLockStyles, styleHash ); 865 }, 866 867 // Lock the scroll (do not call this directly) 868 lock: function() { 869 870 var appliedLock = {}; 871 872 if ( scrollLocked ) { 873 return; 874 } 875 876 // Save scroll state and styles 877 prevScroll = { 878 scrollLeft : $win.scrollLeft(), 879 scrollTop : $win.scrollTop() 880 }; 881 882 chaplin.scrollLock.saveStyles(); 883 884 // Compose our applied CSS, with scroll state as styles 885 $.extend( appliedLock, lockStyles, { 886 'left' : - prevScroll.scrollLeft + 'px', 887 'top' : - prevScroll.scrollTop + 'px' 888 } ); 889 890 // Then lock styles and state 891 $( 'html' ).css( appliedLock ); 892 $( 'html' ).addClass( 'scroll-locked' );
893 $( 'html' ).attr( 'scroll-lock-top', prevScroll.scrollTop ); 894 $win.scrollLeft( 0 ).scrollTop( 0 ); 895 896 window.scrollLocked = true; 897 }, 898 899 // Unlock the scroll (do not call this directly) 900 unlock: function() { 901 902 if ( ! window.scrollLocked ) { 903 return; 904 } 905 906 // Revert styles and state 907 $( 'html' ).attr( 'style', $( '<x>' ).css( prevLockStyles ).attr( 'style' ) || '' ); 908 $( 'html' ).removeClass( 'scroll-locked' ); 909 $( 'html' ).attr( 'scroll-lock-top', '' ); 910 $win.scrollLeft( prevScroll.scrollLeft ).scrollTop( prevScroll.scrollTop ); 911 912 window.scrollLocked = false; 913 }, 914 915 // Call this to lock or unlock the scroll 916 setTo: function( on ) { 917 918 // If an argument is passed, lock or unlock accordingly 919 if ( arguments.length ) { 920 if ( on ) { 921 chaplin.scrollLock.lock(); 922 } else { 923 chaplin.scrollLock.unlock(); 924 } 925 // If not, toggle to the inverse state 926 } else { 927 if ( window.scrollLocked ) { 928 chaplin.scrollLock.unlock(); 929 } else { 930 chaplin.scrollLock.lock(); 931 } 932 } 933 934 }, 935 936} // chaplin.scrollLock 937 938 939/* ----------------------------------------------------------------------------------------------- 940 Dynamic Screen Height 941--------------------------------------------------------------------------------------------------- */ 942 943chaplin.dynamicScreenHeight = { 944 945 init: function() { 946 947 var $screenHeight = $( '.screen-height' ); 948 949 $screenHeight.css( 'min-height', $win.innerHeight() ); 950 951 setTimeout( function() { 952 $screenHeight.css( 'min-height', $win.innerHeight() ); 953 }, 500 ); 954 955 $win.on( 'resize', function() { 956 $screenHeight.css( 'min-height', $win.innerHeight() ); 957 } ); 958 959 }, 960 961} // chaplin.dynamicScreenHeight 962 963 964/* ----------------------------------------------------------------------------------------------- 965 Focus Management 966--------------------------------------------------------------------------------------------------- */ 967 968chaplin.focusManagement = { 969 970 init: function() { 971 972 // Add and remove a class from dropdown menu items on focus 973 chaplin.focusManagement.dropdownFocus(); 974 975 // If the visitor tabs out of the main menu, return focus to the navigation toggle 976 // Also, if the visitor tabs into a hidden element, move the focus to the element after the hidden element 977 chaplin.focusManagement.focusLoop(); 978 979 }, 980 981 focusLoop: function() { 982 $( 'input, a, button' ).on( 'focus', function() { 983 if ( $( '.menu-modal' ).is( '.active' ) ) { 984 if ( ! $( this ).parents( '.menu-modal' ).length ) { 985 $( '.nav-untoggle' ).focus(); 986 } 987 } else if ( $( '.search-modal' ).is( '.active' ) ) { 988 if ( ! $( this ).parents( '.search-modal' ).length ) { 989 $( '.search-modal .search-field' ).focus(); 990 } 991 } 992 } ); 993 }, 994 995 dropdownFocus: function() { 996 $( '.dropdown-menu a' ).on( 'blur focus', function( e ) { 997 $( this ).parents( 'li.menu-item-has-children' ).toggleClass( 'focus' ); 998 if ( e.type == 'focus' ) $( this ).trigger( 'focus-applied' ); 999 } ); 1000 } 1001 1002} // chaplin.focusManagement 1003 1004 1005/* ----------------------------------------------------------------------------------------------- 1006 Main Menu 1007--------------------------------------------------------------------------------------------------- */ 1008 1009chaplin.mainMenu = { 1010 1011 init: function() { 1012 1013 // If the current menu item is in a sub level, expand all the levels higher up on load 1014 chaplin.mainMenu.expandLevel(); 1015 1016 // Determine the direction of sub menus in the alt menu 1017 chaplin.mainMenu.directionCheck(); 1018 1019 }, 1020 1021 // If the current menu item is in a sub level, expand all the levels higher up on load 1022 expandLevel: function() { 1023 var $activeMenuItem = $( '.main-menu .current-menu-item' ); 1024 1025 if ( $activeMenuItem.length !== false ) { 1026 $activeMenuItem.parents( 'li' ).each( function() { 1027 $subMenuToggle = $( this ).find( '.sub-menu-toggle' ).first(); 1028 if ( $subMenuToggle.length ) { 1029 $subMenuToggle.trigger( 'click' ); 1030 } 1031 } ) 1032 } 1033 }, 1034 1035 // Determine the direction of sub menus in the alt menu 1036 directionCheck: function() { 1037 1038 // Note: the focus-applied event is triggered 1039 // by chaplin.focusManagement.dropdownFocus when 1040 // the sub has been given the .focus class. 1041 1042 $( '.main-menu-alt ul a' ).on( 'mouseover focus-applied', function() { 1043 var $sub = $( this ).closest( 'li' ).find( 'ul' ).first(); 1044 if ( $sub.length ) { 1045 1046 $descendantSubs = $sub.find( 'ul' ); 1047 1048 var subOffsetLeft = $sub.offset().left, 1049 subOffsetRight = subOffsetLeft + $sub.outerWidth(), 1050 winWidth = $win.width(); 1051 1052 if ( subOffsetRight > winWidth ) { 1053 $sub.add( $descendantSubs ).removeClass( 'expand-right' ).addClass( 'expand-left' ); 1054 } else if ( subOffsetLeft < 0 ) { 1055 $sub.add( $descendantSubs ).removeClass( 'expand-left' ).addClass( 'expand-right' ); 1056 } 1057 1058 } 1059 } ); 1060 1061 } 1062 1063} // chaplin.mainMenu 1064 1065 1066/* ----------------------------------------------------------------------------------------------- 1067 Load More 1068--------------------------------------------------------------------------------------------------- */ 1069 1070chaplin.loadMore = { 1071 1072 init: function() { 1073 1074 var $pagination = $( '#pagination' ); 1075 1076 // First, check that there's a pagination 1077 if ( $pagination.length ) { 1078 1079 // Default values for variables 1080 window.loading = false;
1081 window.lastPage = $pagination.hasClass( 'last-page' ); 1082 1083 // Load more posts 1084 chaplin.loadMore.prepare( $pagination ); 1085 1086 // Update browser history when the visitor scrolls through loaded posts 1087 chaplin.loadMore.updateHistoryOnScroll(); 1088 1089 } 1090 1091 }, 1092 1093 prepare: function( $pagination ) { 1094 1095 // Get the query arguments from the pagination element 1096 var query_args = JSON.parse( $pagination.attr( 'data-query-args' ) ); 1097 1098 // If we're already at the last page, exit out here 1099 if ( query_args.paged == query_args.max_num_pages ) { 1100 $pagination.addClass( 'last-page' ); 1101 } else { 1102 $pagination.removeClass( 'last-page' ); 1103 } 1104 1105 // Get the load more type (button or scroll) 1106 var loadMoreType = $pagination.data( 'pagination-type' ); 1107 1108 if ( ! loadMoreType ) { 1109 var loadMoreType = 'links'; 1110 } 1111 1112 // Do the appropriate load more detection, depending on the type 1113 if ( loadMoreType == 'scroll' ) { 1114 chaplin.loadMore.detectScroll( $pagination, query_args ); 1115 } else if ( loadMoreType == 'button' ) { 1116 chaplin.loadMore.detectButtonClick( $pagination, query_args ); 1117 } 1118 1119 }, 1120 1121 // Load more on scroll 1122 detectScroll: function( $pagination, query_args ) { 1123 1124 $win.on( 'did-interval-scroll', function() { 1125 1126 // If it's the last page, or we're already loading, we're done here 1127 if ( lastPage || loading ) { 1128 return; 1129 } 1130 1131 var paginationOffset = $pagination.offset().top, 1132 winOffset = $win.scrollTop() + $win.outerHeight(); 1133 1134 // If the bottom of the window is below the top of the pagination, start loading 1135 if ( ( winOffset > paginationOffset ) ) { 1136 chaplin.loadMore.loadPosts( $pagination, query_args ); 1137 } 1138 1139 } ); 1140 1141 }, 1142 1143 // Load more on click 1144 detectButtonClick: function( $pagination, query_args ) { 1145 1146 // Load on click 1147 $( '#load-more' ).on( 'click', function() { 1148 1149 // Make sure we aren't already loading 1150 if ( loading ) { 1151 return; 1152 } 1153 1154 chaplin.loadMore.loadPosts( $pagination, query_args ); 1155 return false; 1156 } ); 1157 1158 }, 1159 1160 // Load the posts 1161 loadPosts: function( $pagination, query_args ) { 1162 1163 // We're now loading 1164 loading = true; 1165 $pagination.addClass( 'loading' ).removeClass( 'last-page' ); 1166 1167 // Increment paged to indicate another page has been loaded 1168 query_args.paged++; 1169 1170 // Prepare the query args for submission 1171 var json_query_args = JSON.stringify( query_args ); 1172 1173 $.ajax({ 1174 url: chaplin_ajax_load_more.ajaxurl, 1175 type: 'post', 1176 data: { 1177 action: 'chaplin_ajax_load_more', 1178 json_data: json_query_args 1179 }, 1180 success: function( result ) { 1181 1182 // Get the results 1183 var $result = $( result ), 1184 $articleWrapper = $( $pagination.data( 'load-more-target' ) ); 1185 1186 // If there are no results, we're at the last page 1187 if ( ! $result.length ) { 1188 loading = false; 1189 $articleWrapper.addClass( 'no-results' ); 1190 $pagination.addClass( 'last-page' ).removeClass( 'loading' ); 1191 } 1192 1193 if ( $result.length ) { 1194 1195 $articleWrapper.removeClass( 'no-results' ); 1196 1197 // Add the paged attribute to the articles, used by updateHistoryOnScroll() 1198 $result.find( 'article' ).each( function() { 1199 $( this ).attr( 'data-post-paged', query_args.paged ); 1200 } ); 1201 1202 // Wait for the images to load 1203 $result.imagesLoaded( function() { 1204 1205 // Append the results 1206 $articleWrapper.append( $result ); 1207 1208 $win.triggerHandler( 'ajax-content-loaded' ); 1209 $win.triggerHandler( 'did-interval-scroll' ); 1210 1211 // Update history 1212 chaplin.loadMore.updateHistory( query_args.paged ); 1213 1214 // We're now finished with the loading 1215 loading = false; 1216 $pagination.removeClass( 'loading' ); 1217 1218 // If that was the last page, make sure we don't check for any more 1219 if ( query_args.paged == query_args.max_num_pages ) { 1220 $pagination.addClass( 'last-page' ); 1221 lastPage = true; 1222 return; 1223 } else { 1224 $pagination.removeClass( 'last-page' ); 1225 lastPage = false; 1226 } 1227 1228 } ); 1229 1230 } 1231 1232 }, 1233 1234 error: function( jqXHR, exception ) { 1235 chaplinAJAXErrors( jqXHR, exception ); 1236 } 1237 } ); 1238 1239 }, 1240 1241 // Update browser history on scroll 1242 updateHistoryOnScroll: function() { 1243 1244 // Get the initial paged value 1245 var initialPaged = chaplin.loadMore.getCurrentPaged(); 1246 1247 // Get the last post visible in the viewport, and set the browser history to the paged attribute of that post 1248 $win.on( 'did-interval-scroll', function() { 1249 1250 var $posts = $( '.posts article' ); 1251 1252 // Check if the page has had posts loaded 1253 // This attribute is added by the loadPosts function 1254 if ( $posts.length && $( '[data-post-paged]' ).length ) { 1255 1256 // Store the ID attributes of the posts above the bottom of the viewport 1257 var postsVisible = []; 1258 1259 // Get the bottom of the viewport 1260 var winBottom = $win.scrollTop() + $win.height(); 1261 1262 $posts.each( function() { 1263 1264 var elemBottom = $( this ).offset().top + $( this ).outerHeight(), 1265 elemId = $( this ).attr( 'id' ); 1266 1267 // Add or remove the ID of the post, depending on whether it's within the viewport 1268 if ( elemBottom < winBottom ) { 1269 postsVisible.push( elemId ); 1270 } else { 1271 var index = postsVisible.indexOf( elemId ); 1272 if ( index !== -1 ) postsVisible.splice( elemId, 1 ); 1273 } 1274 1275 } ); 1276 1277 // If we have visible posts, check if we need to update the history 1278 if ( postsVisible.length !== 0 ) { 1279 1280 // Get the last visible post 1281 var $lastPost = $( '#' + postsVisible[postsVisible.length - 1] ); 1282 1283 // Get the paged attribute of the post, or default to the initial paged value 1284 // (The initial set of posts do not have a paged attribute)
1285 var newPaged = $lastPost.attr( 'data-post-paged' ) ? $lastPost.attr( 'data-post-paged' ) : initialPaged, 1286 currentPaged = chaplin.loadMore.getCurrentPaged(); 1287 1288 // Update the browser history with the paged value of the post 1289 if ( newPaged !== currentPaged ) { 1290 chaplin.loadMore.updateHistory( newPaged ); 1291 } 1292 1293 } 1294 1295 } 1296 1297 } ); 1298 1299 }, 1300 1301 // Update browser history 1302 updateHistory: function( paged ) { 1303 1304 var newUrl, 1305 currentUrl = document.location.href; 1306 1307 // Ensure trailing slash 1308 if ( currentUrl.substr( -1 ) != '/' ) currentUrl += '/'; 1309 1310 var hasPaginationRegexp = new RegExp( '^(.*/page)/[0-9]*/(.*$)' ); 1311 1312 if ( hasPaginationRegexp.test( currentUrl ) ) { 1313 if ( paged ) { 1314 newUrl = currentUrl.replace( hasPaginationRegexp, '$1/' + paged + '/$2' ); 1315 } else { 1316 // If there's no paged, remove /page/X from the string 1317 var pageString = currentUrl.match( /\/page\/(\d*)/ )[0]; 1318 if ( pageString ) { 1319 newUrl = currentUrl.replace( pageString, '' ); 1320 } 1321 } 1322 } else { 1323 var beforeSearchReplaceRegexp = new RegExp( '^([^?]*)(\\??.*$)' ); 1324 newUrl = currentUrl.replace( beforeSearchReplaceRegexp, '$1page/' + paged + '/$2' ); 1325 } 1326 1327 if ( newUrl == currentUrl ) return; 1328 1329 history.pushState( {}, '', newUrl ); 1330 1331 }, 1332 1333 // Get current paged value 1334 getCurrentPaged: function() { 1335 1336 var currentPaged = 0, 1337 currentUrl = document.location.href; 1338 1339 if ( new RegExp( '\/page\/(\d*)' ).test( currentUrl ) ) { 1340 currentPaged = currentUrl.match( /\/page\/(\d*)/ )[1]; 1341 } 1342 1343 return currentPaged; 1344 1345 }, 1346 1347} // chaplin.loadMore 1348 1349 1350/* ----------------------------------------------------------------------------------------------- 1351 Function Calls 1352--------------------------------------------------------------------------------------------------- */ 1353 1354$doc.ready( function() { 1355 1356 chaplin.intervalScroll.init(); // Check for scroll on an interval 1357 chaplin.resizeEnd.init(); // Trigger event at end of resize 1358 chaplin.toggles.init(); // Handle toggles 1359 chaplin.coverModals.init(); // Handle cover modals 1360 chaplin.elementInView.init(); // Check if elements are in view 1361 chaplin.fadeBlocks.init(); // Fade elements on scroll 1362 chaplin.instrinsicRatioVideos.init(); // Retain aspect ratio of videos on window resize 1363 chaplin.smoothScroll.init(); // Smooth scroll to anchor link or a specific element 1364 chaplin.stickMe.init(); // Stick elements on scroll 1365 chaplin.scrollLock.init(); // Scroll Lock 1366 chaplin.mainMenu.init(); // Main Menu 1367 chaplin.focusManagement.init(); // Focus Management 1368 chaplin.dynamicScreenHeight.init(); // Dynamic Screen Height
1369 chaplin.loadMore.init(); // Load More 1370 1371} );
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.