| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546 | 
							- /*************************************************
 
-  *  Academic
 
-  *  https://github.com/gcushen/hugo-academic
 
-  *
 
-  *  Core JS functions and initialization.
 
-  **************************************************/
 
- (function($){
 
-   /* ---------------------------------------------------------------------------
 
-    * Responsive scrolling for URL hashes.
 
-    * --------------------------------------------------------------------------- */
 
-   // Dynamically get responsive navigation bar offset.
 
-   let $navbar = $('.navbar');
 
-   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._config.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.nav-link').on('click', function(event) {
 
-     // Store requested URL hash.
 
-     let hash = this.hash;
 
-     // If we are on a widget page and the navbar link is to a section on the same page.
 
-     if ( this.pathname === window.location.pathname && hash && $(hash).length && ($(".js-widget-page").length > 0)) {
 
-       // Prevent default click behavior.
 
-       event.preventDefault();
 
-       // 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 - navbar_offset
 
-       }, 800);
 
-     }
 
-   });
 
-   /* ---------------------------------------------------------------------------
 
-    * Smooth scrolling for Back To Top link.
 
-    * --------------------------------------------------------------------------- */
 
-   $('#back_to_top').on('click', function(event) {
 
-     event.preventDefault();
 
-     $('html, body').animate({
 
-       'scrollTop': 0
 
-     }, 800, function() {
 
-       window.location.hash = "";
 
-     });
 
-   });
 
-   /* ---------------------------------------------------------------------------
 
-    * Hide mobile collapsable menu on clicking a link.
 
-    * --------------------------------------------------------------------------- */
 
-   $(document).on('click', '.navbar-collapse.show', function(e) {
 
-     //get the <a> element that was clicked, even if the <span> element that is inside the <a> element is e.target
 
-     let targetElement = $(e.target).is('a') ? $(e.target) : $(e.target).parent();
 
-     if (targetElement.is('a') && targetElement.attr('class') != 'dropdown-toggle') {
 
-       $(this).collapse('hide');
 
-     }
 
-   });
 
-   /* ---------------------------------------------------------------------------
 
-    * Filter publications.
 
-    * --------------------------------------------------------------------------- */
 
-   // Active publication filters.
 
-   let pubFilters = {};
 
-   // Search term.
 
-   let searchRegex;
 
-   // Filter values (concatenated).
 
-   let filterValues;
 
-   // Publication container.
 
-   let $grid_pubs = $('#container-publications');
 
-   // Initialise Isotope.
 
-   $grid_pubs.isotope({
 
-     itemSelector: '.isotope-item',
 
-     percentPosition: true,
 
-     masonry: {
 
-       // Use Bootstrap compatible grid layout.
 
-       columnWidth: '.grid-sizer'
 
-     },
 
-     filter: function() {
 
-       let $this = $(this);
 
-       let searchResults = searchRegex ? $this.text().match( searchRegex ) : true;
 
-       let filterResults = filterValues ? $this.is( filterValues ) : true;
 
-       return searchResults && filterResults;
 
-     }
 
-   });
 
-   // Filter by search term.
 
-   let $quickSearch = $('.filter-search').keyup( debounce( function() {
 
-     searchRegex = new RegExp( $quickSearch.val(), 'gi' );
 
-     $grid_pubs.isotope();
 
-   }) );
 
-   // Debounce input to prevent spamming filter requests.
 
-   function debounce( fn, threshold ) {
 
-     let timeout;
 
-     threshold = threshold || 100;
 
-     return function debounced() {
 
-       clearTimeout( timeout );
 
-       let args = arguments;
 
-       let _this = this;
 
-       function delayed() {
 
-         fn.apply( _this, args );
 
-       }
 
-       timeout = setTimeout( delayed, threshold );
 
-     };
 
-   }
 
-   // Flatten object by concatenating values.
 
-   function concatValues( obj ) {
 
-     let value = '';
 
-     for ( let prop in obj ) {
 
-       value += obj[ prop ];
 
-     }
 
-     return value;
 
-   }
 
-   $('.pub-filters').on( 'change', function() {
 
-     let $this = $(this);
 
-     // Get group key.
 
-     let filterGroup = $this[0].getAttribute('data-filter-group');
 
-     // Set filter for group.
 
-     pubFilters[ filterGroup ] = this.value;
 
-     // Combine filters.
 
-     filterValues = concatValues( pubFilters );
 
-     // Activate filters.
 
-     $grid_pubs.isotope();
 
-     // If filtering by publication type, update the URL hash to enable direct linking to results.
 
-     if (filterGroup == "pubtype") {
 
-       // Set hash URL to current filter.
 
-       let url = $(this).val();
 
-       if (url.substr(0, 9) == '.pubtype-') {
 
-         window.location.hash = url.substr(9);
 
-       } else {
 
-         window.location.hash = '';
 
-       }
 
-     }
 
-   });
 
