MediaWiki:Gadget-contribsrange.js

From Wikiversity
Jump to navigation Jump to search

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.
//  _________________________________________________________________________________________
// |                                                                                         |
// |                    === WARNING: GLOBAL GADGET FILE ===                                  |
// |                  Changes to this page affect many users.                                |
// | Please discuss changes on the talk page or on [[Wikipedia_talk:Gadget]] before editing. |
// |_________________________________________________________________________________________|
//
// Imported from version 312947638 as of September 10, 2009 from [[User:Splarka/contribsrange.js]]
// See notes below

/* Special:Contributions Wildcard/CIDR lookup, version [0.2.7]
Originally from: https://en.wikipedia.org/wiki/User:Splarka/contribsrange.js

Notes:
* Uses the API which is faster than most CIDR contrib tools.
** Needs 1.14 r42198+ for advanced continue.
* Currently uses a GET json via <script src=""> to avoid ajax problems.
* Only currently works if submitted (or called by URL parameter, eg Special:Contributions/User).
** Checks namespace and date options in form.
** Also utilizes &ucstart and &ucend date parameters if supplied manually (not supported in the UI atm).
*** These parameters override the form date options.
* Uses: Submit any IP CIDR range /16 or from /24 to /32. Submit any string (at least 3 characters) with a suffixed asterisk.
** eg: [123.123.123.0/24 ] or [123.123.123.* ] or [Willy* ].
* Now keeps searching until it finds crMax (or forever with crshowall=true URI parameter).
** Puts them in a nice collapsed div stack, like enhanced recent changes.
* /25 and /26 ranges now disabled, since they are inaccurate (50 parameter limit), please use /24 (ucuserprefix) or /27 (32 parameters)

To do:
* use ajax (let sysops/bots = 5000)?

en.wikiversity version forked from https://w.wiki/EWA (version 0.2.7)
local version: 0.2.12
*/
/*jshint scripturl:true*/
/*global jQuery, mediaWiki, prefixContribsToggleDiv */
( function ( mw, $ ) {

function prefixContribsInit() {
	const $show = $( '#contentSub' ) || $( '#topbar' );
	if ( $show ) {
		$show.append(
			' \u2022 Javascript-enhanced contributions lookup 0.2 enabled. You may enter a CIDR range or append an asterisk to do a prefix search. For IPv6, you must use capital letters for gadget matching, native contribution matching is not case-sensitive.'
		);
	}
	const ucfrm = $( 'form' )[0];
	if ( !ucfrm.target ) {
		return;
	}

	/** general optionlets independent of type of search. */
	var options = '';
	if ( queryString( 'ucstart' ) ) {
		options += '&ucstart=' + encodeURIComponent( queryString( 'ucstart' ) );
	}
	if ( queryString( 'ucend' ) ) {
		options += '&ucend=' + encodeURIComponent( queryString( 'ucend' ) );
	}
	if ( options === '' ) {
		if ( ucfrm.start.value ) {
			options += '&ucstart=' + ucfrm.start.value + 'T23:59:59Z';
		}
		if ( ucfrm.end.value ) {
			options += '&ucend=' + ucfrm.end.value + 'T23:59:59Z';
		}
	}
	if ( typeof ucfrm.namespace != "undefined" ) {
		const chosenNamespace = ucfrm.namespace[ucfrm.namespace.selectedIndex].value;
		if ( parseInt( chosenNamespace ) > -1 ) {
			options += ( '&ucnamespace=' + chosenNamespace );
		}
	}
	options += '&uclimit=max';

	const patternCIDR = /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/(2[7-9]|3[0-2]|24|16)/i;
	const patternWild = /^.{3,}\*$/i;

	if ( ucfrm.target.value.search( patternCIDR ) === 0 ) {
		var cidr = ucfrm.target.value.match( patternCIDR )[0];
		const range = cidr.match( /[^/]\d{1,2}$/i )[0];
		if ( range === '24' ) {
			options += '&ucuserprefix=' + cidr.match( /\d{1,3}\.\d{1,3}\.\d{1,3}\./ )[0];
		} else if ( range === '16' ) {
			options += '&ucuserprefix=' + cidr.match( /\d{1,3}\.\d{1,3}\./ )[0];
		} else {
			//complex CIDR, lets figure it out
			const oct3 = cidr.match( /\.\d{1,3}\//i )[0].replace( /(\.|\/)/g,'' );
			cidr = cidr.match( /\d{1,3}\.\d{1,3}\.\d{1,3}\./ )[0];
			const num = Math.pow( 2,32 - range );
			const start = oct3 - oct3 % num;
			options += '&ucuser=';
			for ( var iii = start; iii <= start + num; iii++ ) {
				options += '' + cidr + iii;
				if ( iii !== start + num ) {
					options += '|';
				}
			}
		}
	} else if ( ucfrm.target.value.search( patternWild ) === 0 ) {
		//very simple wildcard, lets do-er
		var prefix = ucfrm.target.value.replace( /\*$/, '' );
		prefix = prefix.substr( 0, 1 ).toUpperCase() + prefix.substr( 1 );
		options += '&ucuserprefix=' + prefix;
	} else {
		console.log( 'Contribs Range - not a valid range, closing' );
		return;
	}
	prefixContribsStartbox();
	const url = mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' ) + '/api.php?action=query&format=json&callback=prefixContribs&rawcontinue=&list=usercontribs' + options;
	mw.loader.load( url );
	crContURI = url;
}

function prefixContribsStartbox() {
	$( '.mw-userpage-userdoesnotexist, .mw-contributions-user-tools' ).hide();
	$( 'form:first' ).after(
		$( '<div>' )
			.attr( 'id', 'results-from-CIDR' )
			.append(
				$( '<a>' )
					.attr( 'href', 'javascript:prefixContribsToggleAll();' )
					.text( 'toggle all' )
					.attr( 'id', 'prefixcontribs-tog' ),
				$( '<span>' )
					.attr( 'id', 'prefixcontribs-prog' )
					.text( 'Searching.' ),
				$.createSpinner( 'prefixcontribs-spin' )
			)
	);
}

window.prefixContribs = function ( obj ) {
	if( !obj.query || !obj.query.usercontribs ) {
		return;
	}
	const cidr = obj.query.usercontribs;
	if ( !cidr.length ) {
		$.removeSpinner( 'prefixcontribs-spin' );
		$( '#prefixcontribs-prog' ).text( 'No changes were found for this wildcard/CIDR range.' );
		return;
	}
	cidr.forEach((edit) => {
		const id = 'cr-' + encodeURIComponent( edit.user.replace( / /g,'_' ) ).replace( /%3A/g,':' ).replace( /%/g,'.' );
		// group each result set based on the user name, create new div for new names
		if ( $( '*[id="' + id + '"]' ).length === 0 ) {
			$( '#results-from-CIDR' )
				.append(
					$( '<div>' )
						.attr( 'id', 'd-' + id )
						.append(
							$( '<a>' )
								.attr( 'href', 'javascript:prefixContribsToggleDiv("' + id +'")' )
								.text( edit.user )
								.attr( 'id', 'm-' + id )
								.addClass( 'cr-toggle-hidden' ),
							'\n'
						),
					'\n',
					$( '<ul>' )
						.attr( 'id', id )
						.addClass( 'cr-list' )
						.hide(),
					'\n'
				);
		}
		const $li = $( '<li>' )
			.append(
				edit.timestamp.replace( /T[\d:]*Z/,' ' ),
				$( '<a>' )
					.attr( 'href', mw.util.getUrl( 'Special:Contributions/' + edit.user ) )
					.text( edit.user ),
				' (',
				$( '<a>' )
					.attr( 'href', mw.util.getUrl( 'User_talk:' + edit.user ) )
					.text( 'talk' )
					.addClass( 'mw-mightexist' ),
				') edited (',
				$( '<a>' )
					.attr( 'href', mw.util.getUrl( edit.title, { diff: 'prev', oldid: edit.revid } ) )
					.text( 'diff' ),
				') ',
				$( '<a>' )
					.attr( 'href', mw.util.getUrl( edit.title, { curid: edit.pageid } ) )
					.text( edit.title )
			);
		if ( edit.comment ) {
			$li.append(
				' (' + edit.comment + ')'
			);
		}
		$( '*[id="' + id + '"]' ).append( $li );
	});
	
	mw.hook( 'wikipage.content' ).fire( $( '.cr-list' ) );
	//continue?
	crMax = crMax - cidr.length;
	const $prog = $( '#prefixcontribs-prog' );
	if( !obj['query-continue'] || !obj['query-continue'].usercontribs || !obj['query-continue'].usercontribs.uccontinue ) {
		$.removeSpinner( 'prefixcontribs-spin' );
		$prog.remove();
		prefixContribsNumerate();
		return;
	}
	if ( crMax <= 0 && queryString( 'crshowall' ) !== 'true' ) {
		var gaurl = document.location.href;
		if ( gaurl.indexOf( '#' ) !== -1 ) {
			gaurl = gaurl.substr( 0, gaurl.indexOf( '#' ) );
		}
		if ( gaurl.indexOf( '?' ) === -1 ) {
			gaurl += '?';
		}
		gaurl += '&crshowall=true';

		$prog
			.append(
				' Whoa! Finding a lot. To see them all click ',
				$( '<a>' )
					.attr( 'href', gaurl )
					.text( 'here' ),
				'. (Warning: May bog down browser!)'
			);

		$.removeSpinner( 'prefixcontribs-spin' );
		prefixContribsNumerate();
	} else {
		$prog.append( '.' );
		const url = crContURI + '&uccontinue='+ obj['query-continue'].usercontribs.uccontinue;
		mw.loader.load( url );
	}
};

function prefixContribsNumerate() {
	const $lists = $( 'ul.cr-list' );
	for ( var iii = 0; iii < $lists.length; iii++ ) {
		$( '*[id="d-' + $lists[iii].id + '"]' ).append( ' ' + $lists[iii].childNodes.length + ' found' );
	}
	if ( $lists.length === 1 ) {
		prefixContribsToggleDiv( $lists[0].id );
	}
}

window.prefixContribsToggleAll = function () {
	const $lists = $( 'ul.cr-list' );
	if ( $lists.length === 0 ) {
		return;
	}
	const togglefrom = $lists[0].style.display;
	for ( var iii = 0; iii < $lists.length; iii++ ) {
		if ( $lists[iii].style.display === togglefrom ) {
			prefixContribsToggleDiv( $lists[iii].id );
		}
	}
};

window.prefixContribsToggleDiv = function ( id ) {
	const i = $( '*[id="' + id + '"]' )[0] || false;
	const m = $( '*[id="m-' + id + '"]' )[0] || false;
	if ( !i || !m ) {
		return;
	}
	if ( i.style.display === 'none' ) {
		i.style.display = 'block';
		m.className = 'cr-toggle-shown';
	} else {
		i.style.display = 'none';
		m.className = 'cr-toggle-hidden';
	}
};

function queryString( p ) {
	const re = RegExp( '[&?#]' + p + '=([^&#]*)' );
	const matches = re.exec( document.location );
	if ( matches ) {
		try {
			return decodeURI( matches[1] );
		} catch ( e ) {
			console.log( 'Contribs range error: ', e );
		}
	}
	return null;
}

if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Contributions' ) {
	var crContURI = ''; //query URI for continuing later
	var crMax = 10000; //bypass with &crshowall=true URI parameter
	$( prefixContribsInit );
}
}( mediaWiki, jQuery ) );