/*
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]]
*/