-   // Filter publications according to hash in URL.
 
-   function filter_publications() {
 
-     let urlHash = window.location.hash.replace('#','');
 
-     let filterValue = '*';
 
-     // Check if hash is numeric.
 
-     if (urlHash != '' && !isNaN(urlHash)) {
 
-       filterValue = '.pubtype-' + urlHash;
 
-     }
 
-     // Set filter.
 
-     let filterGroup = 'pubtype';
 
-     pubFilters[ filterGroup ] = filterValue;
 
-     filterValues = concatValues( pubFilters );
 
-     // Activate filters.
 
-     $grid_pubs.isotope();
 
-     // Set selected option.
 
-     $('.pubtype-select').val(filterValue);
 
-   }
 
-   /* ---------------------------------------------------------------------------
 
-   * Google Maps or OpenStreetMap via Leaflet.
 
-   * --------------------------------------------------------------------------- */
 
-   function initMap () {
 
-     if ($('#map').length) {
 
-       let map_provider = $('#map-provider').val();
 
-       let lat = $('#map-lat').val();
 
-       let lng = $('#map-lng').val();
 
-       let zoom = parseInt($('#map-zoom').val());
 
-       let address = $('#map-dir').val();
 
-       let api_key = $('#map-api-key').val();
 
-       if ( map_provider == 1 ) {
 
-         let map = new GMaps({
 
-           div: '#map',
 
-           lat: lat,
 
-           lng: lng,
 
-           zoom: zoom,
 
-           zoomControl: true,
 
-           zoomControlOpt: {
 
-             style: 'SMALL',
 
-             position: 'TOP_LEFT'
 
-           },
 
-           panControl: false,
 
-           streetViewControl: false,
 
-           mapTypeControl: false,
 
-           overviewMapControl: false,
 
-           scrollwheel: true,
 
-           draggable: true
 
-         });
 
-         map.addMarker({
 
-           lat: lat,
 
-           lng: lng,
 
-           click: function (e) {
 
-             let url = 'https://www.google.com/maps/place/' + encodeURIComponent(address) + '/@' + lat + ',' + lng +'/';
 
-             window.open(url, '_blank')
 
-           },
 
-           title: address
 
-         })
 
-       } else {
 
-           let map = new L.map('map').setView([lat, lng], zoom);
 
-           if ( map_provider == 3 && api_key.length ) {
 
-             L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
 
-               attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
 
-               maxZoom: 18,
 
-               id: 'mapbox.streets',
 
-               accessToken: api_key
 
-             }).addTo(map);
 
-           } else {
 
-             L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
 
-               maxZoom: 19,
 
-               attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
 
-             }).addTo(map);
 
-           }
 
-           let marker = L.marker([lat, lng]).addTo(map);
 
-           let url = lat + ',' + lng +'#map='+ zoom +'/'+ lat +'/'+ lng +'&layers=N';
 
-           marker.bindPopup(address + '<p><a href="https://www.openstreetmap.org/directions?engine=osrm_car&route='+ url +'">Routing via OpenStreetMap</a></p>');
 
-       }
 
-     }
 
-   }
 
-   /* ---------------------------------------------------------------------------
 
-    * GitHub API.
 
-    * --------------------------------------------------------------------------- */
 
-   function printLatestRelease(selector, repo) {
 
-     $.getJSON('https://api.github.com/repos/' + repo + '/tags').done(function (json) {
 
-       let release = json[0];
 
-       $(selector).append(release.name);
 
-     }).fail(function( jqxhr, textStatus, error ) {
 
-       let err = textStatus + ", " + error;
 
-       console.log( "Request Failed: " + err );
 
-     });
 
-   }
 
-   /* ---------------------------------------------------------------------------
 
-   * Toggle search dialog.
 
-   * --------------------------------------------------------------------------- */
 
-   function toggleSearchDialog() {
 
-     if ($('body').hasClass('searching')) {
 
-       $('[id=search-query]').blur();
 
-       $('body').removeClass('searching');
 
-     } else {
 
-       $('body').addClass('searching');
 
-       $('.search-results').css({opacity: 0, visibility: 'visible'}).animate({opacity: 1}, 200);
 
-       $('#search-query').focus();
 
-     }
 
-   }
 
-   /* ---------------------------------------------------------------------------
 
-   * Toggle day/night mode.
 
-   * --------------------------------------------------------------------------- */
 
