Procházet zdrojové kódy

refactor(js): run code formatter

George Cushen před 4 roky
rodič
revize
3d8b76f092

+ 1 - 0
wowchemy/.prettierignore

@@ -0,0 +1 @@
+assets/js/_vendor/

+ 9 - 0
wowchemy/.prettierrc.js

@@ -0,0 +1,9 @@
+'use strict';
+
+module.exports = {
+  bracketSpacing: false,
+  singleQuote: true,
+  jsxBracketSameLine: true,
+  trailingComma: 'all',
+  printWidth: 120,
+};

+ 10 - 10
wowchemy/assets/js/algolia-search.js

@@ -5,7 +5,7 @@
  *  Algolia based search algorithm.
  **************************************************/
 
-if ((typeof instantsearch === 'function') && $('#search-box').length) {
+if (typeof instantsearch === 'function' && $('#search-box').length) {
   function getTemplate(templateName) {
     return document.querySelector(`#${templateName}-template`).innerHTML;
   }
@@ -16,17 +16,17 @@ if ((typeof instantsearch === 'function') && $('#search-box').length) {
     indexName: algoliaConfig.indexName,
     routing: true,
     searchParameters: {
-      hitsPerPage: 10
+      hitsPerPage: 10,
     },
     searchFunction: function (helper) {
-      let searchResults = document.querySelector('#search-hits')
+      let searchResults = document.querySelector('#search-hits');
       if (helper.state.query === '') {
         searchResults.style.display = 'none';
         return;
       }
       helper.search();
       searchResults.style.display = 'block';
-    }
+    },
   };
 
   const search = instantsearch(options);
@@ -38,8 +38,8 @@ if ((typeof instantsearch === 'function') && $('#search-box').length) {
       autofocus: false,
       reset: true,
       poweredBy: algoliaConfig.poweredBy,
-      placeholder: i18n.placeholder
-    })
+      placeholder: i18n.placeholder,
+    }),
   );
 
   // Initialize search results.
@@ -49,12 +49,12 @@ if ((typeof instantsearch === 'function') && $('#search-box').length) {
       escapeHits: true,
       templates: {
         empty: '<div class="search-no-results">' + i18n.no_results + '</div>',
-        item: getTemplate('search-hit-algolia')
+        item: getTemplate('search-hit-algolia'),
       },
       cssClasses: {
-        showmoreButton: 'btn btn-outline-primary'
-      }
-    })
+        showmoreButton: 'btn btn-outline-primary',
+      },
+    }),
   );
 
   // On render search results, localize the content type metadata.

+ 11 - 5
wowchemy/assets/js/mathjax-config.js

@@ -5,12 +5,18 @@
 // - The TeX.noUndefined.attributes option is not yet implemented (but may be in a future release)
 window.MathJax = {
   tex: {
-    inlineMath: [['$', '$'], ['\\(', '\\)']],
-    displayMath: [['$$', '$$'], ['\\[', '\\]']],
+    inlineMath: [
+      ['$', '$'],
+      ['\\(', '\\)'],
+    ],
+    displayMath: [
+      ['$$', '$$'],
+      ['\\[', '\\]'],
+    ],
     processEscapes: false,
-    packages: {'[+]': ['noerrors']}
+    packages: {'[+]': ['noerrors']},
   },
   loader: {
-    load: ['[tex]/noerrors']
-  }
+    load: ['[tex]/noerrors'],
+  },
 };

+ 2 - 4
wowchemy/assets/js/wowchemy-animation.js

