|
|
Line 1: |
Line 1: |
− | /**
| + | jQuery(document).ready(function($){ |
− | * main.js
| + | //if you change this breakpoint in the style.css file (or _layout.scss if you use SASS), don't forget to update this value as well |
− | * http://www.codrops.com
| + | var MQL = 1170; |
− | *
| + | |
− | * Licensed under the MIT license.
| + | |
− | * http://www.opensource.org/licenses/mit-license.php
| + | |
− | *
| + | |
− | * Copyright 2015, Codrops
| + | |
− | * http://www.codrops.com
| + | |
− | */
| + | |
− | ;(function(window) { | + | |
| | | |
− | 'use strict'; | + | //primary navigation slide-in effect |
− | | + | if($(window).width() > MQL) { |
− | var support = { transitions: Modernizr.csstransitions },
| + | var headerHeight = $('.cd-header').height(); |
− | // transition end event name
| + | $(window).on('scroll', |
− | transEndEventNames = { 'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'transitionend', 'OTransition': 'oTransitionEnd', 'msTransition': 'MSTransitionEnd', 'transition': 'transitionend' },
| + | { |
− | transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ],
| + | previousTop: 0 |
− | onEndTransition = function( el, callback ) {
| + | }, |
− | var onEndCallbackFn = function( ev ) {
| + | function () { |
− | if( support.transitions ) {
| + | var currentTop = $(window).scrollTop(); |
− | if( ev.target != this ) return;
| + | //check if user is scrolling up |
− | this.removeEventListener( transEndEventName, onEndCallbackFn );
| + | if (currentTop < this.previousTop ) { |
− | }
| + | //if scrolling up... |
− | if( callback && typeof callback === 'function' ) { callback.call(this); }
| + | if (currentTop > 0 && $('.cd-header').hasClass('is-fixed')) { |
− | };
| + | $('.cd-header').addClass('is-visible'); |
− | if( support.transitions ) {
| + | } else { |
− | el.addEventListener( transEndEventName, onEndCallbackFn );
| + | $('.cd-header').removeClass('is-visible is-fixed'); |
− | }
| + | } |
− | else {
| + | } else { |
− | onEndCallbackFn();
| + | //if scrolling down... |
− | }
| + | $('.cd-header').removeClass('is-visible'); |
− | }, | + | if( currentTop > headerHeight && !$('.cd-header').hasClass('is-fixed')) $('.cd-header').addClass('is-fixed'); |
− | // the pages wrapper
| + | } |
− | stack = document.querySelector('.pages-stack'),
| + | this.previousTop = currentTop; |
− | // the page elements
| + | |
− | pages = [].slice.call(stack.children),
| + | |
− | // total number of page elements | + | |
− | pagesTotal = pages.length,
| + | |
− | // index of current page
| + | |
− | current = 0,
| + | |
− | // menu button
| + | |
− | menuCtrl = document.querySelector('button.menu-button'),
| + | |
− | // the navigation wrapper
| + | |
− | nav = document.querySelector('.pages-nav'),
| + | |
− | // the menu nav items | + | |
− | navItems = [].slice.call(nav.querySelectorAll('.link--page')),
| + | |
− | // check if menu is open
| + | |
− | isMenuOpen = false;
| + | |
− | | + | |
− | function init() {
| + | |
− | buildStack();
| + | |
− | initEvents();
| + | |
− | }
| + | |
− | | + | |
− | function buildStack() {
| + | |
− | var stackPagesIdxs = getStackPagesIdxs();
| + | |
− | | + | |
− | // set z-index, opacity, initial transforms to pages and add class page--inactive to all except the current one
| + | |
− | for(var i = 0; i < pagesTotal; ++i) {
| + | |
− | var page = pages[i],
| + | |
− | posIdx = stackPagesIdxs.indexOf(i);
| + | |
− | | + | |
− | if( current !== i ) {
| + | |
− | classie.add(page, 'page--inactive');
| + | |
− | | + | |
− | if( posIdx !== -1 ) {
| + | |
− | // visible pages in the stack
| + | |
− | page.style.WebkitTransform = 'translate3d(0,100%,0)';
| + | |
− | page.style.transform = 'translate3d(0,100%,0)';
| + | |
− | }
| + | |
− | else {
| + | |
− | // invisible pages in the stack
| + | |
− | page.style.WebkitTransform = 'translate3d(0,75%,-300px)';
| + | |
− | page.style.transform = 'translate3d(0,75%,-300px)';
| + | |
− | }
| + | |
− | }
| + | |
− | else {
| + | |
− | classie.remove(page, 'page--inactive');
| + | |
− | }
| + | |
− | | + | |
− | page.style.zIndex = i < current ? parseInt(current - i) : parseInt(pagesTotal + current - i);
| + | |
− |
| + | |
− | if( posIdx !== -1 ) {
| + | |
− | page.style.opacity = parseFloat(1 - 0.1 * posIdx);
| + | |
− | }
| + | |
− | else {
| + | |
− | page.style.opacity = 0;
| + | |
− | }
| + | |
− | }
| + | |
− | }
| + | |
− | | + | |
− | // event binding
| + | |
− | function initEvents() {
| + | |
− | // menu button click
| + | |
− | menuCtrl.addEventListener('click', toggleMenu);
| + | |
− | | + | |
− | // navigation menu clicks
| + | |
− | navItems.forEach(function(item) {
| + | |
− | // which page to open?
| + | |
− | var pageid = item.getAttribute('href').slice(1);
| + | |
− | item.addEventListener('click', function(ev) {
| + | |
− | ev.preventDefault();
| + | |
− | openPage(pageid);
| + | |
− | });
| + | |
| }); | | }); |
− |
| |
− | // clicking on a page when the menu is open triggers the menu to close again and open the clicked page
| |
− | pages.forEach(function(page) {
| |
− | var pageid = page.getAttribute('id');
| |
− | page.addEventListener('click', function(ev) {
| |
− | if( isMenuOpen ) {
| |
− | ev.preventDefault();
| |
− | openPage(pageid);
| |
− | }
| |
− | });
| |
− | });
| |
− |
| |
− | // keyboard navigation events
| |
− | document.addEventListener( 'keydown', function( ev ) {
| |
− | if( !isMenuOpen ) return;
| |
− | var keyCode = ev.keyCode || ev.which;
| |
− | if( keyCode === 27 ) {
| |
− | closeMenu();
| |
− | }
| |
− | } );
| |
| } | | } |
| | | |
− | // toggle menu fn | + | //open/close primary navigation |
− | function toggleMenu() {
| + | $('.cd-primary-nav-trigger').on('click', function(){ |
− | if( isMenuOpen ) {
| + | $('.cd-menu-icon').toggleClass('is-clicked'); |
− | closeMenu();
| + | $('.cd-header').toggleClass('menu-is-open'); |
− | }
| + | |
− | else {
| + | |
− | openMenu();
| + | |
− | isMenuOpen = true;
| + | |
− | }
| + | |
− | }
| + | |
− | | + | |
− | // opens the menu
| + | |
− | function openMenu() { | + | |
− | // toggle the menu button
| + | |
− | classie.add(menuCtrl, 'menu-button--open')
| + | |
− | // stack gets the class "pages-stack--open" to add the transitions
| + | |
− | classie.add(stack, 'pages-stack--open');
| + | |
− | // reveal the menu
| + | |
− | classie.add(nav, 'pages-nav--open');
| + | |
− | | + | |
− | // now set the page transforms
| + | |
− | var stackPagesIdxs = getStackPagesIdxs();
| + | |
− | for(var i = 0, len = stackPagesIdxs.length; i < len; ++i) { | + | |
− | var page = pages[stackPagesIdxs[i]];
| + | |
− | page.style.WebkitTransform = 'translate3d(0, 75%, ' + parseInt(-1 * 200 - 50*i) + 'px)'; // -200px, -230px, -260px
| + | |
− | page.style.transform = 'translate3d(0, 75%, ' + parseInt(-1 * 200 - 50*i) + 'px)';
| + | |
− | } | + | |
− | }
| + | |
− | | + | |
− | // closes the menu
| + | |
− | function closeMenu() {
| + | |
− | // same as opening the current page again
| + | |
− | openPage();
| + | |
− | }
| + | |
− | | + | |
− | // opens a page
| + | |
− | function openPage(id) {
| + | |
− | var futurePage = id ? document.getElementById(id) : pages[current],
| + | |
− | futureCurrent = pages.indexOf(futurePage),
| + | |
− | stackPagesIdxs = getStackPagesIdxs(futureCurrent);
| + | |
− | | + | |
− | // set transforms for the new current page
| + | |
− | futurePage.style.WebkitTransform = 'translate3d(0, 0, 0)';
| + | |
− | futurePage.style.transform = 'translate3d(0, 0, 0)';
| + | |
− | futurePage.style.opacity = 1;
| + | |
− | | + | |
− | // set transforms for the other items in the stack
| + | |
− | for(var i = 0, len = stackPagesIdxs.length; i < len; ++i) {
| + | |
− | var page = pages[stackPagesIdxs[i]];
| + | |
− | page.style.WebkitTransform = 'translate3d(0,100%,0)';
| + | |
− | page.style.transform = 'translate3d(0,100%,0)';
| + | |
− | }
| + | |
− | | + | |
− | // set current
| + | |
− | if( id ) {
| + | |
− | current = futureCurrent;
| + | |
− | }
| + | |
| | | |
− | // close menu.. | + | //in firefox transitions break when parent overflow is changed, so we need to wait for the end of the trasition to give the body an overflow hidden |
− | classie.remove(menuCtrl, 'menu-button--open'); | + | if( $('.cd-primary-nav').hasClass('is-visible') ) { |
− | classie.remove(nav, 'pages-nav--open');
| + | $('.cd-primary-nav').removeClass('is-visible').one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend',function(){ |
− | onEndTransition(futurePage, function() {
| + | $('body').removeClass('overflow-hidden'); |
− | classie.remove(stack, 'pages-stack--open');
| + | }); |
− | // reorganize stack | + | } else { |
− | buildStack();
| + | $('.cd-primary-nav').addClass('is-visible').one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend',function(){ |
− | isMenuOpen = false;
| + | $('body').addClass('overflow-hidden'); |
− | }); | + | }); |
− | }
| + | |
− | | + | |
− | // gets the current stack pages indexes. If any of them is the excludePage then this one is not part of the returned array
| + | |
− | function getStackPagesIdxs(excludePageIdx) {
| + | |
− | var nextStackPageIdx = current + 1 < pagesTotal ? current + 1 : 0,
| + | |
− | nextStackPageIdx_2 = current + 2 < pagesTotal ? current + 2 : 1,
| + | |
− | idxs = [],
| + | |
− | | + | |
− | excludeIdx = excludePageIdx || -1;
| + | |
− | | + | |
− | if( excludePageIdx != current ) {
| + | |
− | idxs.push(current);
| + | |
| } | | } |
− | if( excludePageIdx != nextStackPageIdx ) {
| + | }); |
− | idxs.push(nextStackPageIdx);
| + | }); |
− | }
| + | |
− | if( excludePageIdx != nextStackPageIdx_2 ) {
| + | |
− | idxs.push(nextStackPageIdx_2);
| + | |
− | }
| + | |
− | | + | |
− | return idxs;
| + | |
− | } | + | |
− | | + | |
− | init();
| + | |
− | | + | |
− | })(window); | + | |
jQuery(document).ready(function($){
//if you change this breakpoint in the style.css file (or _layout.scss if you use SASS), don't forget to update this value as well
var MQL = 1170;
//primary navigation slide-in effect
if($(window).width() > MQL) {
var headerHeight = $('.cd-header').height();
$(window).on('scroll',
{
previousTop: 0
},
function () {
var currentTop = $(window).scrollTop();
//check if user is scrolling up
if (currentTop < this.previousTop ) {
//if scrolling up...
if (currentTop > 0 && $('.cd-header').hasClass('is-fixed')) {
$('.cd-header').addClass('is-visible');
} else {
$('.cd-header').removeClass('is-visible is-fixed');
}
} else {
//if scrolling down...
$('.cd-header').removeClass('is-visible');
if( currentTop > headerHeight && !$('.cd-header').hasClass('is-fixed')) $('.cd-header').addClass('is-fixed');
}
this.previousTop = currentTop;
});
}
//open/close primary navigation
$('.cd-primary-nav-trigger').on('click', function(){
$('.cd-menu-icon').toggleClass('is-clicked');
$('.cd-header').toggleClass('menu-is-open');
//in firefox transitions break when parent overflow is changed, so we need to wait for the end of the trasition to give the body an overflow hidden
if( $('.cd-primary-nav').hasClass('is-visible') ) {
$('.cd-primary-nav').removeClass('is-visible').one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend',function(){
$('body').removeClass('overflow-hidden');
});
} else {
$('.cd-primary-nav').addClass('is-visible').one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend',function(){
$('body').addClass('overflow-hidden');
});
}
});
});