MediaWiki:Gadget-PrintOptions.js

From Festipedia, hosted by the FR Heritage Group
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Wikipedia:Bypass your cache.
/**
 * Print options is a Gadget writen by Derk-Jan Hartman / User:TheDJ
 * For more information see [[User:TheDJ/Print_options]]
 *
 * Licensed MIT and/or CC-by-SA 4.0
 *
 * Copyright (c) 2010-2017 Derk-Jan Hartman / User:TheDJ
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

( function () {
	'use strict';
	var windowManager;
	var printDialog;

	var printOptions = {
		install: function () {
			var $printLink = $( '#t-print a' );
			if ( $printLink.length === 0 ) {
				return;
			}
			$printLink
				.text( 'Print page' )
				.off( 'click' )
				.get( 0 ).addEventListener( 'click', function ( e ) {
					mw.loader.using( [ 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows' ] ).done( printOptions.createWindow );
					e.stopPropagation();
					e.preventDefault();
				}, true ); // Use capturing phase, to beat the other click handler

			// Late pre-loading
			mw.loader.load( [ 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows' ] );
		},

		createWindow: function () {
			function PrintDialog( config ) {
				PrintDialog.super.call( this, config );
			}
			OO.inheritClass( PrintDialog, OO.ui.ProcessDialog );

			PrintDialog.static.name = 'printdialog';
			PrintDialog.static.title = 'Print this page';
			PrintDialog.static.actions = [
				{ action: 'print', label: 'Print', flags: 'primary' },
				{ label: 'Cancel', flags: 'safe' }
			];

			PrintDialog.prototype.initialize = function () {
				var checkbox, fieldset = [];
				PrintDialog.super.prototype.initialize.apply( this, arguments );
				this.panel = new OO.ui.PanelLayout( { padded: true, expanded: false } );
				this.content = new OO.ui.FieldsetLayout();

				for ( var i = 0; i < printOptions.questions.length; i++ ) {
					if ( printOptions.questions[ i ].type === 'checkbox' ) {
						checkbox = new OO.ui.CheckboxInputWidget( {
							selected: printOptions.questions[ i ].checked
						} );
						printOptions.questions[ i ].widget = checkbox;
						fieldset.push( new OO.ui.FieldLayout( checkbox, { label: printOptions.questions[ i ].label, align: 'inline' } ) );
					}
				}
				this.content.addItems( fieldset );

				this.panel.$element.append( this.content.$element );
				this.$body.append( this.panel.$element );
			};

			PrintDialog.prototype.getActionProcess = function ( action ) {
				var dialog = this;
				if ( action === 'print' ) {
					return new OO.ui.Process( function () {
						// Get values of checkboxes
						var question;
						for ( var i = 0; i < printOptions.questions.length; i++ ) {
							question = printOptions.questions[ i ];
							if ( question.type === 'checkbox' && question.widget ) {
								printOptions[ question.returnvalue ] = question.widget.isSelected();
							}
						}
						dialog.close( { action: action } ).done( function () {
							printOptions.changePrintCSS();
							printOptions.otherEnhancements();
							window.print();
							window.location = window.location;
						} );
					} );
				}
				return PrintDialog.super.prototype.getActionProcess.call( this, action );
			};

			if ( !windowManager ) {
				windowManager = new OO.ui.WindowManager();
				$( 'body' ).append( windowManager.$element );
			}
			if ( !printDialog ) {
				printDialog = new PrintDialog( {
					size: 'medium'
				} );

				windowManager.addWindows( [ printDialog ] );
			}
			windowManager.openWindow( printDialog );
		},

		changePrintCSS: function () {
			/* Here we:
				 - disable stylesheets that are print specific
				 - make screen specific stylesheets also enabled for print medium
				 - remove print specific stylerules
				 - make screen specific stylerules also enabled for print medium
			*/
			var printStyle = '';
			if ( this.enhanced === false ) {
				var i, j, k,
					rule,
					hasPrint,
					hasScreen,
					rules,
					stylesheet,
					stylesheets = document.styleSheets;

				for ( i = 0; i < stylesheets.length; i++ ) {
					stylesheet = stylesheets[ i ];
					if ( !stylesheet.media ) {
						continue;
					}
					if ( stylesheet.media.mediaText && stylesheet.media.mediaText.indexOf( 'print' ) !== -1 ) {
						if ( stylesheet.media.mediaText.indexOf( 'screen' ) === -1 ) {
							stylesheet.disabled = true;
						}
					} else if ( stylesheet.media.mediaText && stylesheet.media.mediaText.indexOf( 'screen' ) !== -1 ) {
						if ( stylesheet.media.mediaText.indexOf( 'print' ) === -1 ) {
							try {
								stylesheet.media.appendMedium( 'print' );
							} catch ( e ) {
								stylesheet.media.mediaText += ',print';
							}
						}
					}

					/* now test individual stylesheet rules */
					try {
						rules = stylesheet.cssRules || stylesheet.rules;
					} catch ( e ) {
						/* Cross domain issue. */
						mw.log.warn( 'Not possible to correct stylesheet due to cross origin restrictions.' );
						continue;
					}
					stylesheet.compatdelete = stylesheet.deleteRule || stylesheet.removeRule;
					for ( j = 0; rules && j < rules.length; j++ ) {
						rule = rules[ j ];
						hasPrint = false;
						hasScreen = false;
						if ( rule.type === CSSRule.MEDIA_RULE && rule.media ) {
							for ( k = 0; k < rule.media.length; k++ ) {
								if ( rule.media[ k ] === 'print' ) {
									hasPrint = true;
								} else if ( rule.media[ k ] === 'screen' ) {
									hasScreen = true;
								}
							}
						} else {
							continue;
						}
						if ( hasPrint && !hasScreen ) {
							stylesheet.compatdelete( j );
							j--;
						} else if ( hasScreen && !hasPrint ) {
							try {
								rule.media.appendMedium( 'print' );
							} catch ( e ) {
								rule.media.mediaText += ',print';
							}
						}
					}
				}
			}
			/* Add css to hide images */
			if ( this.noimages ) {
				printStyle += 'img, .thumb {display:none;}\n';
			}
			/* Add css to hide references markers and the references lists */
			if ( this.norefs ) {
				printStyle += '.mw-headline[id="References"], ol.references, .reference {display:none;}\n';
			}
			if ( this.notoc ) {
				printStyle += '#toc, .toc {display:none;}\n';
			}
			if ( this.nobackground ) {
				printStyle += '* {background:none !important;}\n';
			}
			if ( this.blacktext ) {
				printStyle += '* {color:black !important;}\n';
			}

			if ( printStyle ) {
				$( 'head' ).append( '<style type="text/css" media="print">' + printStyle + '</style>' );
			}
		},

		/* Rewrite the "retrieved from" url to be readable */
		otherEnhancements: function () {
			var link = $( 'div.printfooter a' );
			link.text( decodeURI( link.text() ) );
		},

		questions: [
			{
				label: 'Hide interface elements',
				type: 'checkbox',
				checked: true,
				returnvalue: 'enhanced'
			},
			{
				label: 'Hide images',
				type: 'checkbox',
				checked: false,
				returnvalue: 'noimages'
			},
			{
				label: 'Hide references',
				type: 'checkbox',
				checked: false,
				returnvalue: 'norefs'
			},
			{
				label: 'Hide Table of Contents',
				type: 'checkbox',
				checked: false,
				returnvalue: 'notoc'
			},
			{
				label: 'Remove backgrounds (Your browser might or might not override this)',
				type: 'checkbox',
				checked: false,
				returnvalue: 'nobackground'
			},
			{
				label: 'Force all text to black',
				type: 'checkbox',
				checked: true,
				returnvalue: 'blacktext'
			}
		]
	};

	if ( mw.config.get( 'wgNamespaceNumber' ) >= 0 ) {
		$( function () {
			// This can be before the click handler by MW is installed. Instead,
			// re-add ourselves to the back of the document.ready list
			// use async timeoute to do this
			setTimeout( function () {
				$( printOptions.install );
			} );
		} );
	}
}() );