-   function toggleDarkMode(codeHlEnabled, codeHlLight, codeHlDark, diagramEnabled) {
 
-     if ($('body').hasClass('dark')) {
 
-       $('body').css({opacity: 0, visibility: 'visible'}).animate({opacity: 1}, 500);
 
-       $('body').removeClass('dark');
 
-       if (codeHlEnabled) {
 
-         codeHlLight.disabled = false;
 
-         codeHlDark.disabled = true;
 
-       }
 
-       $('.js-dark-toggle i').removeClass('fa-sun').addClass('fa-moon');
 
-       localStorage.setItem('dark_mode', '0');
 
-       if (diagramEnabled) {
 
-         // TODO: Investigate Mermaid.js approach to re-render diagrams with new theme without reloading.
 
-         location.reload();
 
-       }
 
-     } else {
 
-       $('body').css({opacity: 0, visibility: 'visible'}).animate({opacity: 1}, 500);
 
-       $('body').addClass('dark');
 
-       if (codeHlEnabled) {
 
-         codeHlLight.disabled = true;
 
-         codeHlDark.disabled = false;
 
-       }
 
-       $('.js-dark-toggle i').removeClass('fa-moon').addClass('fa-sun');
 
-       localStorage.setItem('dark_mode', '1');
 
-       if (diagramEnabled) {
 
-         // TODO: Investigate Mermaid.js approach to re-render diagrams with new theme without reloading.
 
-         location.reload();
 
-       }
 
-     }
 
-   }
 
-   /* ---------------------------------------------------------------------------
 
-   * Normalize Bootstrap Carousel Slide Heights.
 
-   * --------------------------------------------------------------------------- */
 
-   function normalizeCarouselSlideHeights() {
 
-     $('.carousel').each(function(){
 
-       // Get carousel slides.
 
-       let items = $('.carousel-item', this);
 
-       // Reset all slide heights.
 
-       items.css('min-height', 0);
 
-       // Normalize all slide heights.
 
-       let maxHeight = Math.max.apply(null, items.map(function(){return $(this).outerHeight()}).get());
 
-       items.css('min-height', maxHeight + 'px');
 
-     })
 
-   }
 
-   /* ---------------------------------------------------------------------------
 
-    * On document ready.
 
-    * --------------------------------------------------------------------------- */
 
-   $(document).ready(function() {
 
-     // Set dark mode if user chose it.
 
-     let default_mode = 0;
 
-     if ($('body').hasClass('dark')) {
 
-       default_mode = 1;
 
-     }
 
-     let dark_mode = parseInt(localStorage.getItem('dark_mode') || default_mode);
 
-     // Is code highlighting enabled in site config?
 
-     const codeHlEnabled = $('link[title=hl-light]').length > 0;
 
-     const codeHlLight = $('link[title=hl-light]')[0];
 
-     const codeHlDark = $('link[title=hl-dark]')[0];
 
-     const diagramEnabled = $('script[title=mermaid]').length > 0;
 
-     if (dark_mode) {
 
-       $('body').addClass('dark');
 
-       if (codeHlEnabled) {
 
-         codeHlLight.disabled = true;
 
-         codeHlDark.disabled = false;
 
-       }
 
-       if (diagramEnabled) {
 
-         mermaid.initialize({ theme: 'dark' });
 
-       }
 
-       $('.js-dark-toggle i').removeClass('fa-moon').addClass('fa-sun');
 
-     } else {
 
-       $('body').removeClass('dark');
 
-       if (codeHlEnabled) {
 
-         codeHlLight.disabled = false;
 
-         codeHlDark.disabled = true;
 
-       }
 
-       if (diagramEnabled) {
 
-         mermaid.initialize({ theme: 'default' });
 
-       }
 
-       $('.js-dark-toggle i').removeClass('fa-sun').addClass('fa-moon');
 
-     }
 
-     // Toggle day/night mode.
 
-     $('.js-dark-toggle').click(function(e) {
 
-       e.preventDefault();
 
-       toggleDarkMode(codeHlEnabled, codeHlLight, codeHlDark, diagramEnabled);
 
-     });
 
-   });
 
-   /* ---------------------------------------------------------------------------
 
-    * On window loaded.
 
-    * --------------------------------------------------------------------------- */
 
