MediaWiki:Gadget-twinklefluff.js: Perbedaan revisi

Repo at 5c1e7e3: Update from Github
(Repo at a491314: tracking branch 'upstream/master'; don't create rollback links for single-revision pages on contribs; Remove overly parsimonious check for diffs, blocked links if diff content hidden; sort some functions from #562 into the `Twinkle.fluff` object; Fix bug on page preview)
(Repo at 5c1e7e3: Update from Github)
// <nowiki>
 
 
(function($) {
 
 
*** twinklefluff.js: Revert/rollback module
****************************************
* Mode of invocation: Links on historycontributions, contributionsrecent changes, history, and diff pages
* Active on: Diff pages, history pages, contributions pagesSpecial:RecentChanges(Linked),
and Special:Contributions
* Config directives in: TwinkleConfig
*/
 
*/
 
Twinkle.fluff = function twinklefluff() {
// A list of usernames, usually only bots, that vandalism revert is jumped over; that is,
spanTag: function( color, content ) {
// if vandalism revert was chosen on such username, then its target is on the revision before.
var span = document.createElement( 'span' );
// This is for handling quick bots that makes edits seconds after the original edit is made.
// This only affects vandalism rollback; for good faith rollback, it will stop, indicating a bot
// has no faith, and for normal rollback, it will rollback that edit.
Twinkle.fluff.whiteList = [
'AnomieBOT',
'SineBot'
];
 
if (mw.config.get('wgIsProbablyEditable')) {
// Only proceed if the user can actually edit the page
// in question (ignored for contributions, see #632).
// wgIsProbablyEditable should take care of
// namespace/contentModel restrictions as well as
// explicit protections; it won't take care of
// cascading or TitleBlacklist restrictions
if (mw.config.get('wgDiffNewId') || mw.config.get('wgDiffOldId')) { // wgDiffOldId included for clarity in if else loop [[phab:T214985]]
mw.hook('wikipage.diff').add(function () { // Reload alongside the revision slider
Twinkle.fluff.addLinks.diff();
});
} else if (mw.config.get('wgAction') === 'view' && mw.config.get('wgCurRevisionId') !== mw.config.get('wgRevisionId')) {
Twinkle.fluff.addLinks.oldid();
} else if (mw.config.get('wgAction') === 'history') {
Twinkle.fluff.addLinks.history();
}
} else if (mw.config.get('wgNamespaceNumber') === -1) {
Twinkle.fluff.skipTalk = !Twinkle.getPref('openTalkPageOnAutoRevert');
Twinkle.fluff.rollbackInPlace = Twinkle.getPref('rollbackInPlace');
 
if (mw.config.get('wgCanonicalSpecialPageName') === 'Contributions') {
Twinkle.fluff.addLinks.contributions();
} else if (mw.config.get('wgCanonicalSpecialPageName') === 'Recentchanges' || mw.config.get('wgCanonicalSpecialPageName') === 'Recentchangeslinked') {
// Reload with recent changes updates
// structuredChangeFilters.ui.initialized is just on load
mw.hook('wikipage.content').add(function(item) {
if (item.is('div')) {
Twinkle.fluff.addLinks.recentchanges();
}
});
}
}
};
 
Twinkle.fluff.skipTalk = null;
Twinkle.fluff.rollbackInPlace = null;
 
// Consolidated construction of fluff links
Twinkle.fluff.linkBuilder = {
spanTag: function(color, content) {
var span = document.createElement('span');
span.style.color = color;
span.appendChild( document.createTextNode( content ) );
return span;
},
buildLink: function(color, text) {
var link = document.createElement('a');
link.appendChild(Twinkle.fluff.linkBuilder.spanTag('Black', '['));
link.appendChild(Twinkle.fluff.linkBuilder.spanTag(color, text));
link.appendChild(Twinkle.fluff.linkBuilder.spanTag('Black', ']'));
link.href = '#';
return link;
},
 
/**
auto: function() {
* @param {string} vandal - Username of the editor being reverted (required)
if( mw.config.get('wgRevisionId') !== mw.config.get('wgCurRevisionId') ) {
* @param {boolean} inline - True to create two links in a span, false
// not latest revision
* to create three links in a div (optional)
alert("Tidak dapat mengembalikan revisi, halaman sudah berubah saat ini.");
* @param {number|string} [rev=wgCurRevisionId] - Revision ID being reverted (optional)
return;
* @param {string} [page=wgPageName] - Page being reverted (optional)
*/
rollbackLinks: function(vandal, inline, rev, page) {
var elem = inline ? 'span' : 'div';
var revNode = document.createElement(elem);
 
rev = parseInt(rev, 10);
if (rev) {
revNode.setAttribute('id', 'tw-revert' + rev);
} else {
revNode.setAttribute('id', 'tw-revert');
}
 
var normNode = document.createElement('strong');
var vandNode = document.createElement('strong');
 
var normLink = Twinkle.fluff.linkBuilder.buildLink('SteelBlue', 'kembalikan');
var vandLink = Twinkle.fluff.linkBuilder.buildLink('Red', 'vandalisme');
 
$(normLink).click(function() {
Twinkle.fluff.revert('norm', vandal, rev, page);
Twinkle.fluff.disableLinks(revNode);
});
$(vandLink).click(function() {
Twinkle.fluff.revert('vand', vandal, rev, page);
Twinkle.fluff.disableLinks(revNode);
});
 
vandNode.appendChild(vandLink);
normNode.appendChild(normLink);
 
var separator = inline ? ' ' : ' || ';
 
if (!inline) {
var agfNode = document.createElement('strong');
var agfLink = Twinkle.fluff.linkBuilder.buildLink('DarkOliveGreen', 'kembalikan (AGF)');
$(agfLink).click(function() {
Twinkle.fluff.revert('agf', vandal, rev, page);
// Twinkle.fluff.disableLinks(revNode); // rollbackInPlace not relevant for any inline situations
});
agfNode.appendChild(agfLink);
revNode.appendChild(agfNode);
}
revNode.appendChild(document.createTextNode(separator));
revNode.appendChild(normNode);
revNode.appendChild(document.createTextNode(separator));
revNode.appendChild(vandNode);
 
return revNode;
var vandal = $("#mw-diff-ntitle2").find("a.mw-userlink").text();
 
Twinkle.fluff.revert( Morebits.queryString.get( 'twinklerevert' ), vandal, true );
},
 
// Build [restore this revision] links
restoreThisRevisionLink: function(revisionRef, inline) {
// If not a specific revision number, should be wgDiffNewId/wgDiffOldId/wgRevisionId
revisionRef = typeof revisionRef === 'number' ? revisionRef : mw.config.get(revisionRef);
 
var elem = inline ? 'span' : 'div';
var revertToRevisionNode = document.createElement(elem);
 
revertToRevisionNode.setAttribute('id', 'tw-revert-to-' + revisionRef);
revertToRevisionNode.style.fontWeight = 'bold';
 
var revertToRevisionLink = Twinkle.fluff.linkBuilder.buildLink('SaddleBrown', 'kembalikan revisi ini');
$(revertToRevisionLink).click(function() {
Twinkle.fluff.revertToRevision(revisionRef);
});
 
if (inline) {
revertToRevisionNode.appendChild(document.createTextNode(' '));
}
revertToRevisionNode.appendChild(revertToRevisionLink);
return revertToRevisionNode;
}
};
 
 
Twinkle.fluff.addLinks = {
contributions: function() {
// $('sp-contributions-footer-anon-range') relies on the fmbox
// id in [[MediaWiki:Sp-contributions-footer-anon-range]] and
// is used to show rollback/vandalism links for IP ranges
if( mw.config.get('wgCanonicalSpecialPageName') === "Contributions" && (mw.config.exists('wgRelevantUserName') || !!$('#sp-contributions-footer-anon-range')[0])) {
// Get the username these contributions are for
var username = mw.config.get('wgRelevantUserName');
if( (Twinkle.getPref('showRollbackLinks').indexOf('contribs') !== -1 ||
( mw.config.get('wgUserName') !== username && Twinkle.getPref('showRollbackLinks').indexOf('others') !== -1 ) ||
( mw.config.get('wgUserName') === username && Twinkle.getPref('showRollbackLinks').indexOf('mine') !== -1 ) ) {
var list = $("'#mw-content-text"').find("'ul li:has(span.mw-uctop)":has(.mw-changeslist-diff)');
 
var revNode = document.createElement('strong');
var revLink = Twinkle.fluff.buildLink('SteelBlue', 'kembalikan');
revNode.appendChild(revLink);
 
var revVandNode = document.createElement('strong');
var revVandLink = Twinkle.fluff.buildLink('Red', 'vandalisme');
revVandNode.appendChild(revVandLink);
 
list.each(function(key, current) {
// revid is also available in the href of both
var href = $(current).find(".mw-changeslist-diff").attr("href");
// .mw-changeslist-date or .mw-changeslist-diff
if (href) {
var page = $(current).appendChildfind( document'.createTextNode(' mw-contributions-title') .text();
current.appendChild(Twinkle.fluff.linkBuilder.rollbackLinks(username, true, current.dataset.mwRevid, page));
var tmpNode = revNode.cloneNode( true );
tmpNode.firstChild.setAttribute( 'href', href + '&' + Morebits.queryString.create( { 'twinklerevert': 'norm' } ) );
current.appendChild( tmpNode );
current.appendChild( document.createTextNode(' ') );
tmpNode = revVandNode.cloneNode( true );
tmpNode.firstChild.setAttribute( 'href', href + '&' + Morebits.queryString.create( { 'twinklerevert': 'vand' } ) );
current.appendChild( tmpNode );
}
});
}
},
 
diffrecentchanges: function() {
if (Twinkle.getPref('showRollbackLinks').indexOf('recent') !== -1) {
// Add a [restore this revision] link to the older revision
// Latest and revertable (not page creations, logs, categorizations, etc.)
// Don't show if there's a single revision or weird diff (cur on latest)
var list = $('.mw-changeslist .mw-changeslist-last.mw-changeslist-src-mw-edit');
if (mw.config.get('wgDiffOldId') && (mw.config.get('wgDiffOldId') !== mw.config.get('wgDiffNewId'))) {
// Exclude top-level header if "group changes" preference is used
var revertToRevision = document.createElement('div');
// and find only individual lines or nested lines
revertToRevision.setAttribute( 'id', 'tw-revert-to-orevision' );
list = list.not('.mw-rcfilters-ui-highlights-enhanced-toplevel').find('.mw-changeslist-line-inner, td.mw-enhanced-rc-nested');
revertToRevision.style.fontWeight = 'bold';
 
list.each(function(key, current) {
var revertToRevisionLink = Twinkle.fluff.buildLink('SaddleBrown', 'kembalikan revisi ini');
var vandal = $(current).find('.mw-userlink').text();
revertToRevisionLink.href = "#";
var href = $(current).find('.mw-changeslist-diff').attr('href');
$(revertToRevisionLink).click(function(){
var rev = mw.util.getParamValue('diff', href);
Twinkle.fluff.revertToRevision(mw.config.get('wgDiffOldId').toString());
var page = current.dataset.targetPage;
current.appendChild(Twinkle.fluff.linkBuilder.rollbackLinks(vandal, true, rev, page));
});
revertToRevision.appendChild(revertToRevisionLink);
 
var otitle = document.getElementById('mw-diff-otitle1').parentNode;
otitle.insertBefore( revertToRevision, otitle.firstChild );
}
},
 
history: function() {
// Add either restore or rollback links to the newer revision
if (Twinkle.getPref('showRollbackLinks').indexOf('history') !== -1) {
// Don't show if there's a single revision or weird diff (prev on first)
// All revs
var ntitle = document.getElementById('mw-diff-ntitle1').parentNode;
var histList = $('#pagehistory li').toArray();
if( document.getElementById('differences-nextlink') ) {
// Not latest revision
var revertToRevisionN = document.createElement('div');
revertToRevisionN.setAttribute( 'id', 'tw-revert-to-nrevision' );
revertToRevisionN.style.fontWeight = 'bold';
 
// On first page of results, so add revert/rollback
var revertToRevisionNLink = Twinkle.fluff.buildLink('SaddleBrown', 'kembalikan revisi ini');
// links to the top revision
revertToRevisionNLink.href = "#";
if (!$('.mw-firstlink').length) {
$(revertToRevisionNLink).click(function(){
var first = histList.shift();
Twinkle.fluff.revertToRevision(mw.config.get('wgDiffNewId').toString());
var vandal = first.querySelector('.mw-userlink').text;
});
revertToRevisionN.appendChild(revertToRevisionNLink);
 
first.appendChild(Twinkle.fluff.linkBuilder.rollbackLinks(vandal, true));
ntitle.insertBefore( revertToRevisionN, ntitle.firstChild );
}
} else if( Twinkle.getPref('showRollbackLinks').indexOf('diff') !== -1 && mw.config.get('wgDiffOldId') && (mw.config.get('wgDiffOldId') !== mw.config.get('wgDiffNewId') || document.getElementById('differences-prevlink'))) {
var vandal = $("#mw-diff-ntitle2").find("a").first().text();
 
// oldid
var revertNode = document.createElement('div');
histList.forEach(function(rev) {
revertNode.setAttribute( 'id', 'tw-revert' );
// From restoreThisRevision, non-transferable
 
var agfNodehref = documentrev.createElementquerySelector('strong.mw-changeslist-date').href;
var vandNodeoldid = documentparseInt(mw.createElementutil.getParamValue('strongoldid', href), 10);
var normNode = document.createElement('strong');
 
var agfLink = rev.appendChild(Twinkle.fluff.buildLinklinkBuilder.restoreThisRevisionLink('DarkOliveGreen'oldid, 'kembalikan (AGFtrue)');
var vandLink = Twinkle.fluff.buildLink('Red', 'kembalikan (VANDAL)');
var normLink = Twinkle.fluff.buildLink('SteelBlue', 'kembalikan');
 
agfLink.href = "#";
vandLink.href = "#";
normLink.href = "#";
$(agfLink).click(function(){
Twinkle.fluff.revert('agf', vandal);
});
$(vandLink).click(function(){
Twinkle.fluff.revert('vand', vandal);
});
$(normLink).click(function(){
Twinkle.fluff.revert('norm', vandal);
});
 
agfNode.appendChild(agfLink);
vandNode.appendChild(vandLink);
normNode.appendChild(normLink);
 
}
revertNode.appendChild( agfNode );
},
revertNode.appendChild( document.createTextNode(' || ') );
 
revertNode.appendChild( normNode );
diff: function() {
revertNode.appendChild( document.createTextNode(' || ') );
// Autofill user talk links on diffs with vanarticle for easy warning, but don't autowarn
revertNode.appendChild( vandNode );
var warnFromTalk = function(xtitle) {
var talkLink = $('#mw-diff-' + xtitle + '2 .mw-usertoollinks a').first();
if (talkLink.length) {
var extraParams = 'vanarticle=' + mw.util.rawurlencode(Morebits.pageNameNorm) + '&' + 'noautowarn=true';
// diffIDs for vanarticlerevid
extraParams += '&vanarticlerevid=';
extraParams += xtitle === 'otitle' ? mw.config.get('wgDiffOldId') : mw.config.get('wgDiffNewId');
 
var href = talkLink.attr('href');
if (href.indexOf('?') === -1) {
talkLink.attr('href', href + '?' + extraParams);
} else {
talkLink.attr('href', href + '&' + extraParams);
}
}
};
 
// Older revision
warnFromTalk('otitle'); // Add quick-warn link to user talk link
// Don't load if there's a single revision or weird diff (cur on latest)
if (mw.config.get('wgDiffOldId') && (mw.config.get('wgDiffOldId') !== mw.config.get('wgDiffNewId'))) {
// Add a [restore this revision] link to the older revision
var oldTitle = document.getElementById('mw-diff-otitle1').parentNode;
oldTitle.insertBefore(Twinkle.fluff.linkBuilder.restoreThisRevisionLink('wgDiffOldId'), oldTitle.firstChild);
}
 
// Newer revision
warnFromTalk('ntitle'); // Add quick-warn link to user talk link
// Add either restore or rollback links to the newer revision
// Don't show if there's a single revision or weird diff (prev on first)
if (document.getElementById('differences-nextlink')) {
// Not latest revision, add [restore this revision] link to newer revision
var newTitle = document.getElementById('mw-diff-ntitle1').parentNode;
newTitle.insertBefore(Twinkle.fluff.linkBuilder.restoreThisRevisionLink('wgDiffNewId'), newTitle.firstChild);
} else if (Twinkle.getPref('showRollbackLinks').indexOf('diff') !== -1 && mw.config.get('wgDiffOldId') && (mw.config.get('wgDiffOldId') !== mw.config.get('wgDiffNewId') || document.getElementById('differences-prevlink'))) {
var vandal = $('#mw-diff-ntitle2').find('a').first().text();
var ntitle = document.getElementById('mw-diff-ntitle1').parentNode;
 
ntitle.insertBefore( revertNodeTwinkle.fluff.linkBuilder.rollbackLinks(vandal), ntitle.firstChild );
}
},
 
oldid: function() { // Add a [restore this revision] link on old revisions
var revertToRevisiontitle = document.createElementgetElementById('divmw-revision-info').parentNode;
title.insertBefore(Twinkle.fluff.linkBuilder.restoreThisRevisionLink('wgRevisionId'), title.firstChild);
revertToRevision.setAttribute( 'id', 'tw-revert-to-orevision' );
revertToRevision.style.fontWeight = 'bold';
 
var revertToRevisionLink = Twinkle.fluff.buildLink('SaddleBrown', 'kembalikan revisi ini');
revertToRevisionLink.href = "#";
$(revertToRevisionLink).click(function(){
Twinkle.fluff.revertToRevision(mw.config.get('wgRevisionId').toString());
});
revertToRevision.appendChild(revertToRevisionLink);
var otitle = document.getElementById('mw-revision-info').parentNode;
otitle.insertBefore( revertToRevision, otitle.firstChild );
}
};
 
Twinkle.fluff.revertdisableLinks = function revertPagedisablelinks( type, vandal, autoRevert, rev, page parentNode) {
// Array.from not available in IE11 :(
$(parentNode).children().each(function(_ix, node) {
node.innerHTML = node.textContent; // Feels like cheating
$(node).css('font-weight', 'normal').css('color', 'darkgray');
});
};
 
 
Twinkle.fluff.revert = function revertPage(type, vandal, rev, page) {
if (mw.util.isIPv6Address(vandal)) {
vandal = Morebits.sanitizeIPv6(vandal);
var revid = rev || mw.config.get('wgCurRevisionId');
 
if (Twinkle.fluff.rollbackInPlace) {
Morebits.status.init( document.getElementById('mw-content-text') );
var notifyStatus = document.createElement('span');
$( '#catlinks' ).remove();
mw.notify(notifyStatus, {
autoHide: false,
title: 'Rollback on ' + page,
tag: 'twinklefluff_' + rev // Shouldn't be necessary given disableLink
});
Morebits.status.init(notifyStatus);
} else {
Morebits.status.init(document.getElementById('mw-content-text'));
$('#catlinks').remove();
}
 
var params = {
user: vandal,
pagename: pagename,
revid: revid,
autoRevert: !!autoRevert
};
var query = {
'prop': ['info', 'revisions', 'flagged'],
'titles': pagename,
'intestactions': 'edit',
'rvlimit': 50, // max possible
'rvlimit': 50, // intentionally limited
'rvprop': [ 'ids', 'timestamp', 'user', 'comment' ],
'intokencurtimestamp': 'edit',
'meta': 'tokens',
'type': 'csrf'
};
var wikipedia_api = new Morebits.wiki.api( 'Mengambil data revisi yang lebih awal', query, Twinkle.fluff.callbacks.main );
wikipedia_api.params = params;
wikipedia_api.post();
};
 
Twinkle.fluff.revertToRevision = function revertToRevision( oldrev ) {
 
Morebits.status.init( document.getElementById('mw-content-text') );
 
var query = {
'action': 'query',
'prop': ['info', 'revisions'],
'titles': mw.config.get('wgPageName'),
'rvlimit': 1,
'rvstartid': oldrev,
'rvprop': [ 'ids', 'timestamp', 'user', 'comment' ],
'intokenformat': 'editxml',
'formatcurtimestamp': 'xml',
'meta': 'tokens',
'type': 'csrf'
};
var wikipedia_api = new Morebits.wiki.api( 'Mengambil data revisi yang lebih awal', query, Twinkle.fluff.callbacks.toRevision.main );
wikipedia_api.params = { rev: oldrev };
wikipedia_api.post();
};
 
Twinkle.fluff.userIpLink = function( user ) {
return (mw.util.isIPAddress(user) ? "'[[Special:Contributions/"' : "'[[:User:" ') + user + "'|"' + user + "']]"';
};
 
Twinkle.fluff.callbacks = {
toRevision: function(apiobj) {
var xmlDoc = apiobj.responseXML;
main: function( self ) {
var xmlDoc = self.responseXML;
 
var lastrevid = parseInt( $(xmlDoc).find('page').attr('lastrevid'), 10);
var touched = $(xmlDoc).find('page').attr('touched');
var starttimestamploadtimestamp = $(xmlDoc).find('pageapi').attr('starttimestampcurtimestamp');
var edittokencsrftoken = $(xmlDoc).find('pagetokens').attr('edittokencsrftoken');
var revertToRevID = parseInt($(xmlDoc).find('rev').attr('revid'), 10);
var revertToUser = $(xmlDoc).find('rev').attr('user');
 
if (revertToRevID !== selfapiobj.params.rev) {
selfapiobj.statitemstatelem.error( 'The retrieved revision does not match the requested revision. Stopping revert.' );
return;
}
 
var optional_summary = prompt('Please "Berikanspecify alasana pengembalianreason inifor the revert: "', "" ''); // padded out to widen prompt in Firefox
if (optional_summary === null) {
apiobj.statelem.error('Dibatalkan oleh pengguna.');
{
return;
self.statelem.error( 'Dibatalkan oleh pengguna.' );
}
return;
var summary = Twinkle.fluff.formatSummary('Reverted to revision ' + revertToRevID + ' by $USER', revertToUser, optional_summary);
}
var summary = Twinkle.fluff.formatSummary("Dikembalikan ke revisi " + revertToRevID + " oleh $USER", revertToUser, optional_summary);
 
var query = {
'action': 'edit',
'title': mw.config.get('wgPageName'),
'summary': summary,
'token': edittokencsrftoken,
'undo': lastrevid,
'undoafter': revertToRevID,
'basetimestamp': touched,
'starttimestamp': starttimestamploadtimestamp,
'watchlist': Twinkle.getPref('watchRevertedPages').indexOf( 'torev' ) !== -1 ? 'watch' : undefined,
'minor': Twinkle.getPref('markRevertedPagesAsMinor').indexOf( 'torev' ) !== -1 ? true : undefined
};
 
Morebits.wiki.actionCompleted.redirect = mw.config.get('wgPageName');
Morebits.wiki.actionCompleted.notice = "'Pengembalian selesai"';
 
var wikipedia_api = new Morebits.wiki.api( 'Menyimpan isiSaving yangreverted dikembalikancontents', query, Twinkle.fluff.callbacks.complete, selfapiobj.statelem);
wikipedia_api.params = selfapiobj.params;
wikipedia_api.post();
 
}
},
main: function( self apiobj) {
var xmlDoc = selfapiobj.responseXML;
 
varif lastrevid = parseInt(typeof $(xmlDoc).find('pageactions').attr('lastrevidedit'), 10=== 'undefined'); {
self.statelem.error("Unable to edit the page, it's probably protected.");
return;
}
 
var lastrevid = parseInt($(xmlDoc).find('page').attr('lastrevid'), 10);
var touched = $(xmlDoc).find('page').attr('touched');
var starttimestamploadtimestamp = $(xmlDoc).find('pageapi').attr('starttimestampcurtimestamp');
var edittokencsrftoken = $(xmlDoc).find('pagetokens').attr('edittokencsrftoken');
var lastuser = $(xmlDoc).find('rev').attr('user');
 
var revs = $(xmlDoc).find('rev');
 
var statelem = apiobj.statelem;
if( revs.length < 1 ) {
var params = apiobj.params;
self.statelem.error( 'Tidak memiliki satu pun revisi tambahan, sehingga tidak mungkin untuk dikembalikan' );
 
if (revs.length < 1) {
statelem.error('Tidak memiliki satu pun revisi tambahan, sehingga tidak mungkin untuk dikembalikan.');
return;
}
var top = revs[0];
if ( lastrevid < self.params.revid ) {
Morebits.status.error( 'Error', [ 'Penanda revisi terakhir yang diperoleh dari peladen, ', Morebits.htmlNode( 'strong', lastrevid ), ', kurang dari penanda revisi yang saat ini ditampilkan. Ini menandakan bahwa revisi saat ini sudah dihapus, peladen sedang tersendat, atau data buruk yang diterima. Proses aka dihentikan.' ] );
return;
}
var index = 1;
if ( self.params.revid !== lastrevid ) {
Morebits.status.warn( 'Peringatan', [ 'Revisi terakhir ', Morebits.htmlNode( 'strong', lastrevid ), ' tidak sesuai dengan revisi kami ', Morebits.htmlNode( 'strong', self.params.revid ) ] );
if ( lastuser === self.params.user ) {
switch ( self.params.type ) {
case 'vand':
Morebits.status.info( 'Informasi', [ 'Revisi terakhir dibuat oleh ', Morebits.htmlNode( 'strong', self.params.user ) , '. Karena dianggap sebagai vandalisme, kami lanjutkan pengembaliannya.' ]);
break;
case 'agf':
Morebits.status.warn( 'Warning', [ 'Revisi terakhir dibuat oleh ', Morebits.htmlNode( 'strong', self.params.user ) , '. Karena dianggap sebagai niat baik, pengembalian ini dihentikan, di mana masalah mungkin dapat diatasi.' ]);
return;
default:
Morebits.status.warn( 'Perhatian', [ 'Revisi terakhir dibuat oleh ', Morebits.htmlNode( 'strong', self.params.user ) , ', namun kami akan menghentikan proses pengembalian.' ] );
return;
}
} else if (params.type === 'vand' &&
}
Twinkle.fluff.whiteList.indexOf(top.getAttribute('user')) !== -1 && revs.length > 1 &&
else if(self.params.type === 'vand' &&
Twinkle.fluff.whiteList.indexOf( toprevs[1].getAttribute( 'userpageId' ) ) !=== -1 && revsparams.length > 1revid) &&{
Morebits.status.info('Informasi', [ 'Revisi terakhir dibuat oleh ', Morebits.htmlNode('strong', lastuser), ', bot yang tepercaya, dan revisi sebelumnya dibuat oleh pengguna vandalisme, pengembalian dilanjutkan.' ]);
revs[1].getAttribute( 'pageId' ) === self.params.revid) {
Morebits.status.info( 'Informasi', [ 'Revisi terakhir dibuat oleh ', Morebits.htmlNode( 'strong', lastuser ), ', bot yang tepercaya, dan revisi sebelumnya dibuat oleh pengguna vandalisme, pengembalian dilanjutkan.' ] );
index = 2;
} else {
Morebits.status.error( 'Galat', [ 'Revisi terakhir dibuat oleh ', Morebits.htmlNode( 'strong', lastuser ), ', sehingga mungkin telah dikembalikan, akan menghentikan pengembalian ini.'] );
return;
}
}
 
if( (Twinkle.fluff.whiteList.indexOf( self.params.user ) !== -1 ) {
switch ( self.params.type ) {
case 'vand':
Morebits.status.info( 'InformasiInfo', [ 'Pengembalian vandalisme dipilih pada ', Morebits.htmlNode( 'strong', self.params.user ), '. Karena bot ini masuk daftar putih, kami menganggap Anda akan mengembalikan vandalisme yang dibuat oleh pengguna sebelumnya.' ] );
index = 2;
self. params.user = revs[1].getAttribute( 'user' );
break;
case 'agf':
Morebits.status.warn( 'Pemberitahuan', [ 'Pengembalian dengan niat baik dipilih pada ', Morebits.htmlNode( 'strong', self.params.user ), '. Ini adalah bot yang masuk daftar putih, dan karena bot tidak punya niat, pengembalian ANB tidak dilanjutkan.' ] );
return;
case 'norm':
/* falls through */
default:
var cont = confirm( 'Pengembalian normal sudah dipilih, namun suntingan terakhir dibuat oleh bot yang masuk daftar putih (' + self.params.user + '). Ingin melanjutkan revisi sebelumnya saja?' );
if ( cont ) {
Morebits.status.info( 'InformasiInfo', [ 'Pengembalian normal dipilih pada ', Morebits.htmlNode( 'strong', self.params.user ), '. Ini adalah bot daftar putih, dan dengan konfirmasi, kami akan mengembalikan revisi sebelumnya saja.' ] );
index = 2;
self. params.user = revs[1].getAttribute( 'user' );
} else {
Morebits.status.warn( 'Pemberitahuan', [ 'Pengembalian normal dipilih pada ', Morebits.htmlNode( 'strong', self.params.user ), '. Ini adalah bot daftar putih, namun dengan konfirmasi, pengembalian revisi atas akan diproses.' ] );
}
break;
}
}
var count = 0;
 
for( (var i = index; i < revs.length; ++i ) {
++count;
if( (revs[i].getAttribute( 'user' ) !== self.params.user ) {
found = i;
break;
}
 
if ( ! found ) {
self.statelem.error( [ 'Tidak dapat ditemukan revisi sebelumnya. Mungkin ', Morebits.htmlNode( 'strong', self.params.user ), ' adalah satu-satunya penyunting, atau pengguna tersebut telah melakukan ' + Twinkle.getPref('revertMaxRevisions') + ' suntingan berturut-turut.' ] );
return;
}
 
if ( ! count ) {
Morebits.status.error( 'Galat', "'Tidak bisa membatalkan nol revisi. Ini mungkin dikarenakan revisi tersebut telah dibatalkan namun penanda revisi masih tetap sama." ');
return;
}
 
var good_revision = revs[ found ];
var userHasAlreadyConfirmedAction = false;
if (self.params.type !== 'vand' && count > 1) {
if ( !confirm( self.params.user + ' telah melakukan ' + count + ' suntingan berturut-turut. Apakah Anda yakin mau membatalkan semuanya?') ) {
Morebits.status.info( 'Notice', 'Menghentikan pembatalan.' );
return;
}
}
 
self.params.count = count;
 
self.params.goodid = good_revision.getAttribute( 'revid' );
self.params.gooduser = good_revision.getAttribute( 'user' );
 
self.statelem.status( [ ' revisi ', Morebits.htmlNode( 'strong', self.params.goodid ), ' yang dilakukan ', Morebits.htmlNode( 'strong', count ), ' suntingan yang lalu oleh ', Morebits.htmlNode( 'strong', self.params.gooduser ) ] );
 
var summary, extra_summary;
switch ( self.params.type ) {
case 'agf':
extra_summary = prompt( "'Komentar tambahan untuk ringkasan suntingan: "', "" ''); // padded out to widen prompt in Firefox
if (extra_summary === null) {
statelem.error('Dibatalkan oleh pengguna.');
{
return;
self.statelem.error( 'Dibatalkan oleh pengguna.' );
return;}
userHasAlreadyConfirmedAction = true;
}
userHasAlreadyConfirmedAction = true;
 
summary = Twinkle.fluff.formatSummary("'Membatalkan suntingan [[WP:ANB|berniat baik]] oleh $USER"', self.params.user, extra_summary);
break;
 
case 'vand':
 
summary = "'Membatalkan "' + self.params.count + (self.params.count > 1 ? ' suntingan' : ' suntingan') + "' oleh [[Special:Contributions/"' +
self.params.user + "'|"' + self.params.user + "']] ([[User talk:"' + self.params.user + "'|bicara]]) ke revisi terakhir oleh "' +
self.params.gooduser + Twinkle.getPref('summaryAd');
break;
 
case 'norm':
/* falls through */
default:
if ( Twinkle.getPref('offerReasonOnNormalRevert') ) {
extra_summary = prompt( "'Komentar tambahan untuk ringkasan suntingan: "', "" ''); // padded out to widen prompt in Firefox
if (extra_summary === null) {
statelem.error('Dibatalkan oleh pengguna.');
{
return;
self.statelem.error( 'Dibatalkan oleh pengguna.' );
return;}
userHasAlreadyConfirmedAction = true;
}
userHasAlreadyConfirmedAction = true;
}
 
summary = Twinkle.fluff.formatSummary("'Membatalkan "' + selfparams.count + (params.count > 1 ? ' edits' : ' edit') +
"' suntingan olehby $USER"', self.params.user, extra_summary);
break;
}
 
if (Twinkle.getPref('confirmOnFluff') && !userHasAlreadyConfirmedAction && !confirm("'Membatalkan halaman: Anda yakin?"')) {
self.statelem.error( 'Dibatalkan oleh pengguna.' );
return;
}
 
// Decide whether to notify the user on success
var query;
if( (!selfTwinkle.paramsfluff.autoRevertskipTalk ||&& Twinkle.getPref('openTalkPageOnAutoRevertopenTalkPage').indexOf(params.type) !== -1 &&
mw.config.get('wgUserName') !== params.user) {
Twinkle.getPref('openTalkPage').indexOf( self.params.type ) !== -1 &&
params.notifyUser = true;
mw.config.get('wgUserName') !== self.params.user ) {
Morebits.status.info( 'Informasi', [ 'Membuka halaman penyuntingan halaman pembicaraan pengguna ', Morebits.htmlNode( 'strong', self.params.user ) ] );
 
query = {
'title': 'User talk:' + self.params.user,
'action': 'edit',
'preview': 'yes',
'vanarticle': self.params.pagename.replace(/_/g, ' '),
'vanarticlerevid': self.params.revid,
'vanarticlegoodrevid': self.params.goodid,
'type': self.params.type,
'count': self.params.count
};
 
switch( Twinkle.getPref('userTalkPageMode') ) {
case 'tab':
window.open( mw.util.wikiScript('index') + '?' + Morebits.queryString.create( query ), '_blank' );
break;
case 'blank':
window.open( mw.util.wikiScript('index') + '?' + Morebits.queryString.create( query ), '_blank',
'location=no,toolbar=no,status=no,directories=no,scrollbars=yes,width=1200,height=800' );
break;
case 'window':
/* falls through */
default:
window.open( mw.util.wikiScript('index') + '?' + Morebits.queryString.create( query ),
( window.name === 'twinklewarnwindow' ? '_blank' : 'twinklewarnwindow' ),
'location=no,toolbar=no,status=no,directories=no,scrollbars=yes,width=1200,height=800' );
break;
}
}
 
// figure out whether we need to/can review the edit
var $flagged = $(xmlDoc).find('flagged');
if ((Morebits.userIsInGroup('reviewer') || Morebits.userIsInGroup('sysop')userIsSysop) &&
$flagged.length &&
$flagged.attr("'stable_revid"') >= self.params.goodid &&
$flagged.attr("'pending_since"')) {
self.params.reviewRevert = true;
self.params.edittokencsrftoken = edittokencsrftoken;
}
 
var query = {
'action': 'edit',
'title': self.params.pagename,
'summary': summary,
'token': edittokencsrftoken,
'undo': lastrevid,
'undoafter': self.params.goodid,
'basetimestamp': touched,
'starttimestamp': starttimestamploadtimestamp,
'watchlist' : Twinkle.getPref('watchRevertedPages').indexOf( self.params.type ) !== -1 ? 'watch' : undefined,
'minor': Twinkle.getPref('markRevertedPagesAsMinor').indexOf( self.params.type ) !== -1 ? true : undefined
};
 
if (!Twinkle.fluff.rollbackInPlace) {
Morebits.wiki.actionCompleted.redirect = self.params.pagename;
Morebits.wiki.actionCompleted.noticeredirect = "Pembatalan selesai"params.pagename;
}
Morebits.wiki.actionCompleted.notice = 'Pembatalan selesai';
 
var wikipedia_api = new Morebits.wiki.api( 'Menyimpan isi yang telah dibatalkan', query, Twinkle.fluff.callbacks.complete, self.statelem);
wikipedia_api.params = self.params;
wikipedia_api.post();
 
var xml = apiobj.getXML();
var $edit = $(xml).find('edit');
 
var blacklist = $edit.attr('spamblacklist');
if (blacklist$(xml).find('captcha').length > 0) {
apiobj.statelem.error('Could not rollback, because the wiki server wanted you to fill out a CAPTCHA.');
var code = document.createElement('code');
code.style.fontFamily = "monospace";
code.appendChild(document.createTextNode(blacklist));
apiobj.statelem.error(['Tidak dapat membatalkan karena URL ', code, ' berada dalam daftar hitam spam.']);
} else if ( $(xml).find('captcha').length > 0 ) { // TODO: Translate!
apiobj.statelem.error("Could not rollback, because the wiki server wanted you to fill out a CAPTCHA.");
} else if ( $edit.attr('code') === 'abusefilter-disallowed' ) { // TODO: Translate!
apiobj.statelem.error('The edit was disallowed by the edit filter rule "' + $edit.attr('info').substring(17) + '".');
} else if ( $edit.attr('info') && $edit.attr('info').indexOf('Hit AbuseFilter:') === 0 ) { // TODO: Translate!
var div = document.createElement('div');
div.className = "toccolours";
div.style.fontWeight = "normal";
div.style.color = "black";
div.innerHTML = $edit.attr('warning');
apiobj.statelem.error([ 'The following warning was returned by the edit filter: ', div, 'If you wish to proceed with the rollback, please reload this page (F5 or Ctrl+R) and carry it out again. This warning will not appear a second time.' ]);
} else if ($edit.attr('nochange') === '') {
apiobj.statelem.warnerror("'Revisi yang dibatalkan sama dengan revisi terakhir: Tidak ada yang dapat dilakukan."');
} else {
apiobj.statelem.info("'done"');
var params = apiobj.params;
 
if (params.notifyUser) { // Only from main, not from toRevision
Morebits.status.info('Info', [ 'Opening user talk page edit form for user ', Morebits.htmlNode('strong', params.user) ]);
 
var windowQuery = {
'title': 'User talk:' + params.user,
'action': 'edit',
'preview': 'yes',
'vanarticle': params.pagename.replace(/_/g, ' '),
'vanarticlerevid': params.revid,
'vanarticlegoodrevid': params.goodid,
'type': params.type,
'count': params.count
};
 
switch (Twinkle.getPref('userTalkPageMode')) {
case 'tab':
window.open(mw.util.getUrl('', windowQuery), '_blank');
break;
case 'blank':
window.open(mw.util.getUrl('', windowQuery), '_blank',
'location=no,toolbar=no,status=no,directories=no,scrollbars=yes,width=1200,height=800');
break;
case 'window':
/* falls through */
default:
window.open(mw.util.getUrl('', windowQuery),
window.name === 'twinklewarnwindow' ? '_blank' : 'twinklewarnwindow',
'location=no,toolbar=no,status=no,directories=no,scrollbars=yes,width=1200,height=800');
break;
}
}
 
 
// review the revert, if needed
'action': 'review',
'revid': $edit.attr('newrevid'),
'token': apiobj.params.edittokencsrftoken,
'comment': Twinkle.getPref('summaryAd').trim()
};
// a contributions or contributions+talk link if it doesn't push the edit summary
// over the 255-byte limit
var resultLen = unescape(encodeURIComponent(result.replace("'$USER"', ""''))).length;
var contribsLink = "'[[Special:Contributions/"' + userName + "'|"' + userName + "']]"';
var contribsLen = unescape(encodeURIComponent(contribsLink)).length;
if (resultLen + contribsLen <= 255) {
var talkLink = "' ([[User talk:"' + userName + "'|bicara]])"';
if (resultLen + contribsLen + unescape(encodeURIComponent(talkLink)).length <= 255) {
result = Morebits.string.safeReplace(result, "'$USER"', contribsLink + talkLink);
} else {
result = Morebits.string.safeReplace(result, "'$USER"', contribsLink);
}
} else {
result = Morebits.string.safeReplace(result, "'$USER"', userName);
}
 
return result;
};
 
Twinkle.fluff.init = function twinklefluffinit() {
if (Twinkle.userAuthorized)
{
// A list of usernames, usually only bots, that vandalism revert is jumped over; that is,
// if vandalism revert was chosen on such username, then its target is on the revision before.
// This is for handling quick bots that makes edits seconds after the original edit is made.
// This only affects vandalism rollback; for good faith rollback, it will stop, indicating a bot
// has no faith, and for normal rollback, it will rollback that edit.
Twinkle.fluff.whiteList = [
'AnomieBOT',
'SineBot'
];
 
if ( Morebits.queryString.exists( 'twinklerevert' ) ) {
Twinkle.fluff.auto();
} else if( mw.config.get('wgNamespaceNumber') === -1 && mw.config.get('wgCanonicalSpecialPageName') === "Contributions" ) {
Twinkle.fluff.contributions();
} else if( mw.config.get('wgDiffNewId') || mw.config.get('wgDiffOldId') ) { // wgDiffOldId included for clarity in if else loop [[phab:T214985]]
mw.hook( 'wikipage.diff' ).add( function () { // Reload alongside the revision slider
Twinkle.fluff.diff();
} );
} else if( mw.config.get('wgAction') === 'view' && mw.config.get('wgCurRevisionId') !== mw.config.get('wgRevisionId') ) {
Twinkle.fluff.oldid();
}
}
};
})(jQuery);
 
 
// </nowiki>