2021-06-01 04:05:32 +00:00
( function ( jtd , undefined ) {
// Event handling
jtd . addEvent = function ( el , type , handler ) {
if ( el . attachEvent ) el . attachEvent ( 'on' + type , handler ); else el . addEventListener ( type , handler );
}
jtd . removeEvent = function ( el , type , handler ) {
if ( el . detachEvent ) el . detachEvent ( 'on' + type , handler ); else el . removeEventListener ( type , handler );
}
jtd . onReady = function ( ready ) {
// in case the document is already rendered
if ( document . readyState != 'loading' ) ready ();
// modern browsers
else if ( document . addEventListener ) document . addEventListener ( 'DOMContentLoaded' , ready );
// IE <= 8
else document . attachEvent ( 'onreadystatechange' , function (){
if ( document . readyState == 'complete' ) ready ();
});
}
// Show/hide mobile menu
function initNav () {
jtd . addEvent ( document , 'click' , function ( e ){
var target = e . target ;
while ( target && ! ( target . classList && target . classList . contains ( 'nav-list-expander' ))) {
target = target . parentNode ;
}
if ( target ) {
e . preventDefault ();
2023-09-30 09:20:33 +00:00
target . ariaPressed = target . parentNode . classList . toggle ( 'active' );
2021-06-01 04:05:32 +00:00
}
});
const siteNav = document . getElementById ( 'site-nav' );
const mainHeader = document . getElementById ( 'main-header' );
const menuButton = document . getElementById ( 'menu-button' );
2023-08-22 02:01:28 +00:00
2023-10-02 00:50:31 +00:00
disableHeadStyleSheets ();
2021-06-01 04:05:32 +00:00
jtd . addEvent ( menuButton , 'click' , function ( e ){
e . preventDefault ();
if ( menuButton . classList . toggle ( 'nav-open' )) {
siteNav . classList . add ( 'nav-open' );
mainHeader . classList . add ( 'nav-open' );
2023-08-09 00:25:41 +00:00
menuButton . ariaPressed = true ;
2021-06-01 04:05:32 +00:00
} else {
siteNav . classList . remove ( 'nav-open' );
mainHeader . classList . remove ( 'nav-open' );
2023-08-09 00:25:41 +00:00
menuButton . ariaPressed = false ;
2021-06-01 04:05:32 +00:00
}
});
}
2023-08-22 02:01:28 +00:00
2023-10-02 00:50:31 +00:00
// The <head> element is assumed to include the following stylesheets:
// 0. a <link> to /assets/css/just-the-docs-default.css
// 1. a <link> to /assets/css/just-the-docs-head-nav.css
// 2. a <style> containing the result of _includes/css/activation.scss.liquid.
// It also includes any styles provided by users in _includes/head_custom.html.
// Stylesheet 2 may be missing (compression can remove empty <style> elements)
// so disableHeadStyleSheet() needs to access it by its id.
2023-08-22 02:01:28 +00:00
2023-10-02 00:50:31 +00:00
function disableHeadStyleSheets () {
document . styleSheets [ 1 ]. disabled = true ;
const activation = document . getElementById ( 'jtd-nav-activation' );
if ( activation ) {
activation . disabled = true ;
2023-09-30 09:20:33 +00:00
}
2023-08-22 02:01:28 +00:00
}
2021-06-01 04:05:32 +00:00
// Site search
function initSearch () {
var request = new XMLHttpRequest ();
2021-07-03 01:31:59 +00:00
request . open ( 'GET' , '/sfall/assets/js/search-data.json' , true );
2021-06-01 04:05:32 +00:00
request . onload = function (){
if ( request . status >= 200 && request . status < 400 ) {
var docs = JSON . parse ( request . responseText );
2023-01-22 01:15:27 +00:00
2021-06-01 04:05:32 +00:00
lunr . tokenizer . separator = /[\s\-/]+/
var index = lunr ( function (){
this . ref ( 'id' );
this . field ( 'title' , { boost : 200 });
this . field ( 'content' , { boost : 2 });
this . field ( 'relUrl' );
this . metadataWhitelist = [ 'position' ]
for ( var i in docs ) {
2023-01-22 01:15:27 +00:00
2021-06-01 04:05:32 +00:00
this . add ({
id : i ,
title : docs [ i ]. title ,
content : docs [ i ]. content ,
relUrl : docs [ i ]. relUrl
});
}
});
searchLoaded ( index , docs );
} else {
console . log ( 'Error loading ajax request. Request status:' + request . status );
}
};
request . onerror = function (){
console . log ( 'There was a connection error' );
};
request . send ();
}
function searchLoaded ( index , docs ) {
var index = index ;
var docs = docs ;
var searchInput = document . getElementById ( 'search-input' );
var searchResults = document . getElementById ( 'search-results' );
var mainHeader = document . getElementById ( 'main-header' );
var currentInput ;
var currentSearchIndex = 0 ;
function showSearch () {
document . documentElement . classList . add ( 'search-active' );
}
function hideSearch () {
document . documentElement . classList . remove ( 'search-active' );
}
function update () {
currentSearchIndex ++ ;
var input = searchInput . value ;
if ( input === '' ) {
hideSearch ();
} else {
showSearch ();
// scroll search input into view, workaround for iOS Safari
window . scroll ( 0 , - 1 );
setTimeout ( function (){ window . scroll ( 0 , 0 ); }, 0 );
}
if ( input === currentInput ) {
return ;
}
currentInput = input ;
searchResults . innerHTML = '' ;
if ( input === '' ) {
return ;
}
var results = index . query ( function ( query ) {
var tokens = lunr . tokenizer ( input )
query . term ( tokens , {
boost : 10
});
query . term ( tokens , {
wildcard : lunr . Query . wildcard . TRAILING
});
});
if (( results . length == 0 ) && ( input . length > 2 )) {
var tokens = lunr . tokenizer ( input ). filter ( function ( token , i ) {
return token . str . length < 20 ;
})
if ( tokens . length > 0 ) {
results = index . query ( function ( query ) {
query . term ( tokens , {
editDistance : Math . round ( Math . sqrt ( input . length / 2 - 1 ))
});
});
}
}
if ( results . length == 0 ) {
var noResultsDiv = document . createElement ( 'div' );
noResultsDiv . classList . add ( 'search-no-result' );
noResultsDiv . innerText = 'No results found' ;
searchResults . appendChild ( noResultsDiv );
} else {
var resultsList = document . createElement ( 'ul' );
resultsList . classList . add ( 'search-results-list' );
searchResults . appendChild ( resultsList );
addResults ( resultsList , results , 0 , 10 , 100 , currentSearchIndex );
}
function addResults ( resultsList , results , start , batchSize , batchMillis , searchIndex ) {
if ( searchIndex != currentSearchIndex ) {
return ;
}
for ( var i = start ; i < ( start + batchSize ); i ++ ) {
if ( i == results . length ) {
return ;
}
addResult ( resultsList , results [ i ]);
}
setTimeout ( function () {
addResults ( resultsList , results , start + batchSize , batchSize , batchMillis , searchIndex );
}, batchMillis );
}
function addResult ( resultsList , result ) {
var doc = docs [ result . ref ];
var resultsListItem = document . createElement ( 'li' );
resultsListItem . classList . add ( 'search-results-list-item' );
resultsList . appendChild ( resultsListItem );
var resultLink = document . createElement ( 'a' );
resultLink . classList . add ( 'search-result' );
resultLink . setAttribute ( 'href' , doc . url );
resultsListItem . appendChild ( resultLink );
var resultTitle = document . createElement ( 'div' );
resultTitle . classList . add ( 'search-result-title' );
resultLink . appendChild ( resultTitle );
2023-01-22 01:15:27 +00:00
// note: the SVG svg-doc is only loaded as a Jekyll include if site.search_enabled is true; see _includes/icons/icons.html
2021-06-01 04:05:32 +00:00
var resultDoc = document . createElement ( 'div' );
resultDoc . classList . add ( 'search-result-doc' );
resultDoc . innerHTML = '<svg viewBox="0 0 24 24" class="search-result-icon"><use xlink:href="#svg-doc"></use></svg>' ;
resultTitle . appendChild ( resultDoc );
var resultDocTitle = document . createElement ( 'div' );
resultDocTitle . classList . add ( 'search-result-doc-title' );
resultDocTitle . innerHTML = doc . doc ;
resultDoc . appendChild ( resultDocTitle );
var resultDocOrSection = resultDocTitle ;
if ( doc . doc != doc . title ) {
resultDoc . classList . add ( 'search-result-doc-parent' );
var resultSection = document . createElement ( 'div' );
resultSection . classList . add ( 'search-result-section' );
resultSection . innerHTML = doc . title ;
resultTitle . appendChild ( resultSection );
resultDocOrSection = resultSection ;
}
var metadata = result . matchData . metadata ;
var titlePositions = [];
var contentPositions = [];
for ( var j in metadata ) {
var meta = metadata [ j ];
if ( meta . title ) {
var positions = meta . title . position ;
for ( var k in positions ) {
titlePositions . push ( positions [ k ]);
}
}
if ( meta . content ) {
var positions = meta . content . position ;
for ( var k in positions ) {
var position = positions [ k ];
var previewStart = position [ 0 ];
var previewEnd = position [ 0 ] + position [ 1 ];
var ellipsesBefore = true ;
var ellipsesAfter = true ;
for ( var k = 0 ; k < 5 ; k ++ ) {
var nextSpace = doc . content . lastIndexOf ( ' ' , previewStart - 2 );
var nextDot = doc . content . lastIndexOf ( '. ' , previewStart - 2 );
if (( nextDot >= 0 ) && ( nextDot > nextSpace )) {
previewStart = nextDot + 1 ;
ellipsesBefore = false ;
break ;
}
if ( nextSpace < 0 ) {
previewStart = 0 ;
ellipsesBefore = false ;
break ;
}
previewStart = nextSpace + 1 ;
}
for ( var k = 0 ; k < 10 ; k ++ ) {
var nextSpace = doc . content . indexOf ( ' ' , previewEnd + 1 );
var nextDot = doc . content . indexOf ( '. ' , previewEnd + 1 );
if (( nextDot >= 0 ) && ( nextDot < nextSpace )) {
previewEnd = nextDot ;
ellipsesAfter = false ;
break ;
}
if ( nextSpace < 0 ) {
previewEnd = doc . content . length ;
ellipsesAfter = false ;
break ;
}
previewEnd = nextSpace ;
}
contentPositions . push ({
highlight : position ,
previewStart : previewStart , previewEnd : previewEnd ,
ellipsesBefore : ellipsesBefore , ellipsesAfter : ellipsesAfter
});
}
}
}
if ( titlePositions . length > 0 ) {
titlePositions . sort ( function ( p1 , p2 ){ return p1 [ 0 ] - p2 [ 0 ] });
resultDocOrSection . innerHTML = '' ;
addHighlightedText ( resultDocOrSection , doc . title , 0 , doc . title . length , titlePositions );
}
if ( contentPositions . length > 0 ) {
contentPositions . sort ( function ( p1 , p2 ){ return p1 . highlight [ 0 ] - p2 . highlight [ 0 ] });
var contentPosition = contentPositions [ 0 ];
var previewPosition = {
highlight : [ contentPosition . highlight ],
previewStart : contentPosition . previewStart , previewEnd : contentPosition . previewEnd ,
ellipsesBefore : contentPosition . ellipsesBefore , ellipsesAfter : contentPosition . ellipsesAfter
};
var previewPositions = [ previewPosition ];
for ( var j = 1 ; j < contentPositions . length ; j ++ ) {
contentPosition = contentPositions [ j ];
if ( previewPosition . previewEnd < contentPosition . previewStart ) {
previewPosition = {
highlight : [ contentPosition . highlight ],
previewStart : contentPosition . previewStart , previewEnd : contentPosition . previewEnd ,
ellipsesBefore : contentPosition . ellipsesBefore , ellipsesAfter : contentPosition . ellipsesAfter
}
previewPositions . push ( previewPosition );
} else {
previewPosition . highlight . push ( contentPosition . highlight );
previewPosition . previewEnd = contentPosition . previewEnd ;
previewPosition . ellipsesAfter = contentPosition . ellipsesAfter ;
}
}
var resultPreviews = document . createElement ( 'div' );
resultPreviews . classList . add ( 'search-result-previews' );
resultLink . appendChild ( resultPreviews );
var content = doc . content ;
for ( var j = 0 ; j < Math . min ( previewPositions . length , 3 ); j ++ ) {
var position = previewPositions [ j ];
var resultPreview = document . createElement ( 'div' );
resultPreview . classList . add ( 'search-result-preview' );
resultPreviews . appendChild ( resultPreview );
if ( position . ellipsesBefore ) {
resultPreview . appendChild ( document . createTextNode ( '... ' ));
}
addHighlightedText ( resultPreview , content , position . previewStart , position . previewEnd , position . highlight );
if ( position . ellipsesAfter ) {
resultPreview . appendChild ( document . createTextNode ( ' ...' ));
}
}
}
var resultRelUrl = document . createElement ( 'span' );
resultRelUrl . classList . add ( 'search-result-rel-url' );
resultRelUrl . innerText = doc . relUrl ;
resultTitle . appendChild ( resultRelUrl );
}
function addHighlightedText ( parent , text , start , end , positions ) {
var index = start ;
for ( var i in positions ) {
var position = positions [ i ];
var span = document . createElement ( 'span' );
span . innerHTML = text . substring ( index , position [ 0 ]);
parent . appendChild ( span );
index = position [ 0 ] + position [ 1 ];
var highlight = document . createElement ( 'span' );
highlight . classList . add ( 'search-result-highlight' );
highlight . innerHTML = text . substring ( position [ 0 ], index );
parent . appendChild ( highlight );
}
var span = document . createElement ( 'span' );
span . innerHTML = text . substring ( index , end );
parent . appendChild ( span );
}
}
jtd . addEvent ( searchInput , 'focus' , function (){
setTimeout ( update , 0 );
});
jtd . addEvent ( searchInput , 'keyup' , function ( e ){
switch ( e . keyCode ) {
case 27 : // When esc key is pressed, hide the results and clear the field
searchInput . value = '' ;
break ;
case 38 : // arrow up
case 40 : // arrow down
case 13 : // enter
e . preventDefault ();
return ;
}
update ();
});
jtd . addEvent ( searchInput , 'keydown' , function ( e ){
switch ( e . keyCode ) {
case 38 : // arrow up
e . preventDefault ();
var active = document . querySelector ( '.search-result.active' );
if ( active ) {
active . classList . remove ( 'active' );
if ( active . parentElement . previousSibling ) {
var previous = active . parentElement . previousSibling . querySelector ( '.search-result' );
previous . classList . add ( 'active' );
}
}
return ;
case 40 : // arrow down
e . preventDefault ();
var active = document . querySelector ( '.search-result.active' );
if ( active ) {
if ( active . parentElement . nextSibling ) {
var next = active . parentElement . nextSibling . querySelector ( '.search-result' );
active . classList . remove ( 'active' );
next . classList . add ( 'active' );
}
} else {
var next = document . querySelector ( '.search-result' );
if ( next ) {
next . classList . add ( 'active' );
}
}
return ;
case 13 : // enter
e . preventDefault ();
var active = document . querySelector ( '.search-result.active' );
if ( active ) {
active . click ();
} else {
var first = document . querySelector ( '.search-result' );
if ( first ) {
first . click ();
}
}
return ;
}
});
jtd . addEvent ( document , 'click' , function ( e ){
if ( e . target != searchInput ) {
hideSearch ();
}
});
}
// Switch theme
jtd . getTheme = function () {
var cssFileHref = document . querySelector ( '[rel="stylesheet"]' ). getAttribute ( 'href' );
return cssFileHref . substring ( cssFileHref . lastIndexOf ( '-' ) + 1 , cssFileHref . length - 4 );
}
jtd . setTheme = function ( theme ) {
var cssFile = document . querySelector ( '[rel="stylesheet"]' );
2021-07-03 01:31:59 +00:00
cssFile . setAttribute ( 'href' , '/sfall/assets/css/just-the-docs-' + theme + '.css' );
2021-06-01 04:05:32 +00:00
}
2023-08-22 02:01:28 +00:00
// Note: pathname can have a trailing slash on a local jekyll server
// and not have the slash on GitHub Pages
function navLink () {
var href = document . location . pathname ;
if ( href . endsWith ( '/' ) && href != '/' ) {
href = href . slice ( 0 , - 1 );
}
return document . getElementById ( 'site-nav' ). querySelector ( 'a[href="' + href + '"], a[href="' + href + '/"]' );
}
2022-08-27 13:47:30 +00:00
// Scroll site-nav to ensure the link to the current page is visible
function scrollNav () {
2023-08-22 02:01:28 +00:00
const targetLink = navLink ();
if ( targetLink ) {
2022-08-27 13:47:30 +00:00
const rect = targetLink . getBoundingClientRect ();
2023-08-22 02:01:28 +00:00
document . getElementById ( 'site-nav' ). scrollBy ( 0 , rect . top - 3 * rect . height );
}
}
// Find the nav-list-link that refers to the current page
2023-09-30 09:20:33 +00:00
// then make it and all enclosing nav-list-item elements active.
2023-08-22 02:01:28 +00:00
function activateNav () {
var target = navLink ();
if ( target ) {
target . classList . toggle ( 'active' , true );
2023-09-30 09:20:33 +00:00
target . removeAttribute ( 'href' );
2023-08-22 02:01:28 +00:00
}
while ( target ) {
while ( target && ! ( target . classList && target . classList . contains ( 'nav-list-item' ))) {
target = target . parentNode ;
}
if ( target ) {
target . classList . toggle ( 'active' , true );
target = target . parentNode ;
}
}
2022-08-27 13:47:30 +00:00
}
2021-06-01 04:05:32 +00:00
// Document ready
jtd . onReady ( function (){
initNav ();
initSearch ();
2023-08-22 02:01:28 +00:00
activateNav ();
2022-08-27 13:47:30 +00:00
scrollNav ();
2021-06-01 04:05:32 +00:00
});
2023-01-22 01:15:27 +00:00
// Copy button on code
jtd . onReady ( function (){
2023-08-09 00:25:41 +00:00
if ( ! window . isSecureContext ) {
console . log ( 'Window does not have a secure context, therefore code clipboard copy functionality will not be available. For more details see https://web.dev/async-clipboard/#security-and-permissions' );
return ;
}
2023-03-20 02:05:56 +00:00
var codeBlocks = document . querySelectorAll ( 'div.highlighter-rouge, div.listingblock > div.content, figure.highlight' );
2023-01-22 01:15:27 +00:00
// note: the SVG svg-copied and svg-copy is only loaded as a Jekyll include if site.enable_copy_code_button is true; see _includes/icons/icons.html
var svgCopied = '<svg viewBox="0 0 24 24" class="copy-icon"><use xlink:href="#svg-copied"></use></svg>' ;
var svgCopy = '<svg viewBox="0 0 24 24" class="copy-icon"><use xlink:href="#svg-copy"></use></svg>' ;
codeBlocks . forEach ( codeBlock => {
var copyButton = document . createElement ( 'button' );
var timeout = null ;
copyButton . type = 'button' ;
copyButton . ariaLabel = 'Copy code to clipboard' ;
copyButton . innerHTML = svgCopy ;
codeBlock . append ( copyButton );
copyButton . addEventListener ( 'click' , function () {
if ( timeout === null ) {
2023-03-20 02:05:56 +00:00
var code = ( codeBlock . querySelector ( 'pre:not(.lineno, .highlight)' ) || codeBlock . querySelector ( 'code' )). innerText ;
2023-01-22 01:15:27 +00:00
window . navigator . clipboard . writeText ( code );
copyButton . innerHTML = svgCopied ;
var timeoutSetting = 4000 ;
timeout = setTimeout ( function () {
copyButton . innerHTML = svgCopy ;
timeout = null ;
}, timeoutSetting );
}
});
});
});
2021-06-01 04:05:32 +00:00
})( window . jtd = window . jtd || {});