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.
/**
 * This script interacts with [[Template:Menu]]
 * [[Category:Template script pages]]
 */
var TemplateMenu = {

	init: function () {
		$content = $( '#mw-content-text' );
		$content.find( '.menu-header' ).on( 'click', TemplateMenu.toggle );
		$content.find( '.menu-progress-buttons' ).each( TemplateMenu.makeProgressButtons );
		$content.find( '.menu-progress-bar' ).each( TemplateMenu.makeProgressBar );
		$content.find( '.menu-book .mw-ui-button' ).on( 'click', TemplateMenu.makeBook );
		$content.find( '.menu-list' ).each( TemplateMenu.trimList );
	},

	toggle: function ( event ) {
		if ( event.target.tagName === 'A' ) {
			return;
		}
		$( this ).next( '.menu-content' ).toggle();
	},

	/**
	 * Trim lists of more than 10 items
	 * Example: [[Template:NREMT menu]]
	 */
	trimList: function ( event ) {
		var $button = $( '<span>more</span>' ).css( 'cursor', 'pointer' ).on( 'click', function () {
			$( this ).hide().siblings().show();
		} );
		$( this ).find( 'li' ).eq( 10 ).nextAll().hide().last().after( $button );
	},

	makeProgressButtons: function () {
		var $menu = $( this ).closest( '.menu' );
		var prev, next, index;
		var links = $menu.find( 'a' );
		links.each( function ( i ) {
			if ( $( this ).hasClass( 'selflink' ) ) {
				index = i;
				prev = links[ index - 1 ];
				next = links[ index + 1 ];
				return;
			}
		} );
		if ( index === undefined ) {
			return;
		}
		var prevButton = $( prev ).clone().addClass( 'mw-ui-button' ).text( '< Previous' );
		var nextButton;
		if ( next ) {
			nextButton = $( next ).clone().addClass( 'mw-ui-button' ).text( 'Next >' );
		}
		if ( !prev ) {
			nextButton.addClass( 'mw-ui-progressive' ).text( 'Start' );
		}
		$menu.find( '.menu-progress-buttons' ).append( prevButton, nextButton );
	},

	makeProgressBar: function () {
		var $menu = $( this ).closest( '.menu' );
		var index;
		var links = $menu.find( 'a' );
		links.each( function ( i ) {
			if ( $( this ).hasClass( 'selflink' ) ) {
				index = i;
				return;
			}
		} );
		if ( index === undefined ) {
			return;
		}
		var percentage = Math.round( index * 100 / links.length ) + '%';
		$menu.find( '.menu-progress' ).text( percentage ).css( 'width', percentage );
		if ( percentage === '0%' ) {
			$menu.find( '.menu-progress' ).addClass( 'menu-no-progress' );
		}
	},

	makeBook: function ( event ) {

		// Show loading dialog to hint the user that something is happening
		var messageDialog = new OO.ui.MessageDialog();
		var windowManager = new OO.ui.WindowManager();
		TemplateMenu.windowManager = windowManager;
		$( 'body' ).append( windowManager.$element );
		windowManager.addWindows( [ messageDialog ] );
		var progressBar = new OO.ui.ProgressBarWidget( {
			progress: false
		} );
		windowManager.openWindow( messageDialog, {
			title: 'Generating PDF',
			message: progressBar.$element,
			escapable: false,
			actions: []
		} );

		// Get book data
		var $menu = $( this ).closest( '.menu' );
		var $book = $menu.find( '.menu-book' );
		var bookLogo = $book.data( 'book-logo' ) ? '[' + '[File:' + $book.data( 'book-logo' ) + '|link=]]' : '';
		var bookTitle = $book.data( 'book-title' );
		var bookSubtitle = $book.data( 'book-subtitle' );
		var bookImage = $book.data( 'book-image' ) ? '[' + '[File:' + $book.data( 'book-image' ) + '|300px|link=]]' : '';
		var bookAuthors = $book.data( 'book-authors' );

		// Make book cover
		var $cover = $( '<div class="book-cover"></div>' );
		var $coverContent = $( '<div class="book-cover-content"></div>' );
		var $coverLogo = $( '<div class="book-cover-logo">' + bookLogo + '</div>' );
		var $coverTitle = $( '<div class="book-cover-title">' + bookTitle + '</div>' );
		var $coverSubtitle = $( '<div class="book-cover-subtitle">' + bookSubtitle + '</div>' );
		var $coverImage = $( '<div class="book-cover-image">' + bookImage + '</div>' );
		var $coverAuthors = $( '<div class="book-cover-authors">' + bookAuthors + '</div>' );
		$coverContent.append( $coverLogo, $coverTitle, $coverSubtitle, $coverImage, $coverAuthors );
		$cover.append( $coverContent );

		// Cover CSS
		$cover.css( {
			'font-family': 'Garamond',
			'page-break-after': 'always',
			'display': 'flex',
			'align-items': 'center',
			'justify-content': 'center',
			'text-align': 'center',
			'width': '100vw',
			'height': '99vh',
		} );
		$coverContent.css( {
			'border': '10px double #202122',
			'padding': '30px',
		} );
		$coverTitle.css( {
			'font-size': '2em',
		} );
		$coverSubtitle.css( {
			'font-size': '1.5em',
		} );
		$coverAuthors.css( {
			'font-size': '1.5em',
		} );
		$coverContent.find( 'div' ).css( {
			'margin': '30px',
		} );

		// Make book wikitext
		var wikitext = $cover.prop( 'outerHTML' );
		$menu.find( 'a' ).each( function () {
			var link = $( this );
			if ( link.hasClass( 'external' ) ) {
				return; // Skip external pages
			}
			if ( link.hasClass( 'new' ) ) {
				return; // Skip non-existent pages
			}
			if ( link.hasClass( 'mw-ui-button' ) ) {
				return; // Skip Previous and Next buttons
			}
			var chapterName = link.text();
			var chapterPage = link.hasClass( 'selflink' ) ? mw.config.get( 'wgPageName' ) : link.attr( 'title' );
			wikitext += '\n<h1>' + chapterName + '</h1>';
			wikitext += '\n{' + '{#invoke:Transcluder|main|' + chapterPage;
			wikitext += '| noBehaviorSwitches = 1';
			wikitext += '| templates = - Video, .* data, .* menu, .* header';
			wikitext += '}}';
		} );

		// Get book HTML
		new mw.Api().parse( wikitext ).then( function ( html ) {

			// Save original HTML to restore it later
			var $firstHeading = $( '#firstHeading' );
			var $pageContent = $( '#mw-content-text .mw-parser-output' );
			var originalContent = $pageContent.html();

			// Append chapters HTML
			$pageContent.html( html );

			// Use imagesLoaded plugin to wait for images to load
			mw.loader.getScript( 'https://unpkg.com/imagesloaded@5/imagesloaded.pkgd.min.js' ).then( function () {
				$pageContent.imagesLoaded( function () {

					// Hide elements we don't want to print
					TemplateMenu.windowManager.destroy();
					$firstHeading.hide();
					$pageContent.find( '.map' ).hide(); // Maps don't load well so we hide them

					// Finally, print
					window.print();

					// Restore original page
					//$firstHeading.show();
					//$pageContent.html( originalContent );
				} );
			} );
		} );
	}
};

$( TemplateMenu.init );
Cookies help us deliver our services. By using our services, you agree to our use of cookies.