/**
* main.js * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2015, Codrops * http://www.codrops.com */
- (function(window) {
'use strict';
var support = { transitions: Modernizr.csstransitions }, // transition end event name transEndEventNames = { 'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'transitionend', 'OTransition': 'oTransitionEnd', 'msTransition': 'MSTransitionEnd', 'transition': 'transitionend' }, transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ], onEndTransition = function( el, callback ) { var onEndCallbackFn = function( ev ) { if( support.transitions ) { if( ev.target != this ) return; this.removeEventListener( transEndEventName, onEndCallbackFn ); } if( callback && typeof callback === 'function' ) { callback.call(this); } }; if( support.transitions ) { el.addEventListener( transEndEventName, onEndCallbackFn ); } else { onEndCallbackFn(); } }, // the pages wrapper stack = document.querySelector('.pages-stack'), // 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 function toggleMenu() { if( isMenuOpen ) { closeMenu(); } 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.. classie.remove(menuCtrl, 'menu-button--open'); classie.remove(nav, 'pages-nav--open'); onEndTransition(futurePage, function() { classie.remove(stack, 'pages-stack--open'); // reorganize stack buildStack(); isMenuOpen = false; }); }
// 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);