|
### |
|
Mobile Navigation |
|
|
|
Depends on: |
|
- vendor/underscore/underscore-min.js |
|
- vendor/jquery/jquery.min.js |
|
- vendor/hammerjs/hammer.min.js |
|
- vendor/jquery-hammerjs/jquery.hammer.min.js |
|
- vendor/Snap.svg/dist/snap.svg-min.js |
|
- js/jquery.innovate.js |
|
### |
|
|
|
$(document).ready -> |
|
$container = $('#mobile-navigation') |
|
$mobileNav = $container.find 'nav' |
|
$arrow = $container.children '.arrow' |
|
$mobileNavList = $mobileNav.find 'ul' |
|
$navItems = $('.nav li') |
|
$burger = $('a.hamburger') |
|
transitionEnd = 'transitionend webkitTransitionEnd' |
|
scrollingEnabled = true |
|
navAnimating = false |
|
navVisible = false |
|
arrowHeight = 10 |
|
disableBodyScroll = -> |
|
document.ontouchmove = (e) -> e.preventDefault() |
|
scrollingEnabled = false |
|
enableBodyScroll = -> |
|
document.ontouchmove = $.noop |
|
scrollingEnabled = true |
|
|
|
# Build mobile navigation menu as a hierarchical list, using the non-hierarchical main navigation |
|
# to avoid loading duplicate content. |
|
$navItems.each -> |
|
bindVal = $(this).data 'bind' |
|
$navItem = $('<li/>') |
|
$navItem.append $(this).children('a').clone() |
|
|
|
if bindVal |
|
$subnavItems = $("ul[data-bind='#{bindVal}']").clone().find('li').removeClass 'megamenu' |
|
|
|
if $subnavItems.size() |
|
$subnavList = $('<ul/>', 'class': 'mobile-subnav') |
|
backLink = """ |
|
<li> |
|
<a href="" class="back"> |
|
<span class="glyphicon glyphicon-chevron-left"></span> |
|
Back |
|
</a> |
|
</li> |
|
""" |
|
$backLink = $(backLink) |
|
$subnavList.prepend $backLink |
|
$subnavList.append($subnavItems).appendTo $navItem |
|
$navItem.children('a').append '<span class="arrow glyphicon glyphicon-chevron-right"></span>' |
|
|
|
$navItem.appendTo $mobileNavList |
|
|
|
# Bind hamburger tap to open mobile nav menu |
|
if $burger.size() and $mobileNav.size() |
|
$mobileNav.matchYOffset($burger, $burger.outerHeight() + arrowHeight).stretchHeight() |
|
|
|
$burger.hammer().on 'tap click', (evt) -> |
|
return false if evt.type is 'click' |
|
navAnimating = true |
|
$mobileNav.matchYOffset $burger, $burger.outerHeight() + arrowHeight |
|
$mobileNav.toggleClass 'open' |
|
$arrow.toggleClass 'visible' |
|
navVisible = $mobileNav.hasClass 'open' |
|
|
|
$mobileNav.on transitionEnd, (evt) -> |
|
navAnimating = false |
|
$mobileNav.off transitionEnd |
|
if navVisible then disableBodyScroll() else enableBodyScroll() |
|
|
|
false |
|
|
|
# If window is shorter than nav list, handle vertical scrolling of nav |
|
$mobileNav.hammer().on 'drag', (evt) -> |
|
origHeight = $burger.offset().top + $burger.outerHeight() + arrowHeight |
|
navHeight = $mobileNav.height() |
|
winHeight = window.innerHeight |
|
return if navHeight <= winHeight or navAnimating |
|
topPos = parseInt($mobileNav.css('top'), 10) or 0 |
|
|
|
if evt.gesture? |
|
deltaY = evt.gesture.deltaY + topPos / 4 |
|
return if deltaY >= origHeight |
|
$mobileNav.css 'top', "#{deltaY}px" |
|
|
|
# Top level mobile nav link click handler |
|
$mobileNav.children('ul').children('li').children('a').preventClick().hammer().on 'tap', (evt) -> |
|
$mobileNav.children('ul').addClass 'child-open' |
|
$(this).next('ul').addClass 'visible open' |
|
false |
|
|
|
# Mobile subnav back button handler |
|
$mobileNav.find('a.back').preventClick().hammer().on 'tap', -> |
|
$mobileNav.children('ul').removeClass 'child-open' |
|
$(this).closest('ul').removeClass('open').on transitionEnd, -> |
|
$(this).removeClass 'visible' |
|
$(this).off transitionEnd |
|
false |
|
|
|
resizeHandler = -> |
|
$burger = $('a.hamburger') |
|
$mobileNav = $('#mobile-navigation nav') |
|
arrowHeight = 10 |
|
|
|
if $burger.size() and $mobileNav.size() |
|
$mobileNav.matchYOffset($burger, $burger.outerHeight() + arrowHeight).stretchHeight() |
|
|
|
$(window).resize _.throttle(resizeHandler, 100) |