WordPress/wp-content/themes/twentyseventeen/assets/js/global.js
Joe McGill e2b7762e9a Twenty Seventeen: Better handling of custom headers when no image is set.
This ensures that a standard header is shown on the front page whenever
a header video is set without a header image if the video doesn't load,
e.g., on mobile sizes or if the JS doesn't fire.

This adds a new class, `.has-header-video` that is added whenever the
`wp-custom-header-video-loaded` event is fired, which is then used to style
the custom headers along with `.has-header-image` whenever a header image
is available. This also changes the class name on the custom header media
wrapping `div` from `.custom-header-image` to `.custom-header-media`.

Props laurelfulford, joemcgill.
Fixes #38995.
Built from https://develop.svn.wordpress.org/trunk@39413


git-svn-id: http://core.svn.wordpress.org/trunk@39353 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-12-02 05:12:41 +00:00

250 lines
7.5 KiB
JavaScript

/* global twentyseventeenScreenReaderText */
(function( $ ) {
// Variables and DOM Caching.
var $body = $( 'body' ),
$customHeader = $body.find( '.custom-header' ),
$branding = $customHeader.find( '.site-branding' ),
$navigation = $body.find( '.navigation-top' ),
$navWrap = $navigation.find( '.wrap' ),
$navMenuItem = $navigation.find( '.menu-item' ),
$menuToggle = $navigation.find( '.menu-toggle' ),
$menuScrollDown = $body.find( '.menu-scroll-down' ),
$sidebar = $body.find( '#secondary' ),
$entryContent = $body.find( '.entry-content' ),
$formatQuote = $body.find( '.format-quote blockquote' ),
isFrontPage = $body.hasClass( 'twentyseventeen-front-page' ) || $body.hasClass( 'home blog' ),
navigationFixedClass = 'site-navigation-fixed',
navigationHeight,
navigationOuterHeight,
navPadding,
navMenuItemHeight,
idealNavHeight,
navIsNotTooTall,
headerOffset,
menuTop = 0,
resizeTimer;
// Ensure the sticky navigation doesn't cover current focused links.
$( 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex], [contenteditable]', '.site-content-contain' ).filter( ':visible' ).focus( function() {
if ( $navigation.hasClass( 'site-navigation-fixed' ) ) {
var windowScrollTop = $( window ).scrollTop(),
fixedNavHeight = $navigation.height(),
itemScrollTop = $( this ).offset().top,
offsetDiff = itemScrollTop - windowScrollTop;
// Account for Admin bar.
if ( $( '#wpadminbar' ).length ) {
offsetDiff -= $( '#wpadminbar' ).height();
}
if ( offsetDiff < fixedNavHeight ) {
$( window ).scrollTo( itemScrollTop - ( fixedNavHeight + 50 ), 0 );
}
}
});
// Set properties of navigation.
function setNavProps() {
navigationHeight = $navigation.height();
navigationOuterHeight = $navigation.outerHeight();
navPadding = parseFloat( $navWrap.css( 'padding-top' ) ) * 2;
navMenuItemHeight = $navMenuItem.outerHeight() * 2;
idealNavHeight = navPadding + navMenuItemHeight;
navIsNotTooTall = navigationHeight <= idealNavHeight;
}
// Make navigation 'stick'.
function adjustScrollClass() {
// Make sure we're not on a mobile screen.
if ( 'none' === $menuToggle.css( 'display' ) ) {
// Make sure the nav isn't taller than two rows.
if ( navIsNotTooTall ) {
// When there's a custom header image or video, the header offset includes the height of the navigation.
if ( isFrontPage && ( $body.hasClass( 'has-header-image' ) || $body.hasClass( 'has-header-video' ) ) ) {
headerOffset = $customHeader.innerHeight() - navigationOuterHeight;
} else {
headerOffset = $customHeader.innerHeight();
}
// If the scroll is more than the custom header, set the fixed class.
if ( $( window ).scrollTop() >= headerOffset ) {
$navigation.addClass( navigationFixedClass );
} else {
$navigation.removeClass( navigationFixedClass );
}
} else {
// Remove 'fixed' class if nav is taller than two rows.
$navigation.removeClass( navigationFixedClass );
}
}
}
// Set margins of branding in header.
function adjustHeaderHeight() {
if ( 'none' === $menuToggle.css( 'display' ) ) {
// The margin should be applied to different elements on front-page or home vs interior pages.
if ( isFrontPage ) {
$branding.css( 'margin-bottom', navigationOuterHeight );
} else {
$customHeader.css( 'margin-bottom', navigationOuterHeight );
}
} else {
$customHeader.css( 'margin-bottom', '0' );
$branding.css( 'margin-bottom', '0' );
}
}
// Set icon for quotes.
function setQuotesIcon() {
$( twentyseventeenScreenReaderText.quote ).prependTo( $formatQuote );
}
// Add 'below-entry-meta' class to elements.
function belowEntryMetaClass( param ) {
var sidebarPos, sidebarPosBottom;
if ( ! $body.hasClass( 'has-sidebar' ) || (
$body.hasClass( 'search' ) ||
$body.hasClass( 'single-attachment' ) ||
$body.hasClass( 'error404' ) ||
$body.hasClass( 'twentyseventeen-front-page' )
) ) {
return;
}
sidebarPos = $sidebar.offset();
sidebarPosBottom = sidebarPos.top + ( $sidebar.height() + 28 );
$entryContent.find( param ).each( function() {
var $element = $( this ),
elementPos = $element.offset(),
elementPosTop = elementPos.top;
// Add 'below-entry-meta' to elements below the entry meta.
if ( elementPosTop > sidebarPosBottom ) {
$element.addClass( 'below-entry-meta' );
} else {
$element.removeClass( 'below-entry-meta' );
}
});
}
/*
* Test if inline SVGs are supported.
* @link https://github.com/Modernizr/Modernizr/
*/
function supportsInlineSVG() {
var div = document.createElement( 'div' );
div.innerHTML = '<svg/>';
return 'http://www.w3.org/2000/svg' === ( 'undefined' !== typeof SVGRect && div.firstChild && div.firstChild.namespaceURI );
}
/**
* Test if an iOS device.
*/
function checkiOS() {
return /iPad|iPhone|iPod/.test(navigator.userAgent) && ! window.MSStream;
}
/*
* Test if background-attachment: fixed is supported.
* @link http://stackoverflow.com/questions/14115080/detect-support-for-background-attachment-fixed
*/
function supportsFixedBackground() {
var el = document.createElement('div'),
isSupported;
try {
if ( ! ( 'backgroundAttachment' in el.style ) || checkiOS() ) {
return false;
}
el.style.backgroundAttachment = 'fixed';
isSupported = ( 'fixed' === el.style.backgroundAttachment );
return isSupported;
}
catch (e) {
return false;
}
}
// Fire on document ready.
$( document ).ready( function() {
// If navigation menu is present on page, setNavProps and adjustScrollClass.
if ( $navigation.length ) {
setNavProps();
adjustScrollClass();
}
// If 'Scroll Down' arrow in present on page, calculate scroll offset and bind an event handler to the click event.
if ( $menuScrollDown.length ) {
if ( $( 'body' ).hasClass( 'admin-bar' ) ) {
menuTop -= 32;
}
if ( $( 'body' ).hasClass( 'blog' ) ) {
menuTop -= 30; // The div for latest posts has no space above content, add some to account for this.
}
if ( ! $navigation.length ) {
navigationOuterHeight = 0;
}
$menuScrollDown.click( function( e ) {
e.preventDefault();
$( window ).scrollTo( '#primary', {
duration: 600,
offset: { top: menuTop - navigationOuterHeight }
});
});
}
adjustHeaderHeight();
setQuotesIcon();
if ( true === supportsInlineSVG() ) {
document.documentElement.className = document.documentElement.className.replace( /(\s*)no-svg(\s*)/, '$1svg$2' );
}
if ( true === supportsFixedBackground() ) {
document.documentElement.className += ' background-fixed';
}
});
// If navigation menu is present on page, adjust it on scroll and screen resize.
if ( $navigation.length ) {
// On scroll, we want to stick/unstick the navigation.
$( window ).on( 'scroll', function() {
adjustScrollClass();
adjustHeaderHeight();
});
// Also want to make sure the navigation is where it should be on resize.
$( window ).resize( function() {
setNavProps();
setTimeout( adjustScrollClass, 500 );
});
}
$( window ).resize( function() {
clearTimeout( resizeTimer );
resizeTimer = setTimeout( function() {
belowEntryMetaClass( 'blockquote.alignleft, blockquote.alignright' );
}, 300 );
setTimeout( adjustHeaderHeight, 1000 );
});
// Add header video class after the video is loaded.
$( document ).on( 'wp-custom-header-video-loaded', function() {
$body.addClass( 'has-header-video' );
});
})( jQuery );