/* TabContentController Gadget - JS Initialisation, Setup, Events See detailed documentation in Dev/mediawiki deferrable:YES -- This is a standalone gadget / augmentation */ /* See Dev/mediawiki for documentation */ /* Important definitions for Devs ------------------------------ controller = container where the navigation and the content-container navigaton = the mininav container for the tab item list tabContainer = the li element housing the tab tab = the link element to navigate to the corresponding content item sectionList = the collection of the actual content (section) for each tab section = the actual content for an individual tab content = meta concept meaning both section and the corresponding tab */ (function() { let doScroll = true; function chooseTab( contentId ) { let selector = `[data-tcc-contentId="${contentId}"]`; $( '.tcc-tab' + selector ).parent().siblings().children().removeClass('active'); $( '.tcc-section' + selector ).siblings().removeClass('active'); $( selector + ':not(.is-link)' ).addClass('active'); } // --------------------------------------- // jQuery extension : tabContentController $.fn.tabContentController = function(action) { // Only allow 'init' or 'select' at the moment (extendable later) if( action != 'init' && action != 'select' ) return; /* SELECT */ if( action == 'select' ) { let collection = $(this).filter('.tcc-tab, .tcc-section'); collection.each( ( index, elem ) => chooseTab( $(elem).attr('data-tcc-contentid') ) ); return; } /* INIT */ // Traversing over the given collection let collection = $(this).filter('.tab-content-controller'); collection.each( function() { // Prevent double initialization if( $(this).hasClass('js-fully-loaded') ) return; // Setup // For linked Controllers : ID of the tab controller group let tcLinkedGroupId = $(this).attr( 'data-tcc-linkid' ); // If no link id then "group" is just this controller let tcLinkedGroup = tcLinkedGroupId ? collection.filter( (index,element) => $(element).attr( 'data-tcc-linkid' ) == tcLinkedGroupId ) : $(this); tcLinkedGroup.each( function() { // Apply dark feature via tcc-dark class if( $(this).hasClass('tcc-dark') ) $(this).find('> .mininav').addClass('mn-dark'); $(this).find('> .mininav').append('') let tabList = $(this).find('.mininav > ul'); $(this).find('> .tcc-content > .tcc-section').each( function( index, element ) { let section = $(this); let sectionHeadlineId = section.find('.tcc-title .mw-headline').attr('id'); // Create tab. All are links but disabled. If only link given in section then create direct link-tab (with .is-link class) let tabContainer = $( `
  • ` ); // If the section's content has exactly 1 child, that is a p, and that p has 1 child (and no text nodes) that is an a. Whitespaces are trimmed for caparison if( section.find('> .tcc-content > p > a').length == 1 && section.find('> .tcc-content > p').text().trim() == section.find('> .tcc-content > p > a').text() ) { tabContainer = $( `
  • ` ); section.addClass('is-link'); } let tab = tabContainer.children().first(); tab.addClass( 'tcc-tab' ); tab.text( section.find('> .tcc-title .mw-headline').text() ); if( section.hasClass('active') ) tab.addClass('active'); if( section.find('> .tcc-image img').length > 0 ) tab.prepend( section.find('> .tcc-image img') ); // Creating or fetching contentId (from linked Controller) and applying it to tab and section let contentId = 'id-' + Math.random().toString().substr(2); let existingContent = $(`[data-tcc-linkid="${tcLinkedGroupId}"].js-fully-loaded`); if( existingContent.length > 0 ) contentId = existingContent.eq(0).find('> .tcc-content > .tcc-section').eq( index ).attr('data-tcc-contentId'); tab.attr( 'data-tcc-contentId', contentId ); section.attr( 'data-tcc-contentId', contentId ); tabList.append( tabContainer ); // Event : Click Tab if( ! tab.hasClass('is-link') ) tabContainer.on( 'click', () => { doScroll = false; }); // Register Tab Controller with Hash Controller mwDev.tools.hashControl.register( sectionHeadlineId, function() { let selectedHeadline = $( `.tab-content-controller .tcc-title .mw-headline[id="${mwDev.tools.hashControl.get()}"]` ); // If section with hash as headline ID is found open this section/tab and all parent sections/tabs if( selectedHeadline.length > 0 ) { selectedHeadline.parents('.tcc-section').each( function() { chooseTab( $(this).attr('data-tcc-contentid') ); }); // And scroll to the position of the direct content controller parent in the document if( doScroll ) { $('html, body').animate( { scrollTop: selectedHeadline.parents('.tab-content-controller')[0].getBoundingClientRect().top + window.pageYOffset - 70 }, 500 ); doScroll = true; } } }, true ); }); // If no element is active make the first one active that is not a link if( ! $(this).find('.tcc-section').hasClass('active') ) { chooseTab( tabList.find('a:not(.is-link)').eq(0).attr('data-tcc-contentId') ); } $(this).addClass('js-fully-loaded'); }); }); } // ------------------- // Page Initialization // Automatic initialization for all tab controllers $('.tab-content-controller').tabContentController('init'); // Event : Click TOC if( $( '#toc' ).length ) $( '#toc a' ).on( 'click', () => { doScroll = true; }); })(); /* [[Category:MultiWiki]] */