mirror of
https://github.com/McShelby/hugo-theme-relearn.git
synced 2024-11-30 11:13:06 +00:00
d03bc79a78
If input field is in focus, keydown event to trigger navigation change should not fire. User should expect cursor to stay in input field when using arrow keys.
459 lines
15 KiB
JavaScript
459 lines
15 KiB
JavaScript
// 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);
|
|
$('#sidebar .highlightable').perfectScrollbar('update');
|
|
}
|
|
|
|
function fallbackMessage(action) {
|
|
var actionMsg = '';
|
|
var actionKey = (action === 'cut' ? 'X' : 'C');
|
|
|
|
if (/iPhone|iPad/i.test(navigator.userAgent)) {
|
|
actionMsg = 'No support :(';
|
|
}
|
|
else if (/Mac/i.test(navigator.userAgent)) {
|
|
actionMsg = 'Press ⌘-' + actionKey + ' to ' + action;
|
|
}
|
|
else {
|
|
actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action;
|
|
}
|
|
|
|
return actionMsg;
|
|
}
|
|
|
|
// for the window resize
|
|
$(window).resize(function() {
|
|
setMenuHeight();
|
|
});
|
|
|
|
// debouncing function from John Hann
|
|
// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
|
|
(function($, sr) {
|
|
|
|
var debounce = function(func, threshold, execAsap) {
|
|
var timeout;
|
|
|
|
return function debounced() {
|
|
var obj = this, args = arguments;
|
|
|
|
function delayed() {
|
|
if (!execAsap)
|
|
func.apply(obj, args);
|
|
timeout = null;
|
|
};
|
|
|
|
if (timeout)
|
|
clearTimeout(timeout);
|
|
else if (execAsap)
|
|
func.apply(obj, args);
|
|
|
|
timeout = setTimeout(delayed, threshold || 100);
|
|
};
|
|
}
|
|
// smartresize
|
|
jQuery.fn[sr] = function(fn) { return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
|
|
|
|
})(jQuery, 'smartresize');
|
|
|
|
|
|
jQuery(document).ready(function() {
|
|
jQuery('#sidebar .category-icon').on('click', function() {
|
|
$( this ).toggleClass("fa-angle-down fa-angle-right") ;
|
|
$( this ).parent().parent().children('ul').toggle() ;
|
|
return false;
|
|
});
|
|
|
|
var sidebarStatus = searchStatus = 'open';
|
|
$('#sidebar .highlightable').perfectScrollbar();
|
|
setMenuHeight();
|
|
|
|
jQuery('#overlay').on('click', function() {
|
|
jQuery(document.body).toggleClass('sidebar-hidden');
|
|
sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open');
|
|
|
|
return false;
|
|
});
|
|
|
|
jQuery('[data-sidebar-toggle]').on('click', function() {
|
|
jQuery(document.body).toggleClass('sidebar-hidden');
|
|
sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open');
|
|
|
|
return false;
|
|
});
|
|
jQuery('[data-clear-history-toggle]').on('click', function() {
|
|
sessionStorage.clear();
|
|
location.reload();
|
|
return false;
|
|
});
|
|
jQuery('[data-search-toggle]').on('click', function() {
|
|
if (sidebarStatus == 'closed') {
|
|
jQuery('[data-sidebar-toggle]').trigger('click');
|
|
jQuery(document.body).removeClass('searchbox-hidden');
|
|
searchStatus = 'open';
|
|
|
|
return false;
|
|
}
|
|
|
|
jQuery(document.body).toggleClass('searchbox-hidden');
|
|
searchStatus = (jQuery(document.body).hasClass('searchbox-hidden') ? 'closed' : 'open');
|
|
|
|
return false;
|
|
});
|
|
|
|
var ajax;
|
|
jQuery('[data-search-input]').on('input', function() {
|
|
var input = jQuery(this),
|
|
value = input.val(),
|
|
items = jQuery('[data-nav-id]');
|
|
items.removeClass('search-match');
|
|
if (!value.length) {
|
|
$('ul.topics').removeClass('searched');
|
|
items.css('display', 'block');
|
|
sessionStorage.removeItem('search-value');
|
|
$(".highlightable").unhighlight({ element: 'mark' })
|
|
return;
|
|
}
|
|
|
|
sessionStorage.setItem('search-value', value);
|
|
$(".highlightable").unhighlight({ element: 'mark' }).highlight(value, { element: 'mark' });
|
|
|
|
if (ajax && ajax.abort) ajax.abort();
|
|
|
|
jQuery('[data-search-clear]').on('click', function() {
|
|
jQuery('[data-search-input]').val('').trigger('input');
|
|
sessionStorage.removeItem('search-input');
|
|
$(".highlightable").unhighlight({ element: 'mark' })
|
|
});
|
|
});
|
|
|
|
$.expr[":"].contains = $.expr.createPseudo(function(arg) {
|
|
return function( elem ) {
|
|
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
|
|
};
|
|
});
|
|
|
|
if (sessionStorage.getItem('search-value')) {
|
|
var searchValue = sessionStorage.getItem('search-value')
|
|
$(document.body).removeClass('searchbox-hidden');
|
|
$('[data-search-input]').val(searchValue);
|
|
$('[data-search-input]').trigger('input');
|
|
var searchedElem = $('#body-inner').find(':contains(' + searchValue + ')').get(0);
|
|
if (searchedElem) {
|
|
searchedElem.scrollIntoView(true);
|
|
var scrolledY = window.scrollY;
|
|
if(scrolledY){
|
|
window.scroll(0, scrolledY - 125);
|
|
}
|
|
}
|
|
}
|
|
|
|
// clipboard
|
|
var clipInit = false;
|
|
$('code').each(function() {
|
|
var code = $(this),
|
|
text = code.text();
|
|
|
|
if (text.length > 5) {
|
|
if (!clipInit) {
|
|
var text, clip = new Clipboard('.copy-to-clipboard', {
|
|
text: function(trigger) {
|
|
text = $(trigger).prev('code').text();
|
|
return text.replace(/^\$\s/gm, '');
|
|
}
|
|
});
|
|
|
|
var inPre;
|
|
clip.on('success', function(e) {
|
|
e.clearSelection();
|
|
inPre = $(e.trigger).parent().prop('tagName') == 'PRE';
|
|
$(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));
|
|
});
|
|
|
|
clip.on('error', function(e) {
|
|
inPre = $(e.trigger).parent().prop('tagName') == 'PRE';
|
|
$(e.trigger).attr('aria-label', fallbackMessage(e.action)).addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));
|
|
$(document).one('copy', function(){
|
|
$(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));
|
|
});
|
|
});
|
|
|
|
clipInit = true;
|
|
}
|
|
|
|
code.after('<span class="copy-to-clipboard" title="Copy to clipboard" />');
|
|
code.next('.copy-to-clipboard').on('mouseleave', function() {
|
|
$(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w');
|
|
});
|
|
}
|
|
});
|
|
|
|
// allow keyboard control for prev/next links
|
|
jQuery(function() {
|
|
jQuery('.nav-prev').click(function(){
|
|
location.href = jQuery(this).attr('href');
|
|
});
|
|
jQuery('.nav-next').click(function() {
|
|
location.href = jQuery(this).attr('href');
|
|
});
|
|
});
|
|
|
|
jQuery('input').keydown(function (e) {
|
|
// left and right arrow keys
|
|
if (e.which == '37' || e.which == '39') {
|
|
e.stopPropagation();
|
|
}
|
|
});
|
|
|
|
jQuery(document).keydown(function(e) {
|
|
// prev links - left arrow key
|
|
if(e.which == '37') {
|
|
jQuery('.nav.nav-prev').click();
|
|
}
|
|
|
|
// next links - right arrow key
|
|
if(e.which == '39') {
|
|
jQuery('.nav.nav-next').click();
|
|
}
|
|
});
|
|
|
|
$('#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);
|
|
|
|
});
|
|
|
|
jQuery(window).on('load', function() {
|
|
|
|
function adjustForScrollbar() {
|
|
if ((parseInt(jQuery('#body-inner').height()) + 83) >= jQuery('#body').height()) {
|
|
jQuery('.nav.nav-next').css({ 'margin-right': getScrollBarWidth() });
|
|
} else {
|
|
jQuery('.nav.nav-next').css({ 'margin-right': 0 });
|
|
}
|
|
}
|
|
|
|
// adjust sidebar for scrollbar
|
|
adjustForScrollbar();
|
|
|
|
jQuery(window).smartresize(function() {
|
|
adjustForScrollbar();
|
|
});
|
|
|
|
// store this page in session
|
|
sessionStorage.setItem(jQuery('body').data('url'), 1);
|
|
|
|
// loop through the sessionStorage and see if something should be marked as visited
|
|
for (var url in sessionStorage) {
|
|
if (sessionStorage.getItem(url) == 1) jQuery('[data-nav-id="' + url + '"]').addClass('visited');
|
|
}
|
|
|
|
|
|
$(".highlightable").highlight(sessionStorage.getItem('search-value'), { element: 'mark' });
|
|
});
|
|
|
|
$(function() {
|
|
$('a[rel="lightbox"]').featherlight({
|
|
root: 'section#body'
|
|
});
|
|
});
|
|
|
|
jQuery.extend({
|
|
highlight: function(node, re, nodeName, className) {
|
|
if (node.nodeType === 3) {
|
|
var match = node.data.match(re);
|
|
if (match) {
|
|
var highlight = document.createElement(nodeName || 'span');
|
|
highlight.className = className || 'highlight';
|
|
var wordNode = node.splitText(match.index);
|
|
wordNode.splitText(match[0].length);
|
|
var wordClone = wordNode.cloneNode(true);
|
|
highlight.appendChild(wordClone);
|
|
wordNode.parentNode.replaceChild(highlight, wordNode);
|
|
return 1; //skip added node in parent
|
|
}
|
|
} else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
|
|
!/(script|style)/i.test(node.tagName) && // ignore script and style nodes
|
|
!(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
|
|
for (var i = 0; i < node.childNodes.length; i++) {
|
|
i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
});
|
|
|
|
jQuery.fn.unhighlight = function(options) {
|
|
var settings = {
|
|
className: 'highlight',
|
|
element: 'span'
|
|
};
|
|
jQuery.extend(settings, options);
|
|
|
|
return this.find(settings.element + "." + settings.className).each(function() {
|
|
var parent = this.parentNode;
|
|
parent.replaceChild(this.firstChild, this);
|
|
parent.normalize();
|
|
}).end();
|
|
};
|
|
|
|
jQuery.fn.highlight = function(words, options) {
|
|
var settings = {
|
|
className: 'highlight',
|
|
element: 'span',
|
|
caseSensitive: false,
|
|
wordsOnly: false
|
|
};
|
|
jQuery.extend(settings, options);
|
|
|
|
if (!words) { return; }
|
|
|
|
if (words.constructor === String) {
|
|
words = [words];
|
|
}
|
|
words = jQuery.grep(words, function(word, i) {
|
|
return word != '';
|
|
});
|
|
words = jQuery.map(words, function(word, i) {
|
|
return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
|
});
|
|
if (words.length == 0) { return this; }
|
|
;
|
|
|
|
var flag = settings.caseSensitive ? "" : "i";
|
|
var pattern = "(" + words.join("|") + ")";
|
|
if (settings.wordsOnly) {
|
|
pattern = "\\b" + pattern + "\\b";
|
|
}
|
|
var re = new RegExp(pattern, flag);
|
|
|
|
return this.each(function() {
|
|
jQuery.highlight(this, re, settings.element, settings.className);
|
|
});
|
|
};
|