From 1bca2189556359474c7fe50244f925a239fa62f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Weber?= Date: Sat, 26 Feb 2022 00:24:07 +0100 Subject: [PATCH] theme: move code arround #210 --- static/js/theme.js | 397 ++++++++++++++++++++++----------------------- 1 file changed, 194 insertions(+), 203 deletions(-) diff --git a/static/js/theme.js b/static/js/theme.js index 183dc454de..9fb4867370 100644 --- a/static/js/theme.js +++ b/static/js/theme.js @@ -1,35 +1,3 @@ -// Scrollbar Width function -function getScrollBarWidth() { - var inner = document.createElement('p'); - inner.style.width = "100%"; - inner.style.height = "200px"; - - var outer = document.createElement('div'); - outer.style.position = "absolute"; - outer.style.top = "0px"; - outer.style.left = "0px"; - outer.style.visibility = "hidden"; - outer.style.width = "200px"; - outer.style.height = "150px"; - outer.style.overflow = "hidden"; - outer.appendChild(inner); - - document.body.appendChild(outer); - var w1 = inner.offsetWidth; - outer.style.overflow = 'scroll'; - var w2 = inner.offsetWidth; - if (w1 == w2) w2 = outer.clientWidth; - - document.body.removeChild(outer); - - return (w1 - w2); -}; - -function setMenuHeight() { - $('#sidebar .highlightable').height($('#sidebar').innerHeight() - $('#header-wrapper').height() - 40); - ps && ps.update(); -} - function switchTab(tabGroup, tabId) { allTabItems = jQuery("[data-tab-group='"+tabGroup+"']"); targetTabItems = jQuery("[data-tab-group='"+tabGroup+"'][data-tab-item='"+tabId+"']"); @@ -81,6 +49,104 @@ function restoreTabSelections() { } } +function initStickyHeader(){ + var markSticky = function(){ + // add marker when not in top position; allows users + // to change styles (eg. add a dropshadow) + if ($(this).scrollTop() == 0) { + $('#top-bar').removeClass("is-sticky"); + } + else { + $('#top-bar').addClass("is-sticky"); + } + }; + markSticky(); + $(window).scroll( markSticky ); + + /** + * Fix anchor scrolling that hides behind sticky top nav bar + * Courtesy of https://stackoverflow.com/a/13067009/28106 + * + * We could use pure css for this if only heading anchors were + * involved, but this works for any anchor, including footnotes + **/ + (function (document, history, location) { + var HISTORY_SUPPORT = !!(history && history.pushState); + + var anchorScrolls = { + ANCHOR_REGEX: /^#[^ ]+$/, + OFFSET_HEIGHT_PX: 50, + + /** + * Establish events, and fix initial scroll position if a hash is provided. + */ + init: function () { + this.scrollToCurrent(); + $(window).on('hashchange', $.proxy(this, 'scrollToCurrent')); + $('body').on('click', 'a', $.proxy(this, 'delegateAnchors')); + }, + + /** + * Return the offset amount to deduct from the normal scroll position. + * Modify as appropriate to allow for dynamic calculations + */ + getFixedOffset: function () { + return this.OFFSET_HEIGHT_PX; + }, + + /** + * If the provided href is an anchor which resolves to an element on the + * page, scroll to it. + * @param {String} href + * @return {Boolean} - Was the href an anchor. + */ + scrollIfAnchor: function (href, pushToHistory) { + var match, anchorOffset; + + if (!this.ANCHOR_REGEX.test(href)) { + return false; + } + + match = document.getElementById(href.slice(1)); + + if (match) { + anchorOffset = $(match).offset().top - this.getFixedOffset(); + $('html, body').animate({ scrollTop: anchorOffset }); + + // Add the state to history as-per normal anchor links + if (HISTORY_SUPPORT && pushToHistory) { + history.pushState({}, document.title, location.pathname + href); + } + } + + return !!match; + }, + + /** + * Attempt to scroll to the current location's hash. + */ + scrollToCurrent: function (e) { + if (this.scrollIfAnchor(window.location.hash) && e) { + e.preventDefault(); + } + }, + + /** + * If the click event's target was an anchor, fix the scroll position. + */ + delegateAnchors: function (e) { + var elem = e.target; + + if (this.scrollIfAnchor(elem.getAttribute('href'), true)) { + e.preventDefault(); + } + } + }; + + $(document).ready($.proxy(anchorScrolls, 'init')); + })(window.document, window.history, window.location); +} + function initMermaid() { $('code.language-mermaid').each(function(index, element) { var content = $(element).html().replace(/&/g, '&'); @@ -210,6 +276,97 @@ function initArrowNav(){ }); } +function initMenuScrollbar(){ + var setMenuHeight = function (){ + $('#sidebar .highlightable').height($('#sidebar').innerHeight() - $('#header-wrapper').height() - 40); + ps && ps.update(); + }; + + var ps = new PerfectScrollbar('#sidebar .highlightable'); + setMenuHeight(); + + // to inform scrollbar of resizing + $(window).resize(function() { + setMenuHeight(); + }); +} + +function initLightbox(){ + // wrap image inside a lightbox (to get a full size view in a popup) + var images = $("main#body-inner img").not(".inline"); + images.wrap(function(){ + var image =$(this); + var o = getUrlParameter(image[0].src); + var f = o['featherlight']; + // IF featherlight is false, do not use feather light + if (f != 'false') { + if (!image.parent("a").length) { + var html = $( "" ).attr("href", image[0].src).attr("data-featherlight", "image").get(0).outerHTML; + return html; + } + } + }); + + $('a[rel="lightbox"]').featherlight({ + root: 'div#body' + }); +} + +function initImageStyles(){ + // change image styles, depending on parameters set to the image + var images = $("main#body-inner img").not(".inline"); + images.each(function(index){ + var image = $(this) + var o = getUrlParameter(image[0].src); + if (typeof o !== "undefined") { + var h = o["height"]; + var w = o["width"]; + var c = o["classes"]; + image.css("width", function() { + if (typeof w !== "undefined") { + return w; + } else { + return "auto"; + } + }); + image.css("height", function() { + if (typeof h !== "undefined") { + return h; + } else { + return "auto"; + } + }); + if (typeof c !== "undefined") { + var classes = c.split(','); + for (i = 0; i < classes.length; i++) { + image.addClass(classes[i]); + } + } + } + }); +} + +function initToc(){ + var touchsupport = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0) + if (touchsupport){ + $('#toc-menu').click(function() { + $('.progress').stop(true, false, true).fadeToggle(100); + }); + $('.progress').click(function() { + $('.progress').stop(true, false, true).fadeToggle(100); + }); + } + else{ + $('#toc-menu').hover(function() { + $('.progress').stop(true, false, true).fadeToggle(100); + }); + + $('.progress').hover(function() { + $('.progress').stop(true, false, true).fadeToggle(100); + }); + } +} + function scrollToActiveMenu() { window.setTimeout(function(){ var e = $("#sidebar ul.topics li.active a")[0]; @@ -237,67 +394,6 @@ var getUrlParameter = function getUrlParameter(sPageURL) { return obj; }; -// Execute actions on images generated from Markdown pages -var images = $("main#body-inner img").not(".inline"); -// Wrap image inside a featherlight (to get a full size view in a popup) -images.wrap(function(){ - var image =$(this); - var o = getUrlParameter(image[0].src); - var f = o['featherlight']; - // IF featherlight is false, do not use feather light - if (f != 'false') { - if (!image.parent("a").length) { - var html = $( "" ).attr("href", image[0].src).attr("data-featherlight", "image").get(0).outerHTML; - return html; - } - } -}); - -// Change styles, depending on parameters set to the image -images.each(function(index){ - var image = $(this) - var o = getUrlParameter(image[0].src); - if (typeof o !== "undefined") { - var h = o["height"]; - var w = o["width"]; - var c = o["classes"]; - image.css("width", function() { - if (typeof w !== "undefined") { - return w; - } else { - return "auto"; - } - }); - image.css("height", function() { - if (typeof h !== "undefined") { - return h; - } else { - return "auto"; - } - }); - if (typeof c !== "undefined") { - var classes = c.split(','); - for (i = 0; i < classes.length; i++) { - image.addClass(classes[i]); - } - } - } -}); - -// for the window resize -$(window).resize(function() { - setMenuHeight(); -}); -// for the sticky header -$(window).scroll(function() { - // add shadow when not in top position - if ($(this).scrollTop() == 0) { - $('#top-bar').removeClass("is-sticky"); - } - else { - $('#top-bar').addClass("is-sticky"); - } -}); // debouncing function from John Hann // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/ (function($, sr) { @@ -327,19 +423,20 @@ $(window).scroll(function() { })(jQuery, 'smartresize'); -var ps = null; jQuery(function() { restoreTabSelections(); + initStickyHeader(); initMermaid(); initAnchorClipboard(); initCodeClipboard(); initArrowNav(); + initMenuScrollbar(); + initLightbox(); + initImageStyles(); + initToc(); scrollToActiveMenu(); var sidebarStatus = 'open'; - ps = new PerfectScrollbar('#sidebar .highlightable'); - setMenuHeight(); - jQuery('#overlay').on('click', function() { jQuery(document.body).toggleClass('sidebar-hidden'); sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open'); @@ -412,112 +509,6 @@ jQuery(function() { $('#top-bar a:not(:has(img)):not(.btn)').addClass('highlight'); $('#body-inner a:not(:has(img)):not(.btn):not(a[rel="footnote"])').addClass('highlight'); - var touchsupport = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0) - if (!touchsupport){ // browser doesn't support touch - $('#toc-menu').hover(function() { - $('.progress').stop(true, false, true).fadeToggle(100); - }); - - $('.progress').hover(function() { - $('.progress').stop(true, false, true).fadeToggle(100); - }); - } - if (touchsupport){ // browser does support touch - $('#toc-menu').click(function() { - $('.progress').stop(true, false, true).fadeToggle(100); - }); - $('.progress').click(function() { - $('.progress').stop(true, false, true).fadeToggle(100); - }); - } - - /** - * Fix anchor scrolling that hides behind top nav bar - * Courtesy of https://stackoverflow.com/a/13067009/28106 - * - * We could use pure css for this if only heading anchors were - * involved, but this works for any anchor, including footnotes - **/ - (function (document, history, location) { - var HISTORY_SUPPORT = !!(history && history.pushState); - - var anchorScrolls = { - ANCHOR_REGEX: /^#[^ ]+$/, - OFFSET_HEIGHT_PX: 50, - - /** - * Establish events, and fix initial scroll position if a hash is provided. - */ - init: function () { - this.scrollToCurrent(); - $(window).on('hashchange', $.proxy(this, 'scrollToCurrent')); - $('body').on('click', 'a', $.proxy(this, 'delegateAnchors')); - }, - - /** - * Return the offset amount to deduct from the normal scroll position. - * Modify as appropriate to allow for dynamic calculations - */ - getFixedOffset: function () { - return this.OFFSET_HEIGHT_PX; - }, - - /** - * If the provided href is an anchor which resolves to an element on the - * page, scroll to it. - * @param {String} href - * @return {Boolean} - Was the href an anchor. - */ - scrollIfAnchor: function (href, pushToHistory) { - var match, anchorOffset; - - if (!this.ANCHOR_REGEX.test(href)) { - return false; - } - - match = document.getElementById(href.slice(1)); - - if (match) { - anchorOffset = $(match).offset().top - this.getFixedOffset(); - $('html, body').animate({ scrollTop: anchorOffset }); - - // Add the state to history as-per normal anchor links - if (HISTORY_SUPPORT && pushToHistory) { - history.pushState({}, document.title, location.pathname + href); - } - } - - return !!match; - }, - - /** - * Attempt to scroll to the current location's hash. - */ - scrollToCurrent: function (e) { - if (this.scrollIfAnchor(window.location.hash) && e) { - e.preventDefault(); - } - }, - - /** - * If the click event's target was an anchor, fix the scroll position. - */ - delegateAnchors: function (e) { - var elem = e.target; - - if (this.scrollIfAnchor(elem.getAttribute('href'), true)) { - e.preventDefault(); - } - } - }; - - $(document).ready($.proxy(anchorScrolls, 'init')); - })(window.document, window.history, window.location); - - $('a[rel="lightbox"]').featherlight({ - root: 'div#body' - }); - sessionStorage.setItem(jQuery('body').data('url'), 1); // loop through the sessionStorage and see if something should be marked as visited