@@ -9,7 +9,7 @@ function fadeIn(element, duration = 600) {
   element.style.display = '';
   element.style.opacity = '0';
   let last = +new Date();
-  let tick = function() {
+  let tick = function () {
     element.style.opacity = (+element.style.opacity + (new Date() - last) / duration).toString();
     last = +new Date();
     if (+element.style.opacity < 1) {
@@ -19,6 +19,4 @@ function fadeIn(element, duration = 600) {
   tick();
 }
 
-export {
-  fadeIn,
-};
+export {fadeIn};

+ 1 - 1
wowchemy/assets/js/wowchemy-init.js

@@ -12,7 +12,7 @@ import {wcDarkLightEnabled, wcIsSiteThemeDark} from '@params';
 window.wc = {
   darkLightEnabled: wcDarkLightEnabled,
   isSiteThemeDark: wcIsSiteThemeDark,
-}
+};
 
 // Initialize theme variation and set body theme class.
 initThemeVariation();

+ 62 - 46
wowchemy/assets/js/wowchemy-search.js

@@ -6,35 +6,35 @@
  **************************************************/
 
 /* ---------------------------------------------------------------------------
-* Configuration.
-* --------------------------------------------------------------------------- */
+ * Configuration.
+ * --------------------------------------------------------------------------- */
 
 // Configure Fuse.
 let fuseOptions = {
   shouldSort: true,
   includeMatches: true,
   tokenize: true,
-  threshold: search_config.threshold,  // Set to ~0.3 for parsing diacritics and CJK languages.
+  threshold: search_config.threshold, // Set to ~0.3 for parsing diacritics and CJK languages.
   location: 0,
   distance: 100,
   maxPatternLength: 32,
-  minMatchCharLength: search_config.minLength,  // Set to 1 for parsing CJK languages.
+  minMatchCharLength: search_config.minLength, // Set to 1 for parsing CJK languages.
   keys: [
-    {name:'title', weight:0.99}, /* 1.0 doesn't work o_O */
-    {name:'summary', weight:0.6},
-    {name:'authors', weight:0.5},
-    {name:'content', weight:0.2},
-    {name:'tags', weight:0.5},
-    {name:'categories', weight:0.5}
-  ]
+    {name: 'title', weight: 0.99} /* 1.0 doesn't work o_O */,
+    {name: 'summary', weight: 0.6},
+    {name: 'authors', weight: 0.5},
+    {name: 'content', weight: 0.2},
+    {name: 'tags', weight: 0.5},
+    {name: 'categories', weight: 0.5},
+  ],
 };
 
 // Configure summary.
 let summaryLength = 60;
 
 /* ---------------------------------------------------------------------------
-* Functions.
-* --------------------------------------------------------------------------- */
+ * Functions.
+ * --------------------------------------------------------------------------- */
 
 // Get query from URI.
 function getSearchQuery(name) {
@@ -44,29 +44,35 @@ function getSearchQuery(name) {
 // Set query in URI without reloading the page.
 function updateURL(url) {
   if (history.replaceState) {
-    window.history.replaceState({path:url}, '', url);
+    window.history.replaceState({path: url}, '', url);
   }
 }
 
 // Pre-process new search query.
 function initSearch(force, fuse) {
-  let query = $("#search-query").val();
+  let query = $('#search-query').val();
 
   // If query deleted, clear results.
-  if ( query.length < 1) {
+  if (query.length < 1) {
     $('#search-hits').empty();
     $('#search-common-queries').show();
   }
 
   // Check for timer event (enter key not pressed) and query less than minimum length required.
-  if (!force && query.length < fuseOptions.minMatchCharLength)
-    return;
+  if (!force && query.length < fuseOptions.minMatchCharLength) return;
 
   // Do search.
   $('#search-hits').empty();
   $('#search-common-queries').hide();
   searchAcademic(query, fuse);
-  let newURL = window.location.protocol + "//" + window.location.host + window.location.pathname + '?q=' + encodeURIComponent(query) + window.location.hash;
+  let newURL =
+    window.location.protocol +
+    '//' +
+    window.location.host +
+    window.location.pathname +
+    '?q=' +
+    encodeURIComponent(query) +
+    window.location.hash;
   updateURL(newURL);
 }
 
@@ -85,34 +91,42 @@ function searchAcademic(query, fuse) {
 
 // Parse search results.
 function parseResults(query, results) {
-  $.each( results, function(key, value) {
+  $.each(results, function (key, value) {
     let content_key = value.item.section;
-    let content = "";
-    let snippet = "";
+    let content = '';
+    let snippet = '';
     let snippetHighlights = [];
 
     // Show abstract in results for content types where the abstract is often the primary content.
-    if (["publication", "event"].includes(content_key)) {
+    if (['publication', 'event'].includes(content_key)) {
       content = value.item.summary;
     } else {
       content = value.item.content;
     }
 
-    if ( fuseOptions.tokenize ) {
+    if (fuseOptions.tokenize) {
       snippetHighlights.push(query);
     } else {
-      $.each( value.matches, function(matchKey, matchValue) {
-        if (matchValue.key == "content") {
-          let start = (matchValue.indices[0][0]-summaryLength>0) ? matchValue.indices[0][0]-summaryLength : 0;
-          let end = (matchValue.indices[0][1]+summaryLength<content.length) ? matchValue.indices[0][1]+summaryLength : content.length;
+      $.each(value.matches, function (matchKey, matchValue) {
+        if (matchValue.key == 'content') {
+          let start = matchValue.indices[0][0] - summaryLength > 0 ? matchValue.indices[0][0] - summaryLength : 0;
+          let end =
+            matchValue.indices[0][1] + summaryLength < content.length
+              ? matchValue.indices[0][1] + summaryLength
+              : content.length;
           snippet += content.substring(start, end);
-          snippetHighlights.push(matchValue.value.substring(matchValue.indices[0][0], matchValue.indices[0][1]-matchValue.indices[0][0]+1));
+          snippetHighlights.push(
+            matchValue.value.substring(
+              matchValue.indices[0][0],
+              matchValue.indices[0][1] - matchValue.indices[0][0] + 1,
+            ),
+          );
         }
       });
     }
 
     if (snippet.length < 1) {
-      snippet += value.item.summary;  // Alternative fallback: `content.substring(0, summaryLength*2);`
+      snippet += value.item.summary; // Alternative fallback: `content.substring(0, summaryLength*2);`
     }
 
     // Load template.
@@ -129,16 +143,15 @@ function parseResults(query, results) {
       title: value.item.title,
       type: content_key,
       relpermalink: value.item.relpermalink,
-      snippet: snippet
+      snippet: snippet,
     };
     let output = render(template, templateData);
     $('#search-hits').append(output);
 
     // Highlight search terms in result.
-    $.each( snippetHighlights, function(hlKey, hlValue){
-      $("#summary-"+key).mark(hlValue);
+    $.each(snippetHighlights, function (hlKey, hlValue) {
+      $('#summary-' + key).mark(hlValue);
     });
-
   });
 }
 
@@ -146,7 +159,7 @@ function render(template, data) {
   // Replace placeholders with their values.
   let key, find, re;
   for (key in data) {
-    find = '\\{\\{\\s*' + key + '\\s*\\}\\}';  // Expect placeholder in the form `{{x}}`.
+    find = '\\{\\{\\s*' + key + '\\s*\\}\\}'; // Expect placeholder in the form `{{x}}`.
     re = new RegExp(find, 'g');
     template = template.replace(re, data[key]);
   }
@@ -154,21 +167,21 @@ function render(template, data) {
 }
 
 /* ---------------------------------------------------------------------------
-* Initialize.
-* --------------------------------------------------------------------------- */
+ * Initialize.
+ * --------------------------------------------------------------------------- */
 
 // If Academic's in-built search is enabled and Fuse loaded, then initialize it.
 if (typeof Fuse === 'function') {
-// Wait for Fuse to initialize.
+  // Wait for Fuse to initialize.
   $.getJSON(search_config.indexURI, function (search_index) {
     let fuse = new Fuse(search_index, fuseOptions);
 
     // On page load, check for search query in URL.
-    if (query = getSearchQuery('q')) {
-      $("body").addClass('searching');
-      $('.search-results').css({opacity: 0, visibility: "visible"}).animate({opacity: 1},200);
-      $("#search-query").val(query);
-      $("#search-query").focus();
+    if ((query = getSearchQuery('q'))) {
+      $('body').addClass('searching');
+      $('.search-results').css({opacity: 0, visibility: 'visible'}).animate({opacity: 1}, 200);
+      $('#search-query').val(query);
+      $('#search-query').focus();
       initSearch(true, fuse);
     }
 
@@ -178,9 +191,12 @@ if (typeof Fuse === 'function') {
       if (e.keyCode == 13) {
         initSearch(true, fuse);
       } else {
-        $(this).data('searchTimer', setTimeout(function () {
-          initSearch(false, fuse);
-        }, 250));
+        $(this).data(
+          'searchTimer',
+          setTimeout(function () {
+            initSearch(false, fuse);
+          }, 250),
+        );
       }
     });
   });

+ 11 - 8
wowchemy/assets/js/wowchemy-theming.js

@@ -34,7 +34,7 @@ function initThemeVariation() {
 
   let isDarkTheme;
   let currentThemeMode = getThemeMode();
-  console.debug(`User's theme variation: ${currentThemeMode}`)
+  console.debug(`User's theme variation: ${currentThemeMode}`);
 
   switch (currentThemeMode) {
     case 0:
@@ -59,10 +59,10 @@ function initThemeVariation() {
 
   if (isDarkTheme && !body.classList.contains('dark')) {
     console.debug('Applying Wowchemy dark theme');
-    document.body.classList.add("dark");
+    document.body.classList.add('dark');
   } else if (!isDarkTheme && body.classList.contains('dark')) {
     console.debug('Applying Wowchemy light theme');
-    document.body.classList.remove("dark");
+    document.body.classList.remove('dark');
   }
 
   return {
@@ -149,7 +149,7 @@ function renderThemeVariation(isDarkTheme, themeMode = 2, init = false) {
   // Is code highlighting enabled in site config?
   const codeHlLight = document.querySelector('link[title=hl-light]');
   const codeHlDark = document.querySelector('link[title=hl-dark]');
-  const codeHlEnabled = (codeHlLight !== null) || (codeHlDark !== null);
+  const codeHlEnabled = codeHlLight !== null || codeHlDark !== null;
   const diagramEnabled = document.querySelector('script[title=mermaid]') !== null;
 
   // Update active theme mode in navbar theme selector.
@@ -159,7 +159,10 @@ function renderThemeVariation(isDarkTheme, themeMode = 2, init = false) {
   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 === false && !body.classList.contains('dark')) || (isDarkTheme === true && body.classList.contains('dark'))) {
+    if (
+      (isDarkTheme === false && !body.classList.contains('dark')) ||
+      (isDarkTheme === true && body.classList.contains('dark'))
+    ) {
       return;
     }
   }
@@ -176,7 +179,7 @@ function renderThemeVariation(isDarkTheme, themeMode = 2, init = false) {
       if (codeHlLight) {
         codeHlLight.disabled = false;
       }
-      if (codeHlDark){
+      if (codeHlDark) {
         codeHlDark.disabled = true;
       }
     }
@@ -196,13 +199,13 @@ function renderThemeVariation(isDarkTheme, themeMode = 2, init = false) {
       Object.assign(document.body.style, {opacity: 0, visibility: 'visible'});
       fadeIn(document.body, 600);
     }
-    body.classList.add("dark");
+    body.classList.add('dark');
     if (codeHlEnabled) {
       console.debug('Setting HLJS theme to dark');
       if (codeHlLight) {
         codeHlLight.disabled = true;
       }
-      if (codeHlDark){
+      if (codeHlDark) {
         codeHlDark.disabled = false;
       }
     }

+ 1 - 3
wowchemy/assets/js/wowchemy-utils.js

@@ -23,6 +23,4 @@ function fixMermaid() {
   }
 }
 
-export {
-  fixMermaid,
-};
+export {fixMermaid};

+ 114 - 89
wowchemy/assets/js/wowchemy.js

@@ -16,9 +16,9 @@ import {
   onMediaQueryListEvent,
 } from './wowchemy-theming';
 
-const searchEnabled = (typeof search_config !== 'undefined');
+const searchEnabled = typeof search_config !== 'undefined';
 
-console.debug(`Environment: ${hugoEnvironment}`)
+console.debug(`Environment: ${hugoEnvironment}`);
 
 /* ---------------------------------------------------------------------------
  * Responsive scrolling for URL hashes.
@@ -41,20 +41,25 @@ function getNavBarHeight() {
 function scrollToAnchor(target, duration = 600) {
   // If `target` is undefined or HashChangeEvent object, set it to window's hash.
   // Decode the hash as browsers can encode non-ASCII characters (e.g. Chinese symbols).
-  target = (typeof target === 'undefined' || typeof target === 'object') ? decodeURIComponent(window.location.hash) : target;
+  target =
+    typeof target === 'undefined' || typeof target === 'object' ? decodeURIComponent(window.location.hash) : target;
 
   // If target element exists, scroll to it taking into account fixed navigation bar offset.
   if ($(target).length) {
     // Escape special chars from IDs, such as colons found in Markdown footnote links.
-    target = '#' + $.escapeSelector(target.substring(1));  // Previously, `target = target.replace(/:/g, '\\:');`
+    target = '#' + $.escapeSelector(target.substring(1)); // Previously, `target = target.replace(/:/g, '\\:');`
 
-    let elementOffset = Math.ceil($(target).offset().top - getNavBarHeight());  // Round up to highlight right ID!
+    let elementOffset = Math.ceil($(target).offset().top - getNavBarHeight()); // Round up to highlight right ID!
     $('body').addClass('scrolling');
-    $('html, body').animate({
-      scrollTop: elementOffset
-    }, duration, function () {
-      $('body').removeClass('scrolling');
-    });
+    $('html, body').animate(
+      {
+        scrollTop: elementOffset,
+      },
+      duration,
+      function () {
+        $('body').removeClass('scrolling');
+      },
+    );
   } else {
     console.debug('Cannot scroll to target `#' + target + '`. ID not found!');
   }
@@ -73,13 +78,14 @@ function fixScrollspy() {
 
 function removeQueryParamsFromUrl() {
   if (window.history.replaceState) {
-    let urlWithoutSearchParams = window.location.protocol + "//" + window.location.host + window.location.pathname + window.location.hash;
+    let urlWithoutSearchParams =
+      window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.hash;
     window.history.replaceState({path: urlWithoutSearchParams}, '', urlWithoutSearchParams);
   }
 }
 
 // Check for hash change event and fix responsive offset for hash links (e.g. Markdown footnotes).
-window.addEventListener("hashchange", scrollToAnchor);
+window.addEventListener('hashchange', scrollToAnchor);
 
 /* ---------------------------------------------------------------------------
  * Add smooth scrolling to all links inside the main navbar.
@@ -90,22 +96,25 @@ $('#navbar-main li.nav-item a.nav-link, .js-scroll').on('click', function (event
   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)) {
+  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.
-    let elementOffset = Math.ceil($(hash).offset().top - getNavBarHeight());  // Round up to highlight right ID!
+    let elementOffset = Math.ceil($(hash).offset().top - getNavBarHeight()); // Round up to highlight right ID!
 
     // Uncomment to debug.
     // let scrollTop = $(window).scrollTop();
     // let scrollDelta = (elementOffset - scrollTop);
     // console.debug('Scroll Delta: ' + scrollDelta);
 
-    $('html, body').animate({
-      scrollTop: elementOffset
-    }, 800);
+    $('html, body').animate(
+      {
+        scrollTop: elementOffset,
+      },
+      800,
+    );
   }
 });
 
@@ -145,21 +154,23 @@ if ($grid_pubs.length) {
     percentPosition: true,
     masonry: {
       // Use Bootstrap compatible grid layout.
-      columnWidth: '.grid-sizer'
+      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();
-  }));
+  let $quickSearch = $('.filter-search').keyup(
+    debounce(function () {
+      searchRegex = new RegExp($quickSearch.val(), 'gi');
+      $grid_pubs.isotope();
+    }),
+  );
 
   $('.pub-filters').on('change', function () {
     let $this = $(this);
@@ -177,7 +188,7 @@ if ($grid_pubs.length) {
     $grid_pubs.isotope();
 
     // If filtering by publication type, update the URL hash to enable direct linking to results.
-    if (filterGroup === "pubtype") {
+    if (filterGroup === 'pubtype') {
       // Set hash URL to current filter.
       let url = $(this).val();
       if (url.substr(0, 9) === '.pubtype-') {
@@ -218,8 +229,7 @@ function concatValues(obj) {
 // Filter publications according to hash in URL.
 function filter_publications() {
   // Check for Isotope publication layout.
-  if (!$grid_pubs.length)
-    return
+  if (!$grid_pubs.length) return;
 
   let urlHash = window.location.hash.replace('#', '');
   let filterValue = '*';
@@ -242,8 +252,8 @@ function filter_publications() {
 }
 
 /* ---------------------------------------------------------------------------
-* Google Maps or OpenStreetMap via Leaflet.
-* --------------------------------------------------------------------------- */
+ * Google Maps or OpenStreetMap via Leaflet.
+ * --------------------------------------------------------------------------- */
 
 function initMap() {
   if ($('#map').length) {
@@ -263,11 +273,11 @@ function initMap() {
         zoomControl: true,
         zoomControlOpt: {
           style: 'SMALL',
-          position: 'TOP_LEFT'
+          position: 'TOP_LEFT',
         },
         streetViewControl: false,
         mapTypeControl: false,
-        gestureHandling: "cooperative",
+        gestureHandling: 'cooperative',
       });
 
       map.addMarker({
@@ -275,30 +285,36 @@ function initMap() {
         lng: lng,
         click: function (e) {
           let url = 'https://www.google.com/maps/place/' + encodeURIComponent(address) + '/@' + lat + ',' + lng + '/';
-          window.open(url, '_blank')
+          window.open(url, '_blank');
         },
-        title: address
-      })
+        title: address,
+      });
     } else {
       let map = new L.map('map').setView([lat, lng], zoom);
       if (map_provider == 3 && api_key.length) {
         L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
-          attribution: 'Map data &copy; <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>',
+          attribution:
+            'Map data &copy; <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>',
           tileSize: 512,
           maxZoom: 18,
           zoomOffset: -1,
           id: 'mapbox/streets-v11',
-          accessToken: api_key
+          accessToken: api_key,
         }).addTo(map);
       } else {
         L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
           maxZoom: 19,
-          attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
+          attribution: '&copy; <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>');
+      marker.bindPopup(
+        address +
+          '<p><a href="https://www.openstreetmap.org/directions?engine=osrm_car&route=' +
+          url +
+          '">Routing via OpenStreetMap</a></p>',
+      );
     }
   }
 }
@@ -309,19 +325,21 @@ function initMap() {
 
 function printLatestRelease(selector, repo) {
   if (hugoEnvironment === 'production') {
-    $.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);
-    });
+    $.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.
-* --------------------------------------------------------------------------- */
+ * Toggle search dialog.
+ * --------------------------------------------------------------------------- */
 
 function toggleSearchDialog() {
   if ($('body').hasClass('searching')) {
@@ -339,8 +357,8 @@ function toggleSearchDialog() {
     if (!$('#fancybox-style-noscroll').length && document.body.scrollHeight > window.innerHeight) {
       $('head').append(
         '<style id="fancybox-style-noscroll">.compensate-for-scrollbar{margin-right:' +
-        (window.innerWidth - document.documentElement.clientWidth) +
-        'px;}</style>'
+          (window.innerWidth - document.documentElement.clientWidth) +
+          'px;}</style>',
       );
       $('body').addClass('compensate-for-scrollbar');
     }
@@ -353,8 +371,8 @@ function toggleSearchDialog() {
 }
 
 /* ---------------------------------------------------------------------------
-* Normalize Bootstrap Carousel Slide Heights.
-* --------------------------------------------------------------------------- */
+ * Normalize Bootstrap Carousel Slide Heights.
+ * --------------------------------------------------------------------------- */
 
 function normalizeCarouselSlideHeights() {
   $('.carousel').each(function () {
@@ -363,16 +381,21 @@ function normalizeCarouselSlideHeights() {
     // 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());
+    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 and Mermaid code blocks.
+ * --------------------------------------------------------------------------- */
 
 /**
  * Fix Hugo's Goldmark output.
@@ -453,30 +476,32 @@ $(window).on('load', function () {
         itemSelector: '.isotope-item',
         layoutMode: layout,
         masonry: {
-          gutter: 20
+          gutter: 20,
         },
-        filter: filterText
+        filter: filterText,
       });
 
       // Filter Isotope items when a toolbar filter button is clicked.
       let isoFilterButtons = isoSection.querySelectorAll('.project-filters a');
-      isoFilterButtons.forEach(button => button.addEventListener('click', (e) => {
-        e.preventDefault();
-        let selector = button.getAttribute('data-filter');
-
-        // Apply filter
-        console.debug(`Updating Isotope filter to ${selector}`);
-        iso.arrange({filter: selector});
-
-        // Update active toolbar filter button
-        button.classList.remove('active');
-        button.classList.add('active');
-        let buttonSiblings = getSiblings(button);
-        buttonSiblings.forEach(buttonSibling => {
-          buttonSibling.classList.remove('active');
-          buttonSibling.classList.remove('all');
-        });
-      }));
+      isoFilterButtons.forEach((button) =>
+        button.addEventListener('click', (e) => {
+          e.preventDefault();
+          let selector = button.getAttribute('data-filter');
+
+          // Apply filter
+          console.debug(`Updating Isotope filter to ${selector}`);
+          iso.arrange({filter: selector});
+
+          // Update active toolbar filter button
+          button.classList.remove('active');
+          button.classList.add('active');
+          let buttonSiblings = getSiblings(button);
+          buttonSiblings.forEach((buttonSibling) => {
+            buttonSibling.classList.remove('active');
+            buttonSibling.classList.remove('all');
+          });
+        }),
+      );
 
       // Check if all Isotope instances have loaded.
       incrementIsotopeCounter();
@@ -513,8 +538,8 @@ $(window).on('load', function () {
     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);
+        let msg = 'Error: ';
+        $('#modal-error').html(msg + xhr.status + ' ' + xhr.statusText);
       } else {
         $('.js-download-cite').attr('href', filename);
       }
@@ -551,7 +576,7 @@ $(window).on('load', function () {
 
   // Parse Wowchemy keyboard shortcuts.
   document.addEventListener('keyup', (event) => {
-    if (event.code === "Escape") {
+    if (event.code === 'Escape') {
       const body = document.body;
       if (body.classList.contains('searching')) {
         // Close search dialog.
@@ -559,13 +584,13 @@ $(window).on('load', function () {
       }
     }
     // Use `key` to check for slash. Otherwise, with `code` we need to check for modifiers.
-    if (event.key === "/" ) {
-      let focusedElement = (
-        document.hasFocus() &&
-        document.activeElement !== document.body &&
-        document.activeElement !== document.documentElement &&
-        document.activeElement
-      ) || null;
+    if (event.key === '/') {
+      let focusedElement =
+        (document.hasFocus() &&
+          document.activeElement !== document.body &&
+          document.activeElement !== document.documentElement &&
+          document.activeElement) ||
+        null;
       let isInputFocused = focusedElement instanceof HTMLInputElement || focusedElement instanceof HTMLTextAreaElement;
       if (searchEnabled && !isInputFocused) {
         // Open search dialog.
@@ -597,15 +622,15 @@ let linkLight = document.querySelector('.js-set-theme-light');
 let linkDark = document.querySelector('.js-set-theme-dark');
 let linkAuto = document.querySelector('.js-set-theme-auto');
 if (linkLight && linkDark && linkAuto) {
-  linkLight.addEventListener('click', event => {
+  linkLight.addEventListener('click', (event) => {
     event.preventDefault();
     changeThemeModeClick(0);
   });
-  linkDark.addEventListener('click', event => {
+  linkDark.addEventListener('click', (event) => {
     event.preventDefault();
     changeThemeModeClick(1);
   });
-  linkAuto.addEventListener('click', event => {
+  linkAuto.addEventListener('click', (event) => {
     event.preventDefault();
     changeThemeModeClick(2);
   });
@@ -615,7 +640,7 @@ if (linkLight && linkDark && linkAuto) {
 // 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.addEventListener("change", (event) => {
+darkModeMediaQuery.addEventListener('change', (event) => {
   onMediaQueryListEvent(event);
 });
 

+ 3 - 1
wowchemy/package.json

@@ -7,7 +7,9 @@
     "bootstrap": "^4.4.1",
     "instant.page": "^5.1.0"
   },
-  "devDependencies": {},
+  "devDependencies": {
+    "prettier": "2.2.1"
+  },
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
   },

+ 5 - 0
wowchemy/yarn.lock

@@ -11,3 +11,8 @@ instant.page@^5.1.0:
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/instant.page/-/instant.page-5.1.0.tgz#ee0b5c341eda6c16d63def214bb6126701d7154d"
   integrity sha512-7tz0vkrbj6rN08+C56UDTs1Z71ATPNjMv2eCFaYnIIn3jlkEF6HZCaUtsigjaN2hVaYiuu06vu1usDMnu+OEFg==
+
+prettier@2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
+  integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==