-   $(window).on('load', function() {
 
-     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 (!$('.projects-container').length) {
 
-         // If URL contains a hash and there are no dynamically loaded images on the page,
 
-         // immediately scroll to target ID taking into account responsive offset.
 
-         // Otherwise, wait for `imagesLoaded()` to complete before scrolling to hash to prevent scrolling to wrong
 
-         // location.
 
-         scrollToAnchor();
 
-       }
 
-     }
 
-     // Initialize Scrollspy.
 
-     let $body = $('body');
 
-     $body.scrollspy({offset: navbar_offset });
 
-     // Call `fixScrollspy` when window is resized.
 
-     let resizeTimer;
 
-     $(window).resize(function() {
 
-       clearTimeout(resizeTimer);
 
-       resizeTimer = setTimeout(fixScrollspy, 200);
 
-     });
 
-     // Filter projects.
 
-     $('.projects-container').each(function(index, container) {
 
-       let $container = $(container);
 
-       let $section = $container.closest('section');
 
-       let layout;
 
-       if ($section.find('.isotope').hasClass('js-layout-row')) {
 
-         layout = 'fitRows';
 
-       } else {
 
-         layout = 'masonry';
 
-       }
 
-       $container.imagesLoaded(function() {
 
-         // Initialize Isotope after all images have loaded.
 
-         $container.isotope({
 
-           itemSelector: '.isotope-item',
 
-           layoutMode: layout,
 
-           masonry: {
 
-             gutter: 20
 
-           },
 
-           filter: $section.find('.default-project-filter').text()
 
-         });
 
-         // Filter items when filter link is clicked.
 
-         $section.find('.project-filters a').click(function() {
 
-           let selector = $(this).attr('data-filter');
 
-           $container.isotope({filter: selector});
 
-           $(this).removeClass('active').addClass('active').siblings().removeClass('active all');
 
-           return false;
 
-         });
 
-         // If window hash is set, scroll to hash.
 
-         // Placing this within `imagesLoaded` prevents scrolling to the wrong location due to dynamic image loading
 
-         // affecting page layout and position of the target anchor ID.
 
-         // Note: If there are multiple project widgets on a page, ideally only perform this once after images
 
-         // from *all* project widgets have finished loading.
 
-         if (window.location.hash) {
 
-           scrollToAnchor();
 
-         }
 
-       });
 
-     });
 
-     // 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);
 
-     }
 
-     // Load citation modal on 'Cite' click.
 
-     $('.js-cite-modal').click(function(e) {
 
-       e.preventDefault();
 
-       let filename = $(this).attr('data-filename');
 
-       let modal = $('#modal');
 
-       modal.find('.modal-body code').load( filename , function( response, status, xhr ) {
 
-         if ( status == 'error' ) {
 
-           let msg = "Error: ";
 
-           $('#modal-error').html( msg + xhr.status + " " + xhr.statusText );
 
-         } else {
 
-           $('.js-download-cite').attr('href', filename);
 
-         }
 
-       });
 
-       modal.modal('show');
 
-     });
 
-     // Copy citation text on 'Copy' click.
 
-     $('.js-copy-cite').click(function(e) {
 
-       e.preventDefault();
 
-       // Get selection.
 
-       let range = document.createRange();
 
-       let code_node = document.querySelector('#modal .modal-body');
 
-       range.selectNode(code_node);
 
-       window.getSelection().addRange(range);
 
-       try {
 
-         // Execute the copy command.
 
-         document.execCommand('copy');
 
-       } catch(e) {
 
-         console.log('Error: citation copy failed.');
 
-       }
 
-       // Remove selection.
 
-       window.getSelection().removeRange(range);
 
-     });
 
-     // Initialise Google Maps if necessary.
 
-     initMap();
 
-     // Fix Hugo's inbuilt Table of Contents.
 
-     $('#TableOfContents > ul > li > ul').unwrap().unwrap();
 
-     // Print latest Academic version if necessary.
 
-     if ($('#academic-release').length > 0)
 
-       printLatestRelease('#academic-release', $('#academic-release').data('repo'));
 
-     // On search icon click toggle search dialog.
 
-     $('.js-search').click(function(e) {
 
-       e.preventDefault();
 
-       toggleSearchDialog();
 
-     });
 
-     $(document).on('keydown', function(e){
 
-       if (e.which == 27) {
 
-         // `Esc` key pressed.
 
-         if ($('body').hasClass('searching')) {
 
-           toggleSearchDialog();
 
-         }
 
-       } else if (e.which == 191 && e.shiftKey == false && !$('input,textarea').is(':focus')) {
 
-         // `/` key pressed outside of text input.
 
-         e.preventDefault();
 
-         toggleSearchDialog();
 
-       }
 
-     });
 
-   });
 
-   // Normalize Bootstrap carousel slide heights.
 
-   $(window).on('load resize orientationchange', normalizeCarouselSlideHeights);
 
- })(jQuery);
 
 
  |