MediaWiki:Gadget-SidebarTOC.js

Revision as of 17:44, 22 February 2024 by Makko Oko (talk | contribs)
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
$(function(){
	if (!$('#toc').length) {
		return;
	}
	var i18n = {
		header: 'Contents',
		top: '(Top)'
	};

	// Remove the logic for collapsing and expanding the TOC
	$('<nav id="p-toc" class="vector-menu mw-portlet mw-portlet-toc vector-menu-portal portal" aria-labelledby="p-toc-label" role="navigation">').append(
	    $('<h3 id="p-toc-label" class="vector-menu-heading" tabindex="0">').append(
	        $('<span class="vector-menu-heading-label">').text(i18n.header)
	    ),
	    $('<div class="vector-menu-content">').append(
	        $('<ul class="vector-menu-content-list">').append(
	        	$('<li class="toclevel-1 tocsection-0">').append($('<a href="#">').append(
	        		$('<span class="toctext">').text(i18n.top)
	        	)),
	            $('#toc > ul').children().clone()
	        )
	    )
	).appendTo('#mw-panel');

	// Remove the original TOC on the page
	$('#toc').remove();

	mw.loader.using( ['ext.gadget.sectionObserver'], function(require) {
		var initSectionObserver = require('ext.gadget.sectionObserver');
		var allSections = document.querySelectorAll('#firstHeading, .mw-headline');
		var sectionObserver = initSectionObserver({topMargin: 20, onIntersection: onIntersection})
		sectionObserver.setElements(allSections);
		sectionObserver.calcIntersection();
		
		allSections = Array.from(allSections);
		var tocList = $('#p-toc .vector-menu-content-list')[0];
		var tocSections = $('#p-toc .vector-menu-content-list li');
		var baseOffset = $('#p-toc .tocsection-0 .toctext')[0].offsetTop;
		
		function onIntersection(section) {
		    var index = allSections.indexOf(section);
		    $('#p-toc .tocsection-current').removeClass('tocsection-current');
		    var tocSection = tocSections.eq(index).addClass('tocsection-current');
		    if ( tocSection.is(':hidden') && index > 0 ) return onIntersection(allSections[index - 1]);
		    var tocSectionPos = tocSection[0].offsetTop - baseOffset;
		    if ( tocSectionPos < tocList.scrollTop + (tocList.clientHeight * 0.15) ) {
		        tocList.scrollTo({top: tocSectionPos - (tocList.clientHeight * 0.3)});
		    }
		    else if ( tocSectionPos > tocList.scrollTop + (tocList.clientHeight * 0.85) ) {
		        tocList.scrollTo({top: tocSectionPos - (tocList.clientHeight * 0.7)});
		    }
		}
	} );
})