diff --git a/themes/academic/assets/js/academic-search.js b/themes/academic/assets/js/academic-search.js index 1a22753..0020be2 100644 --- a/themes/academic/assets/js/academic-search.js +++ b/themes/academic/assets/js/academic-search.js @@ -50,11 +50,11 @@ function updateURL(url) { // Pre-process new search query. function initSearch(force, fuse) { - let query = $("#search-query").val(); + let query = document.querySelector("#search-query").value; // If query deleted, clear results. - if ( query.length < 1) { - $('#search-hits').empty(); + if (query.length < 1) { + document.querySelector('#search-hits').innerHTML = ""; } // Check for timer event (enter key not pressed) and query less than minimum length required. @@ -62,7 +62,7 @@ function initSearch(force, fuse) { return; // Do search. - $('#search-hits').empty(); + document.querySelector('#search-hits').innerHTML = ""; searchAcademic(query, fuse); let newURL = window.location.protocol + "//" + window.location.host + window.location.pathname + '?q=' + encodeURIComponent(query) + window.location.hash; updateURL(newURL); @@ -74,16 +74,17 @@ function searchAcademic(query, fuse) { // console.log({"results": results}); if (results.length > 0) { - $('#search-hits').append('
wrapper.
- $(mermaids[i]).replaceWith(function () {
- // Convert block to and add `mermaid` class so that Mermaid will parse it.
- return $("").append($(this).contents()).addClass('mermaid');
- });
- }
- }
-
- /* ---------------------------------------------------------------------------
- * On document ready.
- * --------------------------------------------------------------------------- */
-
- $(document).ready(function () {
- fixHugoOutput();
- fixMermaid();
-
- // Initialise code highlighting if enabled for this page.
- // Note: this block should be processed after the Mermaid code-->div conversion.
- if (code_highlighting) {
- hljs.initHighlighting();
- }
-
- // Initialize theme variation.
- initThemeVariation();
-
- // Change theme mode.
- $('.js-set-theme-light').click(function (e) {
- e.preventDefault();
- changeThemeModeClick(2);
- });
- $('.js-set-theme-dark').click(function (e) {
- e.preventDefault();
- changeThemeModeClick(0);
- });
- $('.js-set-theme-auto').click(function (e) {
- e.preventDefault();
- changeThemeModeClick(1);
- });
-
- // Live update of day/night mode on system preferences update (no refresh required).
- // Note: since we listen only for *dark* events, we won't detect other scheme changes such as light to no-preference.
- const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
- darkModeMediaQuery.addListener((e) => {
- if (!canChangeTheme()) {
- // Changing theme variation is not allowed by admin.
- return;
- }
- const darkModeOn = e.matches;
- console.log(`OS dark mode preference changed to ${darkModeOn ? '🌒 on' : '☀️ off'}.`);
- let currentThemeVariation = parseInt(localStorage.getItem('dark_mode') || 2);
- let isDarkTheme;
- if (currentThemeVariation === 2) {
- if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
- // The visitor prefers dark themes.
- isDarkTheme = 1;
- } else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
- // The visitor prefers light themes.
- isDarkTheme = 0;
- } else {
- // The visitor does not have a day or night preference, so use the theme's default setting.
- isDarkTheme = isSiteThemeDark;
- }
- renderThemeVariation(isDarkTheme);
- }
- });
+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);
});
+}
- /* ---------------------------------------------------------------------------
- * On window loaded.
- * --------------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------------
+* Toggle search dialog.
+* --------------------------------------------------------------------------- */
- $(window).on('load', function () {
- // 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';
+function toggleSearchDialog() {
+ if ($('body').hasClass('searching')) {
+ // Clear search query and hide search modal.
+ $('[id=search-query]').blur();
+ $('body').removeClass('searching compensate-for-scrollbar');
+
+ // Remove search query params from URL as user has finished searching.
+ removeQueryParamsFromUrl();
+
+ // Prevent fixed positioned elements (e.g. navbar) moving due to scrollbars.
+ $('#fancybox-style-noscroll').remove();
+ } else {
+ // Prevent fixed positioned elements (e.g. navbar) moving due to scrollbars.
+ if (!$('#fancybox-style-noscroll').length && document.body.scrollHeight > window.innerHeight) {
+ $('head').append(
+ ''
+ );
+ $('body').addClass('compensate-for-scrollbar');
+ }
+
+ // Show search modal.
+ $('body').addClass('searching');
+ $('.search-results').css({opacity: 0, visibility: 'visible'}).animate({opacity: 1}, 200);
+ $('#search-query').focus();
+ }
+}
+
+/* ---------------------------------------------------------------------------
+* Change Theme Mode (0: Day, 1: Night, 2: Auto).
+* --------------------------------------------------------------------------- */
+
+function canChangeTheme() {
+ // If the theme changer component is present, then user is allowed to change the theme variation.
+ return $('.js-theme-selector').length;
+}
+
+function getThemeMode() {
+ return parseInt(localStorage.getItem('dark_mode') || 2);
+}
+
+function changeThemeModeClick(newMode) {
+ console.info('Request to set theme.');
+ if (!canChangeTheme()) {
+ console.info('Cannot set theme - admin disabled theme selector.');
+ return;
+ }
+ let isDarkTheme;
+ switch (newMode) {
+ case 0:
+ localStorage.setItem('dark_mode', '1');
+ isDarkTheme = 1;
+ console.info('User changed theme variation to Dark.');
+ showActiveTheme(0);
+ break;
+ case 1:
+ localStorage.setItem('dark_mode', '2');
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ // The visitor prefers dark themes and switching to the dark variation is allowed by admin.
+ isDarkTheme = 1;
+ } else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
+ // The visitor prefers light themes and switching to the dark variation is allowed by admin.
+ isDarkTheme = 0;
} else {
- layout = 'masonry';
+ isDarkTheme = isSiteThemeDark; // Use the site's default theme variation based on `light` in the theme file.
}
+ console.info('User changed theme variation to Auto.');
+ showActiveTheme(1);
+ break;
+ default:
+ localStorage.setItem('dark_mode', '0');
+ isDarkTheme = 0;
+ console.info('User changed theme variation to Light.');
+ showActiveTheme(2);
+ break;
+ }
+ renderThemeVariation(isDarkTheme);
+}
- $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()
- });
+function showActiveTheme(mode){
+ switch (mode) {
+ case 0:
+ // Dark.
+ $('.js-set-theme-light').removeClass('dropdown-item-active');
+ $('.js-set-theme-dark').addClass('dropdown-item-active');
+ $('.js-set-theme-auto').removeClass('dropdown-item-active');
+ break;
+ case 1:
+ // Auto.
+ $('.js-set-theme-light').removeClass('dropdown-item-active');
+ $('.js-set-theme-dark').removeClass('dropdown-item-active');
+ $('.js-set-theme-auto').addClass('dropdown-item-active');
+ break;
+ default:
+ // Light.
+ $('.js-set-theme-light').addClass('dropdown-item-active');
+ $('.js-set-theme-dark').removeClass('dropdown-item-active');
+ $('.js-set-theme-auto').removeClass('dropdown-item-active');
+ break;
+ }
+}
- // 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;
- });
+function getThemeVariation() {
+ if (!canChangeTheme()) {
+ return isSiteThemeDark; // Use the site's default theme variation based on `light` in the theme file.
+ }
+ let currentThemeMode = getThemeMode();
+ let isDarkTheme;
+ switch (currentThemeMode) {
+ case 0:
+ isDarkTheme = 0;
+ break;
+ case 1:
+ isDarkTheme = 1;
+ break;
+ default:
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ // The visitor prefers dark themes and switching to the dark variation is allowed by admin.
+ isDarkTheme = 1;
+ } else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
+ // The visitor prefers light themes and switching to the dark variation is allowed by admin.
+ isDarkTheme = 0;
+ } else {
+ isDarkTheme = isSiteThemeDark; // Use the site's default theme variation based on `light` in the theme file.
+ }
+ break;
+ }
+ return isDarkTheme;
+}
- // 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();
- }
- });
- });
+/**
+ * Render theme variation (day or night).
+ *
+ * @param {int} isDarkTheme - TODO: convert to boolean.
+ * @param {boolean} init
+ * @returns {undefined}
+ */
+function renderThemeVariation(isDarkTheme, init = false) {
+ // 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;
- // 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);
+ // Check if re-render required.
+ if (!init) {
+ // If request to render light when light variation already rendered, return.
+ // If request to render dark when dark variation already rendered, return.
+ if ((isDarkTheme === 0 && !$('body').hasClass('dark')) || (isDarkTheme === 1 && $('body').hasClass('dark'))) {
+ return;
}
+ }
- // Scroll to top of page.
- $('.back-to-top').click(function (event) {
- event.preventDefault();
- $('html, body').animate({
- 'scrollTop': 0
- }, 800, function () {
- window.location.hash = "";
- });
- });
-
- // 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.');
+ if (isDarkTheme === 0) {
+ if (!init) {
+ // Only fade in the page when changing the theme variation.
+ $('body').css({opacity: 0, visibility: 'visible'}).animate({opacity: 1}, 500);
+ }
+ $('body').removeClass('dark');
+ if (codeHlEnabled) {
+ codeHlLight.disabled = false;
+ codeHlDark.disabled = true;
+ }
+ if (diagramEnabled) {
+ if (init) {
+ mermaid.initialize({theme: 'default', securityLevel: 'loose'});
+ } else {
+ // Have to reload to re-initialise Mermaid with the new theme and re-parse the Mermaid code blocks.
+ location.reload();
}
- // Remove selection.
- window.getSelection().removeRange(range);
- });
-
- // Initialise Google Maps if necessary.
- initMap();
-
- // Print latest version of GitHub projects.
- let githubReleaseSelector = '.js-github-release';
- if ($(githubReleaseSelector).length > 0)
- printLatestRelease(githubReleaseSelector, $(githubReleaseSelector).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();
+ }
+ } else if (isDarkTheme === 1) {
+ if (!init) {
+ // Only fade in the page when changing the theme variation.
+ $('body').css({opacity: 0, visibility: 'visible'}).animate({opacity: 1}, 500);
+ }
+ $('body').addClass('dark');
+ if (codeHlEnabled) {
+ codeHlLight.disabled = true;
+ codeHlDark.disabled = false;
+ }
+ if (diagramEnabled) {
+ if (init) {
+ mermaid.initialize({theme: 'dark', securityLevel: 'loose'});
+ } else {
+ // Have to reload to re-initialise Mermaid with the new theme and re-parse the Mermaid code blocks.
+ location.reload();
}
- });
+ }
+ }
+}
+function initThemeVariation() {
+ // If theme changer component present, set its icon according to the theme mode (day, night, or auto).
+ if (canChangeTheme) {
+ let themeMode = getThemeMode();
+ switch (themeMode) {
+ case 0:
+ showActiveTheme(2);
+ console.info('Initialize theme variation to Light.');
+ break;
+ case 1:
+ showActiveTheme(0);
+ console.info('Initialize theme variation to Dark.');
+ break;
+ default:
+ showActiveTheme(1);
+ console.info('Initialize theme variation to Auto.');
+ break;
+ }
+ }
+ // Render the day or night theme.
+ let isDarkTheme = getThemeVariation();
+ renderThemeVariation(isDarkTheme, true);
+}
+
+/* ---------------------------------------------------------------------------
+* 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');
+ })
+}
+
+/* ---------------------------------------------------------------------------
+* Fix Hugo's Goldmark output and Mermaid code blocks.
+* --------------------------------------------------------------------------- */
+
+/**
+ * Fix Hugo's Goldmark output.
+ */
+function fixHugoOutput() {
+ // Fix Goldmark table of contents.
+ // - Must be performed prior to initializing ScrollSpy.
+ $('#TableOfContents').addClass('nav flex-column');
+ $('#TableOfContents li').addClass('nav-item');
+ $('#TableOfContents li a').addClass('nav-link');
+
+ // Fix Goldmark task lists (remove bullet points).
+ $("input[type='checkbox'][disabled]").parents('ul').addClass('task-list');
+}
+
+/**
+ * Fix Mermaid.js clash with Highlight.js.
+ * Refactor Mermaid code blocks as divs to prevent Highlight parsing them and enable Mermaid to parse them.
+ */
+function fixMermaid() {
+ let mermaids = [];
+ [].push.apply(mermaids, document.getElementsByClassName('language-mermaid'));
+ for (let i = 0; i < mermaids.length; i++) {
+ $(mermaids[i]).unwrap('pre'); // Remove wrapper.
+ $(mermaids[i]).replaceWith(function () {
+ // Convert block to and add `mermaid` class so that Mermaid will parse it.
+ return $("").append($(this).contents()).addClass('mermaid');
+ });
+ }
+}
+
+/* ---------------------------------------------------------------------------
+ * On document ready.
+ * --------------------------------------------------------------------------- */
+
+$(document).ready(function () {
+ fixHugoOutput();
+ fixMermaid();
+
+ // Initialise code highlighting if enabled for this page.
+ // Note: this block should be processed after the Mermaid code-->div conversion.
+ if (code_highlighting) {
+ hljs.initHighlighting();
+ }
+
+ // Initialize theme variation.
+ initThemeVariation();
+
+ // Change theme mode.
+ $('.js-set-theme-light').click(function (e) {
+ e.preventDefault();
+ changeThemeModeClick(2);
+ });
+ $('.js-set-theme-dark').click(function (e) {
+ e.preventDefault();
+ changeThemeModeClick(0);
+ });
+ $('.js-set-theme-auto').click(function (e) {
+ e.preventDefault();
+ changeThemeModeClick(1);
});
- // Normalize Bootstrap carousel slide heights.
- $(window).on('load resize orientationchange', normalizeCarouselSlideHeights);
+ // Live update of day/night mode on system preferences update (no refresh required).
+ // Note: since we listen only for *dark* events, we won't detect other scheme changes such as light to no-preference.
+ const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
+ darkModeMediaQuery.addListener((e) => {
+ if (!canChangeTheme()) {
+ // Changing theme variation is not allowed by admin.
+ return;
+ }
+ const darkModeOn = e.matches;
+ console.log(`OS dark mode preference changed to ${darkModeOn ? '🌒 on' : '☀️ off'}.`);
+ let currentThemeVariation = parseInt(localStorage.getItem('dark_mode') || 2);
+ let isDarkTheme;
+ if (currentThemeVariation === 2) {
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ // The visitor prefers dark themes.
+ isDarkTheme = 1;
+ } else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
+ // The visitor prefers light themes.
+ isDarkTheme = 0;
+ } else {
+ // The visitor does not have a day or night preference, so use the theme's default setting.
+ isDarkTheme = isSiteThemeDark;
+ }
+ renderThemeVariation(isDarkTheme);
+ }
+ });
+});
- // Automatic main menu dropdowns on mouse over.
- $('body').on('mouseenter mouseleave', '.dropdown', function (e) {
- var dropdown = $(e.target).closest('.dropdown');
- var menu = $('.dropdown-menu', dropdown);
- dropdown.addClass('show');
- menu.addClass('show');
- setTimeout(function () {
- dropdown[dropdown.is(':hover') ? 'addClass' : 'removeClass']('show');
- menu[dropdown.is(':hover') ? 'addClass' : 'removeClass']('show');
- }, 300);
+/* ---------------------------------------------------------------------------
+ * On window loaded.
+ * --------------------------------------------------------------------------- */
- // Re-initialize Scrollspy with dynamic navbar height offset.
- fixScrollspy();
+$(window).on('load', function () {
+ // 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';
+ }
- 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.
+ $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();
}
- }
-
- // Call `fixScrollspy` when window is resized.
- 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);
+ }
+
+ // Scroll to top of page.
+ $('.back-to-top').click(function (event) {
+ event.preventDefault();
+ $('html, body').animate({
+ 'scrollTop': 0
+ }, 800, function () {
+ window.location.hash = "";
+ });
+ });
+
+ // 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();
+
+ // Print latest version of GitHub projects.
+ let githubReleaseSelector = '.js-github-release';
+ if ($(githubReleaseSelector).length > 0)
+ printLatestRelease(githubReleaseSelector, $(githubReleaseSelector).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);
+
+// Automatic main menu dropdowns on mouse over.
+$('body').on('mouseenter mouseleave', '.dropdown', function (e) {
+ var dropdown = $(e.target).closest('.dropdown');
+ var menu = $('.dropdown-menu', dropdown);
+ dropdown.addClass('show');
+ menu.addClass('show');
+ setTimeout(function () {
+ dropdown[dropdown.is(':hover') ? 'addClass' : 'removeClass']('show');
+ menu[dropdown.is(':hover') ? 'addClass' : 'removeClass']('show');
+ }, 300);
+
+ // Re-initialize Scrollspy with dynamic navbar height offset.
+ fixScrollspy();
+
+ 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();
+ }
+ }
+
+ // Call `fixScrollspy` when window is resized.
+ let resizeTimer;
+ $(window).resize(function () {
+ clearTimeout(resizeTimer);
+ resizeTimer = setTimeout(fixScrollspy, 200);
+ });
+});
+
})(jQuery);
diff --git a/themes/academic/assets/js/vendor/fuse.min.js b/themes/academic/assets/js/vendor/fuse.min.js
new file mode 100644
index 0000000..0c7ae7d
--- /dev/null
+++ b/themes/academic/assets/js/vendor/fuse.min.js
@@ -0,0 +1,9 @@
+/*!
+ * Fuse.js v3.2.1 - Lightweight fuzzy-search (http://fusejs.io)
+ *
+ * Copyright (c) 2012-2017 Kirollos Risk (http://kiro.me)
+ * All Rights Reserved. Apache Software License 2.0
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("Fuse",[],t):"object"==typeof exports?exports.Fuse=t():e.Fuse=t()}(this,function(){return function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};return t.m=e,t.c=r,t.i=function(e){return e},t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=8)}([function(e,t,r){"use strict";e.exports=function(e){return Array.isArray?Array.isArray(e):"[object Array]"===Object.prototype.toString.call(e)}},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;rr)return i(e,this.pattern,n);var o=this.options,s=o.location,c=o.distance,h=o.threshold,l=o.findAllMatches,u=o.minMatchCharLength;return a(e,this.pattern,this.patternAlphabet,{location:s,distance:c,threshold:h,findAllMatches:l,minMatchCharLength:u})}}]),e}();e.exports=c},function(e,t,r){"use strict";var n=r(0),o=function e(t,r,o){if(r){var i=r.indexOf("."),a=r,s=null;-1!==i&&(a=r.slice(0,i),s=r.slice(i+1));var c=t[a];if(null!==c&&void 0!==c)if(s||"string"!=typeof c&&"number"!=typeof c)if(n(c))for(var h=0,l=c.length;h0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,r=[],n=-1,o=-1,i=0,a=e.length;i=t&&r.push([n,o]),n=-1)}return e[i-1]&&i-n>=t&&r.push([n,i-1]),r}},function(e,t,r){"use strict";e.exports=function(e){for(var t={},r=e.length,n=0;n2&&void 0!==arguments[2]?arguments[2]:/ +/g,n=new RegExp(t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&").replace(r,"|")),o=e.match(n),i=!!o,a=[];if(i)for(var s=0,c=o.length;s=P;T-=1){var E=T-1,K=r[e.charAt(E)];if(K&&(S[E]=1),z[T]=(z[T+1]<<1|1)&K,0!==I&&(z[T]|=(L[T+1]|L[T])<<1|1|L[T+1]),z[T]&C&&(w=n(t,{errors:I,currentLocation:E,expectedLocation:g,distance:h}))<=m){if(m=w,(k=E)<=g)break;P=Math.max(1,2*g-k)}}if(n(t,{errors:I+1,currentLocation:g,expectedLocation:g,distance:h})>m)break;L=z}return{isMatch:k>=0,score:0===w?.001:w,matchedIndices:o(S,p)}}},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r0&&void 0!==arguments[0]?arguments[0]:"",t=[];if(this.options.tokenize)for(var r=e.split(this.options.tokenSeparator),n=0,o=r.length;n0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1],r=this.list,n={},o=[];if("string"==typeof r[0]){for(var i=0,a=r.length;i1)throw new Error("Key weight has to be > 0 and <= 1");d=d.name}else s[d]={weight:1};this._analyze({key:d,value:this.options.getFn(l,d),record:l,index:c},{resultMap:n,results:o,tokenSearchers:e,fullSearcher:t})}return{weights:s,results:o}}},{key:"_analyze",value:function(e,t){var r=e.key,n=e.arrayIndex,o=void 0===n?-1:n,i=e.value,a=e.record,c=e.index,h=t.tokenSearchers,l=void 0===h?[]:h,u=t.fullSearcher,f=void 0===u?[]:u,d=t.resultMap,v=void 0===d?{}:d,p=t.results,g=void 0===p?[]:p;if(void 0!==i&&null!==i){var y=!1,m=-1,k=0;if("string"==typeof i){this._log("\nKey: "+(""===r?"-":r));var x=f.search(i);if(this._log('Full text: "'+i+'", score: '+x.score),this.options.tokenize){for(var S=i.split(this.options.tokenSeparator),M=[],b=0;b-1&&(P=(P+m)/2),this._log("Score average:",P);var j=!this.options.tokenize||!this.options.matchAllTokens||k>=l.length;if(this._log("\nCheck Matches: "+j),(y||x.isMatch)&&j){var z=v[c];z?z.output.push({key:r,arrayIndex:o,value:i,score:P,matchedIndices:x.matchedIndices}):(v[c]={item:a,output:[{key:r,arrayIndex:o,value:i,score:P,matchedIndices:x.matchedIndices}]},g.push(v[c]))}}else if(s(i))for(var T=0,E=i.length;T-1&&(a.arrayIndex=i.arrayIndex),t.matches.push(a)}}}),this.options.includeScore&&r.push(function(e,t){t.score=e.score});for(var n=0,o=e.length;n1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=i,this.iframesTimeout=o}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t=e.getAttribute("src").trim();return"about:blank"===e.contentWindow.location.href&&"about:blank"!==t&&t}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:null===t?e.nextNode():e.nextNode()&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o,a=this,s=this.createIterator(t,e,r),c=[],u=[],l=void 0,h=void 0;void 0,o=a.getIteratorNode(s),h=o.prevNode,l=o.node;)this.iframes&&this.forEachIframe(t,function(e){return a.checkIframeFilter(l,h,e,c)},function(t){a.createInstanceOnIframe(t).forEachNode(e,function(e){return u.push(e)},r)}),u.push(l);u.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(c,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}(),o=function(){function o(e){t(this,o),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(o,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createRegExp",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e)}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(a)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynomyms(a)+"|"+this.processSynomyms(s)+")"+r))}return e}},{key:"processSynomyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return(r=(s=s>o?o:s)+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return i.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(n-t),a=document.createElement(r);return a.setAttribute("data-markjs","true"),this.opt.className&&a.setAttribute("class",this.opt.className),a.textContent=i.textContent,i.parentNode.replaceChild(a,i),o}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];)if(n(i[a],t)){var s=i.index;if(0!==a)for(var c=1;c
{{ block "main" . }}{{ end }}
+ {{ partial "search" . }}
{{ partial "site_js" . }}