@@ -653,6 +653,99 @@ window.document.addEventListener("DOMContentLoaded", function (_event) {
653653 highlightReaderToggle ( isReaderMode ( ) ) ;
654654} ) ;
655655
656+ // grouped tabsets
657+ window . addEventListener ( "pageshow" , ( _event ) => {
658+ function getTabSettings ( ) {
659+ const data = localStorage . getItem ( "quarto-persistent-tabsets-data" ) ;
660+ if ( ! data ) {
661+ localStorage . setItem ( "quarto-persistent-tabsets-data" , "{}" ) ;
662+ return { } ;
663+ }
664+ if ( data ) {
665+ return JSON . parse ( data ) ;
666+ }
667+ }
668+
669+ function setTabSettings ( data ) {
670+ localStorage . setItem (
671+ "quarto-persistent-tabsets-data" ,
672+ JSON . stringify ( data )
673+ ) ;
674+ }
675+
676+ function setTabState ( groupName , groupValue ) {
677+ const data = getTabSettings ( ) ;
678+ data [ groupName ] = groupValue ;
679+ setTabSettings ( data ) ;
680+ }
681+
682+ function toggleTab ( tab , active ) {
683+ const tabPanelId = tab . getAttribute ( "aria-controls" ) ;
684+ const tabPanel = document . getElementById ( tabPanelId ) ;
685+ if ( active ) {
686+ tab . classList . add ( "active" ) ;
687+ tabPanel . classList . add ( "active" ) ;
688+ } else {
689+ tab . classList . remove ( "active" ) ;
690+ tabPanel . classList . remove ( "active" ) ;
691+ }
692+ }
693+
694+ function toggleAll ( selectedGroup , selectorsToSync ) {
695+ for ( const [ thisGroup , tabs ] of Object . entries ( selectorsToSync ) ) {
696+ const active = selectedGroup === thisGroup ;
697+ for ( const tab of tabs ) {
698+ toggleTab ( tab , active ) ;
699+ }
700+ }
701+ }
702+
703+ function findSelectorsToSyncByLanguage ( ) {
704+ const result = { } ;
705+ const tabs = Array . from (
706+ document . querySelectorAll ( `div[data-group] a[id^='tabset-']` )
707+ ) ;
708+ for ( const item of tabs ) {
709+ const div = item . parentElement . parentElement . parentElement ;
710+ const group = div . getAttribute ( "data-group" ) ;
711+ if ( ! result [ group ] ) {
712+ result [ group ] = { } ;
713+ }
714+ const selectorsToSync = result [ group ] ;
715+ const value = item . innerHTML ;
716+ if ( ! selectorsToSync [ value ] ) {
717+ selectorsToSync [ value ] = [ ] ;
718+ }
719+ selectorsToSync [ value ] . push ( item ) ;
720+ }
721+ return result ;
722+ }
723+
724+ function setupSelectorSync ( ) {
725+ const selectorsToSync = findSelectorsToSyncByLanguage ( ) ;
726+ Object . entries ( selectorsToSync ) . forEach ( ( [ group , tabSetsByValue ] ) => {
727+ Object . entries ( tabSetsByValue ) . forEach ( ( [ value , items ] ) => {
728+ items . forEach ( ( item ) => {
729+ item . addEventListener ( "click" , ( _event ) => {
730+ setTabState ( group , value ) ;
731+ toggleAll ( value , selectorsToSync [ group ] ) ;
732+ } ) ;
733+ } ) ;
734+ } ) ;
735+ } ) ;
736+ return selectorsToSync ;
737+ }
738+
739+ const selectorsToSync = setupSelectorSync ( ) ;
740+ for ( const [ group , selectedName ] of Object . entries ( getTabSettings ( ) ) ) {
741+ const selectors = selectorsToSync [ group ] ;
742+ // it's possible that stale state gives us empty selections, so we explicitly check here.
743+ if ( selectors ) {
744+ toggleAll ( selectedName , selectors ) ;
745+ }
746+ }
747+ } ) ;
748+
656749function throttle ( func , wait ) {
657750 let waiting = false ;
658751 return function ( ) {
0 commit comments