MediaWiki:Gadget-diffedit.js

/*!
 * diffedit.js – script that lets you edit pages directly from the diff view
 * @authors [[m:User:Jon Harald Søby]]
 * @licence CC-by-SA 4.0
 *
 * For documentation, see [[User:Jon Harald Søby/diffedit]]
 * @source [[m:User:Jon Harald Søby/diffedit.js]]
 *
 * Info dla aktualizujących:
 * Na samym końcu, oryginalnego skryptu znajduje się polecenie doładowania
 * zależności z użyciem mw.using oraz arkusza CSS. Te linie zostały skasowane,
 * ponieważ wczytanie zależności zapewnia ResourceLoader. Przy aktualizacji
 * gadżetu warto pamiętać o usuwaniu tych komend.
 */
function initDiffedit( $, mw, OO ) {
	"use strict";
	var messages,
		linetopCache = "",
		tabIndex = 1,
		pageId = mw.config.get( 'wgArticleId' ),
		oldRevisionId = mw.config.get( 'wgDiffOldId' ),
		newRevisionId = mw.config.get( 'wgDiffNewId' ),
		currentRevisionId = mw.config.get( 'wgCurRevisionId' ),
		contentModel = mw.config.get( 'wgPageContentModel' ),
		allowedContentModels = [ 'wikitext', 'text', 'sanitized-css', 'json', 'javascript', 'css', 'Scribunto' ],
		api = new mw.Api();
		
	/* The 'messages' function is from [[d:MediaWiki:Gadget-Merge.js]],
	 * see that page's history for credits
	 */
	messages = function() {
		var translations = {
			en: {
				editTitle: 'Edit this diff',
				editTitleNewerRevs: 'This diff can\'t be edited, since there are newer revisions of the page.',
				noPermission: 'You do not have permission to edit this page',
				refresh: 'Show latest',
				refreshTitle: 'Click to load the diff against the newest revision of the page'
			},
			bn: {
				editTitle: 'এই পার্থক্যটি সম্পাদনা করুন',
				editTitleNewerRevs: 'পাতাটিতে নতুনতর সম্পাদনা থাকায়, এই পার্থক্যটি সম্পাদনা করা যাবে না।',
				noPermission: 'আপনার এই পাতাটি সম্পাদনা করার অনুমতি নেই',
				refresh: 'সর্বশেষটি দেখান',
				refreshTitle: 'পাতাটির নতুনতর সংশোধনের পার্থক্য লোড করতে ক্লিক করুন'
			},
			es: {
				editTitle: 'Editar esta diferencia',
				editTitleNewerRevs: 'Esta diferencia no puede editarse ya que hay revisiones más recientes de la página.',
				noPermission: 'No tienes permiso para editar esta página',
				refresh: 'Mostrar la última revisión',
				refreshTitle: 'Pulsa para cargar la diferencia con la revisión más reciente de la página'
			},
			fa: {
				editTitle: 'ویرایش این تفاوت',
				editTitleNewerRevs: 'این تفاوت را نمی‌توان ویرایش کرد؛ زیرا نسخه‌های جدیدتری از صفحه موجود هستند.',
				noPermission: 'شما اختیارات لازم برای ویرایش این صفحه را ندارید',
				refresh: 'نمایش جدیدترین',
				refreshTitle: 'برای بارگیری تفاوت با جدیدترین نسخهٔ صفحه کلیک کنید'
			},
			fr: {
				editTitle: 'Modifier ce diff',
				editTitleNewerRevs: 'Ce diff ne peut pas être édité, car il existe des révisions plus récentes de la page.',
				noPermission: 'Vous n\'avez pas le droit de modifier cette page',
				refresh: 'Montrer le dernier',
				refreshTitle: 'Cliquez pour charger la comparaison avec la dernière révision de la page.'
			},
			he: {
				editTitle: 'עריכת ההשוואה הזאת',
				editTitleNewerRevs: 'ההשוואה הזאת לא ניתנת לעריכה, מכיוון שקיימות גרסאות חדשות יותר של הדף.',
				noPermission: 'אין לך הרשאות לעריכת הדף הזה',
				refresh: 'להראות את המאוחר ביותר',
				refreshTitle: 'ללחוץ לקבלת ההשוואה עם הגרסה האחרונה של הדף'
			},
			ja: {
				editTitle: 'この差分を編集',
				editTitleNewerRevs: 'ページに新しい版があるため、この差分は編集できません。',
				noPermission: 'このページを編集する権限がありません',
				refresh: '最新版を表示',
				refreshTitle: 'クリックして、ページの最新版との差分を読み込みます'
			},
			ka: {
				editTitle: 'ამ განსხვავების რედაქტირება',
				editTitleNewerRevs: 'ამ განსხვავების რედაქტირება შეუძლებელია, რადგან არსებობს გვერდის უფრო ახალი ვერსია.',
				noPermission: 'თქვენ არ გაქვთ ამ გვერდის რედაქტირების უფლება',
				refresh: 'უკანასკნელის ხილვა',
				refreshTitle: 'დააწკაპეთ, რათა იხილოთ განსხვავება გვერდის უახლეს ვერსიასთან'
			},
			nb: {
				editTitle: 'Rediger denne diffen',
				editTitleNewerRevs: 'Denne diffen kan ikke redigeres, siden det finnes nyere revisjoner av siden.',
				noPermission: 'Du har ikke tillatelse til å redigere denne sida',
				refresh: 'Vis nyeste',
				refreshTitle: 'Klikk for å laste diffen mot den nyeste revisjonen av siden'
			},
			nn: {
				editTitle: 'Endre denne diffen',
				editTitleNewerRevs: 'Du kan ikkje endre denne diffen, av di det finst nyare revisjonar av sida.',
				noPermission: 'Du har ikkje løyve til å endra denne sida',
				refresh: 'Syn nyaste',
				refreshTitle: 'Klikk for å lasta diffen mot den nyaste versjonen av sida'
			},
			pl: {
				editTitle: 'Edytuj to porównanie',
				editTitleNewerRevs: 'Nie możesz edytować porównania, bo istnieją nowsze wersje tej strony.',
				noPermission: 'Nie masz uprawnień do edycji tej strony',
				refresh: 'Pokaż najnowszą',
				refreshTitle: 'Kliknij, aby załadować porównanie z najnowszą wersją tej strony'
			},
			sv: {
				editTitle: 'Redigera denna diff',
				editTitleNewerRevs: 'Denna diff kan inte redigeras då det finns nyare sidversioner.',
				noPermission: 'Du har inte behörighet att redigera den här sidan',
				refresh: 'Visa senaste',
				refreshTitle: 'Klicka för att ladda in skillnaden mot den senaste sidversionen'
			},
			th: {
				editTitle: 'แก้ไขความแตกต่างนี้',
				editTitleNewerRevs: 'แก้ไขความแตกต่างนี้ไม่ได้ เนื่องจากมีการแก้ไขหน้าเว็บที่ใหม่กว่า',
				noPermission: 'คุณไม่ได้รับอนุญาตให้แก้ไขหน้านี้',
				refresh: 'แสดงการแก้ไขล่าสุด',
				refreshTitle: 'คลิกเพื่อโหลดความแตกต่างกับรุ่นใหม่ล่าสุดของหน้า'
			},
			tl: {
				editTitle: 'I-edit ang diff na ito',
				editTitleNewerRevs: 'Hindi ma-edit ang diff na ito, dahil may mga mas bagong rebisyon ng page.',
				noPermission: 'Wala kang permission mag-edit ang page.',
				refresh: 'Ipakita ang pinakbago',
				refreshTitle: 'I-click upang i-load ang diff laban sa pinakabagong rebisyon ng pahina'
			},
			vi: {
				editTitle: 'Sửa đổi từ trang Khác này',
				editTitleNewerRevs: 'Không thể sửa đổi vì có các phiên bản mới hơn.',
				noPermission: 'Bạn không có quyền sửa trang này',
				refresh: 'Xem sửa đổi mới nhất',
				refreshTitle: 'Nhấp để xem khác biệt với phiên bản hiện tại của trang'
			},
			zh: {
				editTitle: '編輯此差異',
				editTitleNewerRevs: '由於有更新的版本,這個差異無法被修改。',
				noPermission: '您沒有權限修改這個頁面。',
				refresh: '顯示最新版本',
				refreshTitle: '點擊以載入頁面與最新修改的差異'
			},
		},
			chain = mw.language.getFallbackLanguageChain(),
			len = chain.length,
			ret = {},
			i = len - 1;
	    while ( i >= 0 ) {
			if ( translations.hasOwnProperty( chain[ i ] ) ) {
	        	$.extend( ret, translations[ chain[ i ] ] );
	    	}
	    	i = i - 1;
	    	}
			return ret;
	}();

	
	function enumerateLines() {
		var currentLine = 0,
			numberRegex = "0-9",
			localNumbers = mw.language.getDigitTransformTable();
		if ( ( localNumbers instanceof Array && localNumbers.length ) || Object.keys( localNumbers ).length ) {
			for ( var i = 0; i < 10; i++ ) {
				numberRegex = numberRegex.concat( localNumbers[ i ] );
			}
		}
		$( 'table.diff tbody tr td:last-of-type' ).each( function() {
			if ( $( this ).hasClass( 'diff-lineno' ) ) {
				var lineNo = $( this ).text();
				lineNo = mw.language.convertNumber( lineNo.replace( new RegExp( '[^' + numberRegex + ']', 'g' ), "" ), true );
				currentLine = lineNo;
			} else if ( $( this ).hasClass( 'diff-addedline' ) || $( this ).hasClass( 'diff-context' ) ) {
				$( this ).addClass( 'diff-editable' ).attr( 'data-mw-diff-line', currentLine );
				$( this ).attr( 'data-mw-diff-tabindex', tabIndex );
				currentLine++;
				tabIndex++;
			}
		});
	}
	
	function addEditButton( titleText ) {
		var editTitle = titleText ? titleText : messages.editTitle,
			editIcon = titleText ? 'editLock' : 'edit';
		var editButton = new OO.ui.ButtonWidget( {
				label: mw.message( 'edit' ).text(),
				icon: editIcon,
				title: editTitle,
				flags: [ 'primary', 'progressive' ],
				disabled: !!titleText
			});
		linetopCache = $( '.diff-linetop' ).html();
		$( '.diffedit-editbutton' ).append( editButton.$element );
		if ( !titleText ) {
			editButton.on( 'click', function() {
				toggleEditMode( 'enable' );
				addEditLine();
			});
		}
	}
	
	function addRefreshButton() {
		var refreshButton = new OO.ui.ButtonWidget( {
				label: messages.refresh,
				icon: 'reload',
				title: messages.refreshTitle,
				flags: [ 'progressive' ],
				invisibleLabel: true,
				framed: false
			});
		$( '.diffedit-editbutton' ).prepend( refreshButton.$element );
		refreshButton.on( 'click', function() {
			window.location.href = mw.config.get( 'wgServer' ) + mw.util.getUrl( mw.config.get( 'wgPageName' ), { 'diff': 'cur', 'oldid': oldRevisionId } );
		});
	}
	
	function addEditLine() {
		var editSummary = new OO.ui.TextInputWidget( {
				icon: 'textSummary',
				accessKey: mw.message( 'accesskey-summary' ).text(),
				name: 'wpSummary',
				tabIndex: tabIndex + 1,
				placeholder: mw.message( 'revisionslider-label-comment' ).text(),
				title: mw.message( 'tooltip-summary' ).text(),
				classes: [ 'diffedit-editsummary' ]
			}),
			publishButton = new OO.ui.ButtonWidget( {
				label: mw.message( 'publishchanges' ).text(),
				title: mw.message( 'tooltip-publish' ).text(),
				accessKey: mw.message( 'accesskey-publish' ).text(),
				tabIndex: tabIndex + 2,
				flags: [ 'primary', 'progressive' ],
				classes: [ 'diffedit-publishbutton' ]
			}),
			cancelButton = new OO.ui.ButtonWidget( {
				label: mw.message( 'cancel' ).text(),
				icon: 'cancel',
				invisibleLabel: true,
				tabIndex: tabIndex + 3,
				flags: [ 'destructive' ],
				framed: false
			}),
			editLine = new OO.ui.FieldLayout( new OO.ui.Widget( {
				content: [
					new OO.ui.HorizontalLayout( {
						items: [ editSummary, publishButton, cancelButton ]
					})]
				}));
		publishButton.on( 'click', function() {
			processEdit();
		});
		publishButton.$element.hover( function() {
			if ( $( 'input[name=wpSummary]' ).val().length === 0 ) {
				$( 'input[name=wpSummary]' ).css( { 'outline': '5px solid gold', 'transition': 'outline 500ms cubic-bezier(.5,2,.5,-1)' } );
			} else {
				$( 'input[name=wpSummary] ').css( { 'outline': '5px solid transparent' } );
			}
		});
		editSummary.$element.keyup( function( e ) {
			if ( e.key === 'Enter' ) {
				processEdit();
			}
		});
		cancelButton.on( 'click', function() {
			toggleEditMode( 'disable' );
		});
		editLine.$field.css( 'float', 'none' );
		$( '.diff-linetop' ).html( editLine.$element );
		$( 'input[name=wpSummary]' ).on( 'keyup keydown change', function() {
			$( this ).css( { 'outline': '5px solid transparent', 'transition': 'outline 500ms ease-out' } );
		});
	}
	
	function toggleEditMode( state ) {
		if ( state === 'enable' ) {
			$( 'table.diff' ).addClass( 'diff-editmode' );
			$( '.diff-editable' ).each( function() {
				$( this ).attr( { 'contenteditable': 'true', 'tabindex': $( this ).attr( 'data-mw-diff-tabindex' ) } ).css( { 'word-wrap': 'break-word', 'white-space': 'pre-wrap' } );
			});
			$( '.diff-editable div' ).text();
			$( '.diff-editable' ).first().attr( 'accesskey', ',' ).focus();
		} else {
			$( 'table.diff' ).removeClass( 'diff-editmode' );
			$( '.diff-linetop' ).html( linetopCache );
			addEditButton();
			$( '.diff-editable' ).each( function() {
				$( this ).attr( 'contenteditable', 'false').removeAttr( 'tabindex' ).css( { 'word-wrap': 'break-word', 'white-space': 'pre-wrap' } );
			});
		}
	}
	
	function processEdit() {
		$( '.diffedit-publishbutton' ).addClass( 'oo-ui-pendingElement-pending' ).removeClass( 'oo-ui-flaggedElement-primary' );
		var currentContent = "",
			contentFromApi = api.get( {
				action: 'query',
				prop: 'revisions',
				rvprop: 'content',
				rvslots: 'main',
				pageids: pageId,
				rvstartid: currentRevisionId,
				rvendid: currentRevisionId
			} );
		contentFromApi.done( function( data ) {
			var mainSlot = data.query.pages[pageId].revisions[0].slots.main,
				contentModel = mainSlot.contentmodel;
			currentContent = mainSlot["*"];
			currentContent = currentContent.split( "\n" );
			var newContent = currentContent;
			$( '.diff-editable' ).each( function() {
				var thisline = [],
					lineNo = $( this ).attr( 'data-mw-diff-line' );
				if ( $( this ).contents().length === 0 ) {
					thisline.push( "" );
				} else if ( $( this ).contents()[0].nodeName === "#text" ) {
					thisline.push( $( this ).contents()[0].textContent );
				} else {
					$( this ).contents().each( function() {
						thisline.push( this.textContent );
					});
				}
				newContent[lineNo-1] = thisline.join( "\n" );
			});
			api.postWithEditToken( {
				action: 'edit',
				pageid: pageId,
				baserevid: newRevisionId,
				nocreate: true,
				text: newContent.join( "\n" ),
				minor: true,
				summary: $( 'input[name=wpSummary]' ).val() + " " + mw.message( 'parentheses', '[[m:Special:MyLanguage/User:Jon Harald Søby/diffedit|diffedit]]' ).text()
			} ).done( function( data ) {
				window.location.href = mw.config.get( 'wgServer' ) + mw.util.getUrl( mw.config.get( 'wgPageName' ), { 'diff': 'cur' } );
			}).fail( function( err ) {
				console.log(err);
				alert( "Error: " + err );
			});
		}).fail( function( err ) {
			alert( "Failed: " + err );
			return;
		});
	}
	
	$( '.diff-lineno:first' ).next().addClass( 'diff-linetop' ).append( $( '<div />' ).addClass( 'diffedit-editbutton' ) );
	if ( !mw.config.get( 'wgIsProbablyEditable' ) ) {
		addEditButton( messages.noPermission );
	} else if ( $( ".mw-diff-slot-header" ).length ) {
		addEditButton( mw.message( 'editpage-invalidcontentmodel-text', 'mixed content' ).text() );
	} else if ( !allowedContentModels.includes( contentModel ) ) {
		addEditButton( mw.message( 'editpage-invalidcontentmodel-text', contentModel ).text() );
	} else if ( newRevisionId !== currentRevisionId ) {
		addEditButton( messages.editTitleNewerRevs );
		addRefreshButton();
	} else {
		enumerateLines();
		addEditButton();
		$( '.diff-linetop, .diff-editable' ).keyup( function( e ) {
			if ( e.key === 'Escape' ) {
				toggleEditMode( 'disable' );
			} else if ( e.ctrlKey && e.key === 'Enter' ) {
				processEdit();
			}
		});
	}
}

if ( mw.config.get( 'wgDiffNewId' ) !== null ) {
	new mw.Api().loadMessagesIfMissing( [
		'edit', // Edit
		'publishchanges', // Publish
		'tooltip-publish', // Publish these changes
		'cancel', // Cancel
		'accesskey-publish', // s
		'accesskey-summary', // b
		'editpage-invalidcontentmodel-text', // Invalid content model $1
		'revisionslider-label-comment', // Edit summary
		'tooltip-summary', // Summary tooltip
		'parentheses' // ($1)
	] ).done( function( data ) {
		initDiffedit( jQuery, mediaWiki, OO );
	} ).fail( function( err ) {
		mw.notify( err, { title: "diffedit error", type: "error" } );
	} );
}

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.
Kembali kehalaman sebelumnya