diff --git a/static/css/hugo-academic.css b/static/css/hugo-academic.css index 1a381051..96f2fbf3 100644 --- a/static/css/hugo-academic.css +++ b/static/css/hugo-academic.css @@ -785,15 +785,6 @@ footer a#back_to_top i { min-height: 70px !important; } -/* Prevent navbar hiding initial content when jumping to in-page anchor. */ -*[id]:not([id^="fn"]):before { - display: block; - content: " "; - margin-top: -70px; - height: 70px; - visibility: hidden; -} - .navbar-default { background: #fff; box-shadow: 0 0.125rem 0.25rem 0 rgba(0,0,0,.11) @@ -860,12 +851,6 @@ nav#navbar-main li { min-height: 50px !important; } - /* Prevent navbar hiding initial content when jumping to in-page anchor. */ - *[id]:not([id^="fn"]):before { - margin-top: -50px; - height: 50px; - } - .navbar-brand, .navbar-nav li a { height: inherit; diff --git a/static/js/hugo-academic.js b/static/js/hugo-academic.js index 2c580278..b8a7635a 100644 --- a/static/js/hugo-academic.js +++ b/static/js/hugo-academic.js @@ -1,38 +1,73 @@ /************************************************* - * Hugo Academic: an academic theme for Hugo. + * Academic: the personal website framework for Hugo. * https://github.com/gcushen/hugo-academic **************************************************/ (function($){ + /* --------------------------------------------------------------------------- + * Responsive scrolling for URL hashes. + * --------------------------------------------------------------------------- */ + + // Dynamically get responsive navigation bar offset. + let $navbar = $('.navbar-header'); + let navbar_offset = $navbar.innerHeight(); + + /** + * Responsive hash scrolling. + * Check for a URL hash as an anchor. + * If it exists on current page, scroll to it responsively. + * If `target` argument omitted (e.g. after event), assume it's the window's hash. + */ + function scrollToAnchor(target) { + // If `target` is undefined or HashChangeEvent object, set it to window's hash. + target = (typeof target === 'undefined' || typeof target === 'object') ? window.location.hash : target; + // Escape colons from IDs, such as those found in Markdown footnote links. + target = target.replace(/:/g, '\\:'); + + // If target element exists, scroll to it taking into account fixed navigation bar offset. + if($(target).length) { + $('body').addClass('scrolling'); + $('html, body').animate({ + scrollTop: $(target).offset().top - navbar_offset + }, 600, function () { + $('body').removeClass('scrolling'); + }); + } + } + + // Make Scrollspy responsive. + function fixScrollspy() { + let $body = $('body'); + let data = $body.data('bs.scrollspy'); + if (data) { + data.options.offset = navbar_offset; + $body.data('bs.scrollspy', data); + $body.scrollspy('refresh'); + } + } + + // Check for hash change event and fix responsive offset for hash links (e.g. Markdown footnotes). + window.addEventListener("hashchange", scrollToAnchor); + /* --------------------------------------------------------------------------- * Add smooth scrolling to all links inside the main navbar. * --------------------------------------------------------------------------- */ - $('#navbar-main li.nav-item a').on('click', function(event){ - + $('#navbar-main li.nav-item a').on('click', function(event) { // Store requested URL hash. - var hash = this.hash; + let hash = this.hash; // If we are on the homepage and the navigation bar link is to a homepage section. - if( hash && $(hash).length && ($("#homepage").length > 0)){ - // Prevent default click behavior + if ( hash && $(hash).length && ($("#homepage").length > 0)) { + // Prevent default click behavior. event.preventDefault(); - var navbarHeight = $('.navbar-header').innerHeight(); - // Use jQuery's animate() method for smooth page scrolling. // The numerical parameter specifies the time (ms) taken to scroll to the specified hash. $('html, body').animate({ - scrollTop: $(hash).offset().top - navbarHeight - }, 800, function () { - // Add hash (#) to URL once finished scrolling to hash position - if (hash == "#top"){ - window.location.hash = "" - }else { - window.location.hash = hash; - } - }); + scrollTop: $(hash).offset().top - navbar_offset + }, 800); } }); @@ -40,51 +75,21 @@ * Smooth scrolling for Back To Top link. * --------------------------------------------------------------------------- */ - $('#back_to_top').on('click', function(event){ + $('#back_to_top').on('click', function(event) { event.preventDefault(); - $('html, body').animate({ 'scrollTop': 0 - }, 800, function(){ - window.location.hash = "" + }, 800, function() { + window.location.hash = ""; }); }); - /* --------------------------------------------------------------------------- - * Smooth scrolling for mouse wheel. - * --------------------------------------------------------------------------- */ - - function smoothScroll(scrollTime, scrollDistance){ - - if (navigator.userAgent.indexOf('Mac') != -1 || navigator.userAgent.indexOf('Firefox') > -1 || jQuery('body').hasClass('is-horizontal')){ - return; - } - - jQuery(window).on("mousewheel DOMMouseScroll", function(event){ - - event.preventDefault(); - - var delta = event.originalEvent.wheelDelta/120 || -event.originalEvent.detail/3; - var scrollTop = jQuery(window).scrollTop(); - var finalScroll = scrollTop - parseInt(delta*scrollDistance); - - TweenMax.to(jQuery(window), scrollTime, { - scrollTo : { y: finalScroll, autoKill:true }, - ease: Expo.easeOut, - autoKill: true, - overwrite: 5 - }); - - }); - - } - /* --------------------------------------------------------------------------- * Hide mobile collapsable menu on clicking a link. * --------------------------------------------------------------------------- */ - $(document).on('click','.navbar-collapse.in',function(e){ - if( $(e.target).is('a') && $(e.target).attr('class') != 'dropdown-toggle' ){ + $(document).on('click', '.navbar-collapse.in', function(e) { + if ( $(e.target).is('a') && $(e.target).attr('class') != 'dropdown-toggle' ) { $(this).collapse('hide'); } }); @@ -93,7 +98,7 @@ * Filter projects. * --------------------------------------------------------------------------- */ - var $grid_projects = $('#container-projects'); + let $grid_projects = $('#container-projects'); $grid_projects.imagesLoaded(function () { // Initialize Isotope after all images have loaded. $grid_projects.isotope({ @@ -103,18 +108,18 @@ // Filter items when filter link is clicked. $('#filters a').click(function () { - var selector = $(this).attr('data-filter'); + let selector = $(this).attr('data-filter'); $grid_projects.isotope({filter: selector}); - $(this).removeClass('active').addClass('active').siblings().removeClass('active all'); - return false; - }); + $(this).removeClass('active').addClass('active').siblings().removeClass('active all'); + return false; + }); }); /* --------------------------------------------------------------------------- * Filter publications. * --------------------------------------------------------------------------- */ - var $grid_pubs = $('#container-publications'); + let $grid_pubs = $('#container-publications'); $grid_pubs.isotope({ itemSelector: '.isotope-item', percentPosition: true, @@ -125,14 +130,14 @@ }); // Bind publication filter on dropdown change. - $('.pub-filters-select').on( 'change', function() { + $('.pub-filters-select').on('change', function() { // Get filter value from option value. - var filterValue = this.value; + let filterValue = this.value; // Apply filter to Isotope. $grid_pubs.isotope({ filter: filterValue }); // Set hash URL to current filter. - var url = $(this).val(); + let url = $(this).val(); if (url.substr(0, 9) == '.pubtype-') { window.location.hash = url.substr(9); } else { @@ -142,8 +147,8 @@ // Filter publications according to hash in URL. function filter_publications() { - var urlHash = window.location.hash.replace('#',''); - var filterValue = '*'; + let urlHash = window.location.hash.replace('#',''); + let filterValue = '*'; // Check if hash is numeric. if (urlHash != '' && !isNaN(urlHash)) { @@ -158,48 +163,36 @@ * On window load. * --------------------------------------------------------------------------- */ - $(window).load(function(){ + $(window).on('load', function() { - // When accessing publication index, enable filtering. - if ($('.pub-filters-select')) { - filter_publications(); - - // Useful for changing hash manually (e.g. in development): - // window.addEventListener('hashchange', filter_publications, false); - } - - // Enable smooth scrolling with mouse wheel - smoothScroll(1.3, 220); - - // When accessing homepage from another page and `#top` hash is set, show top of page (no hash). - if (window.location.hash == "#top") { - window.location.hash = "" - } - - // Initialize Scrollspy. - var $body = $('body'); - var $navbar = $('.navbar-header'); - var navbar_offset = $navbar.innerHeight() + 1; - $body.scrollspy({offset: navbar_offset }); - - // Make Scrollspy responsive. - function fixScrollspy() { - var data = $body.data('bs.scrollspy'); - if (data) { - navbar_offset = $navbar.innerHeight() + 1; - data.options.offset = navbar_offset; - $body.data('bs.scrollspy', data); - $body.scrollspy('refresh'); + if (window.location.hash) { + // When accessing homepage from another page and `#top` hash is set, show top of page (no hash). + if (window.location.hash == "#top") { + window.location.hash = "" + } else { + // If URL contains a hash, scroll to target ID taking into account responsive offset. + scrollToAnchor(); } } + // Initialize Scrollspy. + let $body = $('body'); + $body.scrollspy({offset: navbar_offset }); + // Call `fixScrollspy` when window is resized. - var resizeTimer; + let resizeTimer; $(window).resize(function() { clearTimeout(resizeTimer); resizeTimer = setTimeout(fixScrollspy, 200); }); + // Enable publication filter for publication index page. + if ($('.pub-filters-select')) { + filter_publications(); + // Useful for changing hash manually (e.g. in development): + // window.addEventListener('hashchange', filter_publications, false); + } + }); })(jQuery);