MediaWiki:Gadget-tabbedwindow.js

From mediawiki.org

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.
/**
 *
 * tabbedWindow.js
 *
 * It embeds an OOUI tabbed window on all pages in the API namespace on MediaWiki.org.
 * Each tab of the window contains sample code in a programming language (PHP, Javascript, Python, etc.)
 * demonstrating the use of the MediaWiki Action API.
 *
 * @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3-or-Later
 * @licstart  The following is the entire license notice for the JavaScript code in this gadget.
 *
 * Copyright (C) 2019 Jay Prakash <https://meta.wikimedia.org/wiki/User:Jayprakash12345> and contributors
 *
 * The JavaScript/Gadget code in this page is free software: you can
 * redistribute it and/or modify it under the terms of the GNU
 * General Public License (GNU GPL) as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version.  The code is distributed WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
 *
 * As additional permission under GNU GPL version 3 section 7, you
 * may distribute non-source (e.g., minimized or compacted) forms of
 * that code without the copy of the GNU GPL normally required by
 * section 4, provided you include this license notice and a URL
 * through which recipients can access the Corresponding Source.
 *
 * @licend  The above is the entire license notice for the JavaScript/Gadget code in this gadget.
 */

( function () {
	'use strict';

	function trySettingTab( indexLayout, hash ) {
		var possiblePanelName = hash.slice( 1 );
		var possiblePanel = possiblePanelName && indexLayout.getTabPanel( possiblePanelName );
		if ( possiblePanel ) {
			indexLayout.setTabPanel( possiblePanelName );
			indexLayout.scrollElementIntoView();
		}
	}

	/**
	 * This function fetches sample code in different programming languages
	 * from the sub-sections of the section "Sample Code" and places
	 * them into an OOUI tabbed window.
	 *
	 * @param {jQuery} $tabbedWindows
	 */
	function makeTabWindow( $tabbedWindows ) {
		var tabs = [];

		$tabbedWindows.each( function () {

			var panelLayout,
				indexLayout = new OO.ui.IndexLayout( {
					expanded: false
				} );

			$( this ).find( 'h3, h4, h5, h6' ).each( function () {
				$( this ).find( '.mw-editsection' ).remove();
				var id = $( this ).find( 'span[class=mw-headline]' ).attr( 'id' );

				var $content = $( this ).nextUntil( 'h3, h4, h5, h6' );

				var tabPanel = new OO.ui.TabPanelLayout( id, {
					expanded: false,
					label: $( this ).text(),
					// Attach the original DOM elements directly by reference.
					// This means they move directly in memory instead of getting copied/serialized/parsed as HTML.
					// If we didn't move them, but instead copied and re-parsed HTML, then it would disconnect events
					// and other live references from gadgets and extensions, which breaks sorting features, responsive gallery, etc.
					$content: $content
				} );

				tabPanel.$element.css( 'padding', '0.5em' );

				tabs.push( tabPanel );
			} );

			indexLayout.addTabPanels( tabs );
			tabs = [];

			panelLayout = new OO.ui.PanelLayout( {
				expanded: false,
				framed: true,
				content: [ indexLayout ]
			} );

			$( this ).empty().append( panelLayout.$element );
			
			// Workaround for T348680
			mw.hook( 've.deactivationComplete' ).fire();

			// Select and scroll to any initially linked item in the address
			trySettingTab( indexLayout, location.hash );
			// Keep address bar updated with sharable link (also makes forward/backward browser navigation work)
			if ( history.replaceState ) {
				indexLayout.on( 'set', function ( tabPanel ) {
					history.replaceState( null, document.title, '#' + tabPanel.getName() );
				} );
			}
			// Support anchor links on the same page (from table of Contents, or [[#Section]] links) 
			window.addEventListener( 'hashchange', function () {
				trySettingTab( indexLayout, location.hash );
			} );

		} );
	}

	// Quick check (dependency-free, this is executed for all pages/actions/namespaces)
	var $tabbedWindows,
		supportedNamespaces = [ 'API', 'Help', 'Manual', '' ],
		action = mw.config.get( 'wgAction' ),
		namespace = mw.config.get( 'wgCanonicalNamespace' );

	if ( 
		supportedNamespaces.indexOf( namespace ) !== -1 || 
		mw.config.get( 'wgPageName' ).indexOf( 'Template:TabbedWindowBegin' ) === 0 
	) {
		mw.hook( 'wikipage.content' ).add( function ( $content ) {
			// Expensive checks (only on the subset of supported pages)
			$tabbedWindows = $content.find( '.mw-gadget-tabbedwindow' );
			if ( $tabbedWindows.length > 0 ) {
				// Viewing an API subject page with tabs on it, let's make them nice!
				mw.loader.using( [ 'oojs-ui-widgets' ] ).then( function () {
					makeTabWindow( $tabbedWindows );
				} );
			}
		} );
	}
}() );