@@ -28,102 +28,140 @@ function changeAbsoluteUrls() {
2828
2929// Hide Table of Content items whose related paragraph has the 'no-toc' class
3030function hideTocItems ( ) {
31- let toc_items = document . querySelectorAll ( '[aria-label="On this page"] .md-nav__item' )
32- toc_items . forEach ( item => {
33- let parag_id = item . querySelector ( 'a' ) . href . split ( '#' ) [ 1 ] ;
34- let parag = document . getElementById ( parag_id )
35- if ( parag && parag . classList . contains ( 'no-toc' ) ) {
36- item . style . display = 'none'
37- }
38- } )
31+ document . querySelectorAll ( '[aria-label="On this page"] .md-nav__item' ) . forEach ( item => {
32+ let paragraph_id = item . querySelector ( 'a' ) ?. href . split ( '#' ) [ 1 ] ;
33+ let paragraph = document . getElementById ( paragraph_id )
34+ if ( paragraph ?. classList . contains ( 'no-toc' ) ) {
35+ item . style . display = 'none'
36+ }
37+ } ) ;
3938}
4039
4140// Add buttons at the top of each table column (when hovered) to sort it
4241function sortTables ( ) {
43- let tables = document . querySelectorAll ( "article table:not([class])" ) ;
44- tables . forEach ( table => new Tablesort ( table ) ) ;
42+ if ( typeof Tablesort !== 'function' ) return ;
43+ document . querySelectorAll ( "article table:not([class])" ) . forEach ( table => new Tablesort ( table ) ) ;
4544}
4645
4746/*
4847 Add functionality to tabs
4948*/
5049function tabFunctionality ( ) {
51- let activeEl = document . activeElement ;
52- // If tab is activeElement (for example if a link points to an ID
53- // inside the tab content/button), make that tab active
54- if ( activeEl ?. parentElement . classList . contains ( "tabLabels" ) ) {
55- activeEl . blur ( ) ;
56- openTab ( activeEl ) ;
57- } else {
58- // Otherwise first check if a tab was open and a page reloaded, and open the same tab,
59- // otherwise open the tab that has the .activeTab class, otherwise open the first tab
60- document . querySelectorAll ( ".tabLabels" ) . forEach ( tabLabels => {
61- let label = tabLabels . getAttribute ( "label" ) ;
62- let tabID ;
63- if ( sessionStorage . getItem ( `tabs-label=${ label } ` ) ) {
64- tabID = document . getElementById ( tabID ) ? sessionStorage . getItem ( `tabs-label=${ label } ` ) : tabLabels . firstElementChild . id ;
65- } else if ( tabLabels . querySelector ( ".activeTab" ) ) {
66- tabID = tabLabels . querySelector ( ".activeTab" ) . id ;
67- } else {
68- tabID = tabLabels . firstElementChild . id ;
69- }
70- openTab ( document . getElementById ( tabID ) ) ;
71- } )
50+ // === Helpers ===
51+ function getTabIDFromStorage ( label ) {
52+ return sessionStorage . getItem ( `tabs-label=${ label } ` ) ?? null ;
7253 }
73- // Add click event to tab buttons
74- let tabButtons = document . querySelectorAll ( ".tabLabels > button" ) ;
75- tabButtons . forEach ( button => {
76- button . addEventListener ( 'click' , ( e ) => openTab ( e . currentTarget ) ) ;
77- } )
78-
79- // Add click event for links to tab IDs
80- document . querySelectorAll ( '[href^="#"]:not([class^="md"])' ) . forEach ( el => {
81- let href = el . getAttribute ( 'href' ) ;
82- let tabEl = document . getElementById ( href . slice ( 1 , ) )
83- if ( tabEl ?. parentElement . classList . contains ( "tabLabels" ) ) {
84- el . addEventListener ( "click" , ( e ) => openTab ( tabEl ) , false ) ;
85- }
86- } )
8754
88- function openTab ( tab ) {
89- let label = tab . parentElement . getAttribute ( 'label' ) ;
90- let index = Array . from ( tab . parentElement . children ) . indexOf ( tab ) + 1 ;
91- // Remove active classes from tabs with matching labels
92- document . querySelectorAll ( `.tabLabels[label="${ label } "] > .activeTab` ) . forEach ( elem => {
93- elem . classList . remove ( 'activeTab' ) ;
55+ function getTabButtons ( label , index = null ) {
56+ let query = `.tabLabels[label=${ label } ] > button`
57+ if ( ! ! index ) query += `:nth-child(${ index } )`
58+ return document . querySelectorAll ( query ) ;
59+ }
60+
61+ function getTabContents ( label ) {
62+ const tabContents = Array . from ( document . querySelectorAll ( '[tabcontentfor]' ) ) . filter ( el => {
63+ const targetId = el . getAttribute ( 'tabcontentfor' ) . split ( ' ' ) [ 0 ] ;
64+ const targetElement = document . getElementById ( targetId ) ;
65+ if ( ! targetElement ) return false ;
66+ const parent = targetElement . parentElement ;
67+ return parent && parent . getAttribute ( 'label' ) === label ;
68+ } ) ;
69+ return tabContents ;
70+ }
71+
72+ function isAssociatedWithActiveTab ( elem ) {
73+ // More than one tab can be associated with the same content block
74+ // (e.g. tabcontentfor="tab1 tab2")
75+ const tabIDs = elem . getAttribute ( 'tabcontentfor' ) . split ( ' ' ) ;
76+ return tabIDs . some ( tabID => {
77+ const tab = document . getElementById ( tabID ) ;
78+ return tab && tab . classList . contains ( 'activeTab' ) ;
79+ } ) ;
80+ }
81+
82+ function openTab ( tab , updateURL = true ) {
83+ // Get the label of the tab and its index
84+ const label = tab . parentElement . getAttribute ( 'label' ) ;
85+ const index = Array . from ( tab . parentElement . children ) . indexOf ( tab ) + 1 ;
86+
87+ // Deselect all tabs from tabLabels with the associated label
88+ getTabButtons ( label ) . forEach ( btn => btn . classList . remove ( 'activeTab' ) ) ;
89+
90+ // Hide content blocks for all tabLabels with the associated label
91+ getTabContents ( label ) . forEach ( elem => {
92+ elem . classList . remove ( 'activeContent' ) ;
9493 } ) ;
95- // Remove active classes from contents whose none of their associated tabs IDs are activeTabs
96- document . querySelectorAll ( '[tabcontentfor]' ) . forEach ( elem => {
97- let tabcontentfor = elem . getAttribute ( 'tabcontentfor' ) ;
98- if (
99- ! tabcontentfor . split ( ' ' ) . some ( tabID => {
100- return document . getElementById ( tabID ) . classList . contains ( 'activeTab' )
101- } )
102- ) {
103- elem . classList . remove ( 'activeTab' ) ;
94+
95+ // Select tabs with the same index of the select one in all tabLabels with the associated label
96+ getTabButtons ( label , index ) . forEach ( elem => {
97+ elem . classList . add ( 'activeTab' ) ;
98+ } ) ;
99+
100+ // Show content blocks associated with the specific tab
101+ getTabContents ( label ) . forEach ( elem => {
102+ if ( isAssociatedWithActiveTab ( elem ) ) {
103+ elem . classList . add ( 'activeContent' ) ;
104104 }
105105 } ) ;
106- // Add active classes to tab labels
107- document . querySelectorAll ( `.tabLabels[label=${ label } ] > :nth-child(${ index } )` )
108- . forEach ( button => { button . classList . add ( 'activeTab' ) } ) ;
109- // Add active classes to contents whose any associated tabs IDs are activeTabs
110- document . querySelectorAll ( '[tabcontentfor]' ) . forEach ( elem => {
111- let tabcontentfor = elem . getAttribute ( 'tabcontentfor' ) ;
112- if (
113- tabcontentfor . split ( ' ' ) . some ( tabID => {
114- return document . getElementById ( tabID ) . classList . contains ( 'activeTab' )
115- } )
116- ) {
117- elem . classList . add ( 'activeTab' ) ;
106+
107+ // Update URL anchor
108+ if ( updateURL ) {
109+ history . pushState ( null , null , `#${ tab . id } ` ) ;
110+ }
111+ // Save active tab in sessionStorage
112+ sessionStorage . setItem ( `tabs-label=${ label } ` , tab . id ) ;
113+ }
114+
115+ function getTabToOpen ( tabLabels ) {
116+ const label = tabLabels . getAttribute ( "label" ) ;
117+ const tabID = getTabIDFromStorage ( label ) ?? tabLabels ?. firstElementChild ?. id
118+ return document . getElementById ( tabID )
119+ }
120+
121+ function openTabsOnPageLoad ( ) {
122+ let tabsToOpen = [ ]
123+ let checkedLabel = null ;
124+ // Select tab associated with anchor if present
125+ const hash = window . location . hash ;
126+ if ( hash ) {
127+ const element = document . getElementById ( hash . slice ( 1 ) ) ;
128+ const tabLabelContainer = element ?. parentElement ;
129+ if ( tabLabelContainer ?. classList . contains ( "tabLabels" ) ) {
130+ checkedLabel = tabLabelContainer . getAttribute ( "label" ) ;
131+ tabsToOpen . push ( element ) ;
118132 }
133+ }
134+ // Find a tab to open for each .tabLabels that isn't already opened
135+ document . querySelectorAll ( `.tabLabels:not([label="${ checkedLabel } "])` )
136+ . forEach ( tabLabels => {
137+ const tab = getTabToOpen ( tabLabels ) ;
138+ if ( tab ) tabsToOpen . push ( tab ) ;
139+ } ) ;
140+ // Open tabs
141+ tabsToOpen . forEach ( tab => {
142+ openTab ( tab , false ) ;
119143 } ) ;
120- // Add tab ID hash to URL
121- history . pushState ( null , null , `#${ tab . id } ` ) ;
122- // Save active tab to sessionStorage
123- sessionStorage . setItem ( `tabs-label=${ label } ` , `${ tab . id } ` ) ;
124144 }
125- }
126145
146+ // Open tabs when the page is loaded
147+ openTabsOnPageLoad ( ) ;
148+
149+ // Open tabs when clicked on them
150+ // (Add click listeners to tab buttons)
151+ document . querySelectorAll ( ".tabLabels > button" ) . forEach ( button => {
152+ button . addEventListener ( "click" , e => openTab ( e . currentTarget ) ) ;
153+ } ) ;
154+
155+ // Open tabs when linked to with an anchor link in same page
156+ // (Add click listeners to anchor links pointing to tab IDs)
157+ document . querySelectorAll ( '[href^="#"]:not([class^="md"])' ) . forEach ( el => {
158+ const href = el . getAttribute ( 'href' ) ;
159+ const tabEl = document . getElementById ( href . slice ( 1 ) ) ;
160+ if ( tabEl ?. parentElement . classList . contains ( "tabLabels" ) ) {
161+ el . addEventListener ( "click" , ( ) => openTab ( tabEl ) , false ) ;
162+ }
163+ } ) ;
164+ }
127165
128166/*
129167 Make links that go to a different website 'external' by adding the
@@ -247,13 +285,16 @@ function toggleTerminalAnimations() {
247285*/
248286function fitText ( ) {
249287 const coeff = 0.9 ;
288+ const minSize = 8 ;
250289 function isOverflowing ( el ) {
251290 return el . scrollHeight > el . clientHeight || el . scrollWidth > el . clientWidth ;
252291 }
253292 function fit ( el ) {
254293 el . style . fontSize = null ;
255- while ( isOverflowing ( el ) ) {
256- el . style . fontSize = `${ parseFloat ( getComputedStyle ( el ) . fontSize ) * coeff } px` ;
294+ let size = parseFloat ( getComputedStyle ( el ) . fontSize ) ;
295+ while ( isOverflowing ( el ) && size > minSize ) {
296+ size *= coeff ;
297+ el . style . fontSize = `${ size } px` ;
257298 }
258299 }
259300 const observer = new ResizeObserver ( entries => {
@@ -294,5 +335,11 @@ function main() {
294335 makeCitationLinks ( ) ;
295336}
296337
297- // Run all functions
298- window . onload = ( ) => document$ . subscribe ( ( ) => main ( ) ) ;
338+ // Run all functions after every navigation event
339+ if ( typeof document$ !== 'undefined' ) {
340+ // The `document$` is a special observable enabled by the navigation.instant plugin (in mkdocs.yaml)
341+ document$ . subscribe ( ( ) => main ( ) ) ;
342+ } else {
343+ // If navigation.instant plugin is not active
344+ window . addEventListener ( 'load' , main ) ;
345+ }
0 commit comments