MediaWiki:Gadget-patrolRevisions.js

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.
( function ( mw, $ ) {

	var api;

	function markAsPatrolled( rcid ) {
		return api.postWithToken( 'patrol', {
			'action': 'patrol',
			'rcid': rcid,
		} );
	}

	function processNext( queue ) {
		if ( queue.length === 0 ) {
			return $.Deferred().resolve();
		}
		var rcid = queue.pop();
		return markAsPatrolled( rcid )
		.then(
			function () {
				return processNext( queue );
			},
			function () {
				return processNext( queue );
			}
		);
	}

	function onHistory() {
		if (
			mw.config.get( 'wgAction' ) !== 'history' ||
			mw.config.get('wgTranslatePageTranslation') === 'translation'
		) {
			return;
		}

		api.get( {
			'action': 'query',
			'list': 'recentchanges',
			'rcprop': 'ids',
			'rcshow': 'unpatrolled',
			'rclimit': 'max',
			'rctype': [ 'edit', 'new' ],
			'rctitle': mw.config.get( 'wgPageName' ),
		} ).then( function ( resp ) {
			var data = {};
			$.each( resp.query.recentchanges, function ( i, info ) {
				data[ info.revid ] = info.rcid;
			} );

			if ( $.isEmptyObject( data ) ) {
				return;
			}
			$( function() {
				$( '.mw-checkbox-toggle-controls' )
				.append(
					$( '<div>' )
					.addClass( 'mark-all-as-patrolled' )
					.css( {
						'float': 'right',
					} )
					.append(
						'[',
						$( '<a>' )
						.attr( 'href', '#' )
						.text( 'Mark all revisions as patrolled' )
						.on( 'click', function ( event ) {
							event.preventDefault();
							$( this ).replaceWith( '...' );
							processNext( Object.values( data ) )
							.then( function () {
								$( '.mark-all-as-patrolled' ).remove();
								$( '.row-unpatrolled' ).removeClass( 'row-unpatrolled' );
								mw.notify( 'All revisions have been marked as patrolled' );
							} );
						} ),
						']'
					)
				);
				var rows = Object.values( data ).length;
				$( '#pagehistory .mw-contributions-list li' ).each( function () {
					var $this = $( this );
					if ( data[ $this.data( 'mw-revid' ) ] ) {
						$this.addClass( 'row-unpatrolled' );
						return --rows !== 0;
					}
				} );
				mw.util.addCSS( '.row-unpatrolled { background-color: #fff0c2 !important; }' );
			} );
		} );
	}

	function onUserContribs() {
		if ( mw.config.get( 'wgCanonicalSpecialPageName' ) !== 'Contributions' ) {
			return;
		}

		if ( !mw.config.get( 'wgRelevantUserName' ) ) {
			return;
		}

		api.get( {
			'action': 'query',
			'list': 'recentchanges',
			'rcprop': 'ids',
			'rcshow': 'unpatrolled',
			'rclimit': 'max',
			'rctype': [ 'edit', 'new' ],
			'rcuser': mw.config.get( 'wgRelevantUserName' ),
		} ).then( function ( resp ) {
			var data = {};
			$.each( resp.query.recentchanges, function ( i, info ) {
				data[ info.revid ] = info.rcid;
			} );

			if ( $.isEmptyObject( data ) ) {
				return;
			}
			$( function() {
				// There might not be a navigation bar if there were not enough
				// changes
				$buttonGoesAfter = $( '.mw-pager-navigation-bar' );
				if ( $buttonGoesAfter.length === 0 ) {
					// go after search form
					$buttonGoesAfter = $( '.mw-htmlform-ooui-wrapper' );
				}
				$buttonGoesAfter.after(
					$( '<div>' )
					.addClass( 'mark-all-as-patrolled' )
					.css( {
						'float': 'right',
					} )
					.append(
						'[',
						$( '<a>' )
						.attr( 'href', '#' )
						.text( 'Mark all revisions as patrolled' )
						.on( 'click', function( event ) {
							event.preventDefault();
							$( this ).replaceWith( '...' );
							processNext( Object.values( data ) )
							.then( function() {
								$( '.mark-all-as-patrolled' ).remove();
								$( '.unpatrolled' ).remove();
								mw.notify( 'All user\'s revisions have been marked as patrolled' );
							} );
						} ),
						']'
					)
				);
				var marker = $( '<abbr>' )
					.attr( 'title', 'This change has not been patrolled yet' )
					.addClass( 'unpatrolled' )
					.html( '!' );
				var rows = Object.values( data ).length;
				$( '.mw-contributions-list > li' ).each( function () {
					var $this = $( this );
					if ( data[ $this.data( 'mw-revid' ) ] ) {
						$this.find( '.mw-changeslist-separator' ).eq( 1 ).after( [ ' ', marker.clone() ] );
						return --rows !== 0;
					}
				} );
			} );
		} );
	}

	function onDiff( $diff ) {
		if (
			!mw.config.get( 'wgDiffNewId' ) ||
			!mw.config.get( 'wgDiffOldId' ) ||
			mw.config.get('wgTranslatePageTranslation') === 'translation'
		) {
			return;
		}

		var $el = $diff.find( '.diff-multi' );
		if ( $el.length !== 1 ) {
			return;
		}

		var newId = mw.config.get( 'wgDiffNewId' ),
			oldId = mw.config.get( 'wgDiffOldId' );
		api.get( {
			'formatversion': 2,
			'action': 'query',
			'prop': 'revisions',
			'titles': mw.config.get( 'wgPageName' ),
			'rvprop': [ 'ids', 'timestamp' ],
			'rvlimit': 'max',
			'rvdir': 'older',
			'rvstartid': newId,
			'rvendid': oldId,
		} ).then( function ( resp ) {
			var revisions = resp.query.pages[0].revisions,
				len = revisions.length;
			if ( len < 3 ) {
				return $.Deferred().reject();
			}
			return api.get( {
				'action': 'query',
				'list': 'recentchanges',
				'rcprop': 'ids',
				'rcshow': 'unpatrolled',
				'rclimit': 'max',
				'rctype': [ 'edit', 'new' ],
				'rctitle': mw.config.get( 'wgPageName' ),
				'rcdir': 'older',
				'rcstart': revisions[0].timestamp,
				'rcend': revisions[len-1].timestamp,
			} );
		} ).then( function ( resp ) {
			var data = {};
			$.each( resp.query.recentchanges, function ( i, info ) {
				if ( oldId < info.revid && info.revid <= newId ) {
					data[ info.revid ] = info.rcid;
				}
			} );

			if ( $.isEmptyObject( data ) ) {
				return;
			}
			$( function() {
				$el
				.append(
					$( '<div>' )
					.addClass( 'mark-revisions-as-patrolled' )
					.append(
						'[',
						$( '<a>' )
						.attr( 'href', '#' )
						.text( 'Mark all revisions as patrolled' )
						.on( 'click', function ( event ) {
							event.preventDefault();
							$( this ).replaceWith( '...' );
							processNext( Object.values( data ) )
							.then( function () {
								$el.find( '.mark-revisions-as-patrolled' ).remove();
								$diff.find( '#mw-diff-ntitle4 .patrollink' ).remove();
								mw.notify( 'All revisions have been marked as patrolled' );
							} );
						} ),
						']'
					)
				);
			} );
		} );
	}

	mw.loader.using( [ 'mediawiki.api' ] ).then( function () {
		api = new mw.Api();
		onHistory();
		onUserContribs();
		mw.hook( 'wikipage.diff' ).add( onDiff );
	} );

} )( mediaWiki, jQuery );