MediaWiki:Gadget-preview.js

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
JS-код ниже относится к гаджету: Быстрый предпросмотр без перезагрузки страницы (альтернатива штатной возможности, включаемой на вкладке «Редактирование») (править описание). Связанный CSS-файл: MediaWiki:Gadget-preview.css. Его использует около 14 000 учётных записей.

После сохранения или недавних изменений очистите кэш браузера.

window.ajaxPreviewMsg = {
	emptydiff: 'Изменений нет.',
	difftip: 'Нажмите кнопку с зажатым Shift для сравнения с редактируемой старой версией',
	diff2old: 'Это сравнение со старой версией',
	viewtip: 'Нажмите кнопку с зажатым Shift для обновления также категорий и шаблонов (<a href="/wiki/Википедия:Гаджеты/Ajax-предпросмотр#preview" target="_blank">подробнее</a>)'
};


if (
	/^(edit|submit)$/.test( mw.config.get( 'wgAction' ) ) &&
	mw.config.get( 'wgCanonicalNamespace' ) !== 'Special'
) {
	$( function () {
		ajaxPreviewPos = window.ajaxPreviewPos || 'right';

		if ( ajaxPreviewPos !== 'bottom' ) {
			var previewToolbar = $( '<div>' )
				.addClass( 'ajaxPreview-toolbar' )
				.css( 'float', ajaxPreviewPos )
				.css( 'margin', '4px 0' );
			if ( mw.user.options.get( 'usebetatoolbar' ) || $.wikiEditor ) {
				$( '#wikiPreview' ).after( previewToolbar );
			} else {
				var el = $( '#toolbar' );
				if ( el.length ) {
					el.prepend( previewToolbar );
				} else {
					$( '#editform' ).before( previewToolbar );
				}
			}
		}
		addBtn( window.ajaxPreviewButton, 'wpPreview', window.ajaxPreviewKey || 'p' );
		addBtn( window.ajaxDiffButton, 'wpDiff', window.ajaxDiffKey || 'v' );

		var $wkPreview = $( '#wikiPreview' ),
			frm = document.editform;
		if ( !$wkPreview.length || !frm ) return;
		$( '#wpPreviewLive, #wpDiffLive' ).click( run );

		var isDiff, isFullPreview, $btn, oldHeight, parse, scriptTip;
		var mm = window.ajaxPreviewMsg;

		function run( e ) {
			$btn = $( this );
			if ( !$btn.data( 'orig-value' ) ) {
				$btn.data( 'orig-value', $btn.val() );
			}
			$btn.val( '…' );

			$( '#wikiDiff, #newarticletext' ).hide();
			oldHeight = $wkPreview.height();
			scriptTip = '';

			$( '#wikiPreview' ).addClass( 'ajaxPreview-preview-loading' );
			$( 'body' ).addClass( 'ajaxPreview-body-loading' );

			var data, ext;
			var txt = $( '#wpTextbox1' ).textSelection( 'getContents' );
			if ( frm.wpSection.value == 'new' && frm.wpSummary && frm.wpSummary.value ) {
				txt = '== ' + frm.wpSummary.value + ' ==\n\n' + txt;
			}

			isDiff = $btn.attr( 'id' ) === 'wpDiffLive';

			if ( isDiff ) {
				data = {
					action: 'compare',
					fromtitle: mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ),
					toslots: 'main',
					'totext-main': txt,
					topst: true,
					prop: 'diff',
					formatversion: 2,
				};

				if ( frm.wpSection.value ) {
					if ( frm.wpSection.value === 'new' ) {
						data.fromslots = 'main';
						data['fromtext-main'] = '';
					} else {
						// API says "fromsection" is deprecated, but if specifying "fromslots", it
						// requires "fromslots-text" while we have "fromtitle".
						data.fromsection = frm.wpSection.value;
					}
				}

				// Can compare to currently edited older version, not to the latest
				if ( frm.oldid.value && frm.oldid.value != '0' ) {
					if ( e.shiftKey ) {
						data.fromrev = frm.oldid.value;
						scriptTip = mm.diff2old;
					} else {
						scriptTip = mm.difftip;
					}
				}
			} else {  // Preview
				if ( frm.wpSection.value ) {
					txt += '<br><references />';
				}

				data = {
					action: 'parse',
					title: mw.config.get( 'wgPageName' ),
					text: txt,
					pst: true,
					summary: frm.wpSummary ? frm.wpSummary.value : '',
					disableeditsection: true,
					disablelimitreport: true,
					prop: [ 'text', 'modules', 'jsconfigvars' ],
					formatversion: 2,
				};

				if ( window.ajaxPreviewFull || e.shiftKey ) {
					isFullPreview = true;
					data.prop.push( 'categorieshtml', 'templates' );
				} else {
					isFullPreview = false;
					scriptTip = mm.viewtip;
				}
			}

			new mw.Api().post( data, {
				// Switch to multipart to decrease sent data volume on non-Latin languages
				contentType: 'multipart/form-data',
			} ).then( receive, receive );
		}

		function receive() {
			var resp = typeof arguments[ 0 ] === 'string' ? arguments[ 1 ] : arguments[ 0 ];
			$( '#wikiPreview' ).removeClass( 'ajaxPreview-preview-loading' );
			$( 'body' ).removeClass( 'ajaxPreview-body-loading' );
			$btn.val( $btn.data( 'orig-value' ) );
			if ( window.currentFocused ) {
				currentFocused.focus();
			}

			var $content;
			var error;

			try {
				if ( isDiff ) {
					var body = resp && resp.compare && resp.compare.body;
					if ( body ) {
						$content = $(
							'<table class="diff">' +
							'<col class="diff-marker"><col class="diff-content">' +
							'<col class="diff-marker"><col class="diff-content">' +
							body +
							'</table>'
						);
					} else {
						if ( body === '' ) {
							error = mm.emptydiff;
						} else {
							if ( resp && resp.error && resp.error.code === 'missingtitle' ) {
								error = 'Страница ещё не создана — не с чем показывать разницу.';
							} else {
								error = 'Ошибка при получении разницы версий.';
							}
						}
					}
				} else {
					parse = resp.parse;
					if ( parse ) {
						$content = $( parse.text );
						if ( frm.wpSection.value !== 'new' ) {
							var $sum = $( frm ).find( '.mw-summary-preview' );  // Create summary preview if needed
							if ( !$sum.length ) {
								$sum = $( '<div>' )
									.addClass( 'mw-summary-preview' )
									.insertAfter( '#wpSummary' );
							}
							$sum.html( '<span class="comment">' + parse.parsedsummary + '</span>' );
						}
						if ( parse.modules ) {
							mw.loader.load(
								parse.modules.concat( parse.modulescripts, parse.modulestyles )
							);
							mw.config.set( parse.jsconfigvars );
						}
					} else {
						error = 'Ошибка при получении преобразованного кода.';
					}
				}
			} catch ( err ) {
				error = 'Ошибка: ' + err;
			}

			var elements = [];
			
			var $span;
			if ( scriptTip ) {
				$span = $( '<span>' )
					.addClass( 'ajaxPreview-shiftTip' )
					.html( scriptTip );
				elements.push( $span );
			}
			var $h3 = $( '<h3>' )
				.attr( 'id', 'ajaxPreview-label' )
				.text( $btn.val() );
			var $hr = $( '<hr>' );
			
			elements.push( $h3, $hr, $content || error );

			$wkPreview
				.empty()
				.append( elements )
				.show();

			// New content is available, fire the hook
			mw.hook( 'wikipage.content' ).fire( $wkPreview );

			if ( window.ajaxPreviewScrollTop ) {
				$wkPreview[ 0 ].scrollIntoView();
			} else {
				$( window ).scrollTop( $( window ).scrollTop() + $wkPreview.height() - oldHeight );
			}

			if ( !isDiff ) {
				finalizePreview( parse );
			}
		}

		function finalizePreview( parse ) {
			// Demonstrate that hiddencats will not be updated
			$( '.hiddencats' ).addClass( '.ajaxPreview-outdated' );

			if ( $( '.tex' ).length && mw.user.options.get( 'math' ) === '6' ) { // 6 — mathjax mode
				mw.loader.using( 'ext.math.mathjax.enabler', function () {
					$( '#wikiPreview' ).renderTex();
				} );
			}
			if ( window.ajaxPreviewExec ) {
				ajaxPreviewExec( $wkPreview[ 0 ] );
			}


			// !!! [[mediazilla:36476]]
			if ( $( 'body' ).hasClass( 'ltr' ) ) {
				$( '#wikiPreview' ).addClass( 'mw-content-ltr' );
			}

			if ( !isFullPreview ) {
				$( '.templatesUsed, #p-lang, #catlinks' ).addClass( 'ajaxPreview-outdated' );
				// $( '#p-lang, #catlinks' ).attr( 'title', 'Not updated by latest preview' );
				return;
			}

			// Otherwise update other areas
			$( '.templatesUsed, #p-lang, #catlinks' ).removeClass( 'ajaxPreview-outdated' );

			$( '#catlinks' ).replaceWith( parse.categorieshtml );

			var elements = parse.templates.map( ( function ( template ) {
				var $a = $( '<a>' )
					.attr( 'href', mw.util.getUrl( template.title ) )
					.text( template.title );
				if ( !template.exists ) {
					$a.addClass( 'new' );
				}
				return $( '<li>' ).append( $a );
			} ) );
			$( '#editform' )
				.find( '.templatesUsed ul' )
				.empty()
				.append( elements );
		}

		function addBtn( name, id, akey ) {
			var $btnOld = $( '#' + id );
			if ( !$btnOld.length ) {
				return;
			}
			var $btn = $( '<input> ')
				.attr( 'type', 'button' )
				.attr( 'id', id + 'Live' )
				.attr( 'title', $btnOld.val() )
				.addClass( 'mw-ui-button' )
				.css( 'margin-left', '4px' );
			if ( ajaxPreviewPos === 'bottom' ) {
				$btn.val( '>' ).insertAfter( '#' + id + 'Widget' );
			} else {
				if ( !name ) {  // Extract last word from standard buttons
					name = $btnOld.val();
					var i = name.lastIndexOf( ' ' ) + 1;
					name = name.substring( i, i + 1 ).toUpperCase() + name.substring( i + 1 );
				}
				$btn
					.val( name )
					.addClass( 'ajaxPreview-button' )
					.appendTo( previewToolbar );
			}
			if ( akey ) { // Reassign access key
				if ( $btnOld.attr( 'accesskey' ) === akey ) {
					$btnOld
						.removeAttr( 'accesskey' )
						.updateTooltipAccessKeys( '' );
				}
				$btn
					.attr( 'accesskey', akey )
					.updateTooltipAccessKeys( akey );
			}
			$btn.width( $btn.width() );
		}
	} );
}