User:SHEIKH/reference.js

From Meta, a Wikimedia project coordination wiki

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.
$(mw.util.addPortletLink('p-tb', '#', 'তথসূত্র স')).click(function(e) {
	e.preventDefault();

	function ProcessDialog(config) {
		ProcessDialog.super.call(this, config);
	}

	OO.inheritClass(ProcessDialog, OO.ui.ProcessDialog);

	ProcessDialog.static.name = 'citoidExpandRefs';
	ProcessDialog.static.title = 'Reference Expander';
	ProcessDialog.static.actions = [{
		action: 'close',
		label: 'Close',
		flags: ['safe', 'close']
	}];

	ProcessDialog.prototype.initialize = function() {
		ProcessDialog.super.prototype.initialize.apply(this, arguments);

		this.content = new OO.ui.PanelLayout({
			padded: true,
			expanded: false
		});
		this.progressBar = new OO.ui.ProgressBarWidget({
			progress: false
		});
		this.logElement = $('<div>').css('font-family', 'monospace monospace');

		this.progressBar.$element.css({marginTop: '1em'});
		this.content.$element.append(this.logElement, this.progressBar.$element);
		this.$body.append(this.content.$element);

		this.setStatus('Initalizing...');
	};

	ProcessDialog.prototype.getActionProcess = function() {
		var dialog = this;
		return new OO.ui.Process(function() {
			dialog.close();
		});
	};

	ProcessDialog.prototype.getBodyHeight = function() {
		return this.content.$element.outerHeight(true);
	};

	ProcessDialog.prototype.log = function(msg, color) {
		this.logElement.append($('<div>').text('> ' + msg).css({color: color || 'grey'}));
		this.updateSize();
		this.$body.scrollTop(this.$body.prop('scrollHeight'));
	};

	ProcessDialog.prototype.setStatus = function(text) {
		this.title.setLabel(ProcessDialog.static.title + ': ' + text);
	};

	ProcessDialog.prototype.setProgress = function(progress) {
		this.progressBar.setProgress(progress);
	};

	var windowManager = new OO.ui.WindowManager();

	$(document.body).append(windowManager.$element);

	var processDialog = new ProcessDialog({
		size: 'large'
	});

	windowManager.addWindows([processDialog]);
	windowManager.openWindow(processDialog);

	processDialog.log('Loading page content and scripts...');

	mw.loader.getScript('https://en.wikipedia.org/w/index.php?title=User:BrandonXLF/Citoid.js&action=raw&ctype=text/javascript').then(function() {
		new mw.Api().edit(mw.config.get('wgPageName'), function(rev) {
			var urlProtocols = mw.config.get('wgUrlProtocols'),
				urlProtocolsWithoutRel = mw.config.get('wgUrlProtocols').split('|').filter(function(protocol) {
					return protocol !== '\\/\\/';
				}).join('|'),
				urlCharacters = '[^<>"\\x00-\\x20\\x7F\\xA0\\u1680\\u2000-\\u200A\\u202F\\u205F\\u3000\\uFFFD]', // From Parser::EXT_LINK_URL_CLASS
				enclosedUrlRegex = new RegExp('\\[((?:' + urlProtocols + ')' + urlCharacters + '*).?\\]'),
				unenclosedUrlRegex = new RegExp('((?:' + urlProtocolsWithoutRel + ')' + urlCharacters + '*)'),
				refRegex = /<ref(?:[^>]+?[^/]|)>.*?<\/ref>/g,
				textarea = document.createElement('textarea'),
				def = $.Deferred(),
				refs = rev.content.match(refRegex),
				done = 0;

			processDialog.setProgress(0);
			processDialog.setStatus('Expanding references...');

			function afterRef(msg, color) {
				done++;

				processDialog.log(msg, color);
				processDialog.setProgress(done / refs.length * 100);

				if (done >= refs.length) {
					processDialog.setProgress(false);
					processDialog.setStatus('Saving...');
					processDialog.log('Saving changes to ' + mw.config.get('wgPageName') + '...');

					var pos = 0;

					def.resolve({
						text: rev.content.replace(refRegex, function() {
							return refs[pos++];
						}),
						summary: 'তথ্যসূত্র ঠিক করা হয়েছে'
					});
				}
			}

			function expandRef(startTag, url, endTag, refIndex) {
				getCitoidRef(url).then(function(expanded) {
					refs[refIndex] = startTag + expanded + endTag;
					afterRef('Expanded reference to "' + url + '".', 'green');
				}, function() {
					afterRef('Error expanding reference to "' + url + '".', 'red');
				});
			}

			function doRef(refIndex) {
				if (refs[refIndex].match(/<ref.*?> *{{/)) {
					afterRef('Skipping already expanded reference.');
					return;
				}

				var parts = refs[refIndex].match(/(<ref.*?>)(.*?)(<\/ref>)/),
					startTag = parts[1],
					refText = parts[2].trim(),
					endTag = parts[3],
					match;

				// Unescape HTML escape codes
				textarea.innerHTML = refText;
				refText = textarea.value;

				// Match url in brackets
				match = refText.match(enclosedUrlRegex);

				if (match) {
					expandRef(startTag, match[1], endTag, refIndex);
					return;
				}

				// Match url out of brackets
				match = refText.match(unenclosedUrlRegex);

				if (match) {
					// Remove trailing punctuation
					// From Parser::makeFreeExternalLink
					var sep = ',;.:!?';
					if (match[1].indexOf('(') == -1) sep += ')';

					var trailLength = 0;

					for (var i = match[1].length - 1; i >= 0; i--) {
						if (sep.indexOf(match[1][i]) == -1) break;
						else trailLength++;
					}

					expandRef(startTag, match[1].substring(0, match[1].length - trailLength), endTag, refIndex);
					return;
				}

				afterRef('Skipped reference without URL.');
				return;
			}

			if (refs) {
				for (var i = 0; i < refs.length; i++) doRef(i);
			} else {
				processDialog.log('No references found on the page.');
				def.resolve({text: rev.content});
			}

			return def.promise();
		}).then(function() {
			processDialog.setProgress(100);
			processDialog.setStatus('Edit saved!');
			processDialog.log('Edit saved. Reloading...');
			window.location.reload();
		});
	});
});
// </nowiki>


//patrol

( 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();
		}
		const rcid = queue.pop();
		return markAsPatrolled( rcid )
		.then( function () {
			return processNext( queue );
		} );
	}

	function getRevToRcIdMapping( response ) {
		var revToRcIdMapping = {};
		response.query.recentchanges.forEach( function ( info ) {
			revToRcIdMapping[ info.revid ] = info.rcid;
		} );
		return revToRcIdMapping;
	}

	function queryRevToRcIdMapping( query ) {
		return api.get( query ).then( getRevToRcIdMapping );
	}

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

		queryRevToRcIdMapping( {
			'action': 'query',
			'list': 'recentchanges',
			'rcprop': 'ids',
			'rcshow': 'unpatrolled',
			'rclimit': 'max',
			'rctype': [ 'edit', 'new' ],
			'rctitle': mw.config.get( 'wgPageName' ),
		} ).then( function ( revToRcIdMapping ) {
			var length = Object.values( revToRcIdMapping ).length,
				queue = [];
			$( function () {
				$( '#pagehistory > li' ).each( function () {
					var $this = $( this );
					const
						revid = +$this.data( 'mw-revid' ),
						rcid = revToRcIdMapping[ revid ];
					if ( rcid ) {
						$this.addClass( 'row-unpatrolled' );
						queue.push( rcid );
						return --length !== 0;
					}
				} );

				if ( queue.length === 0 ) {
					return;
				}

				mw.util.addCSS( '.row-unpatrolled { background-color: #fff0c2 !important; }' );

				$( '.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( $.createSpinner( {
								size: 'small',
								type: 'inline',
							} ) );
							processNext( queue )
							.then( function () {
								$( '.mark-all-as-patrolled' ).remove();
								$( '.row-unpatrolled' ).removeClass( 'row-unpatrolled' );
								mw.notify( 'All revisions have been marked as patrolled' );
							} /* TODO: report error */ );
						} ),
						']'
					)
				);
			} );
		} );
	}

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

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

		queryRevToRcIdMapping( {
			'action': 'query',
			'list': 'recentchanges',
			'rcprop': 'ids',
			'rcshow': 'unpatrolled',
			'rclimit': 'max',
			'rctype': [ 'edit', 'new' ],
			'rcuser': mw.config.get( 'wgRelevantUserName' ),
		} ).then( function ( revToRcIdMapping ) {
			var queue = [],
				length = Object.values( revToRcIdMapping ).length,
				marker = $( '<abbr>' )
					.attr( 'title', 'This change hasn\'t been patrolled yet' )
					.addClass( 'unpatrolled' )
					.html( '!' );
			$( function () {
				$( '.mw-contributions-list > li' ).each( function () {
					var $this = $( this );
					const
						revid = +$this.data( 'mw-revid' ),
						rcid = revToRcIdMapping[ revid ];
					if ( rcid ) {
						$this.find( '.mw-changeslist-separator' ).eq( 1 ).after( [ ' ', marker.clone() ] );
						queue.push( rcid );
						return --length !== 0;
					}
				} );

				if ( queue.length === 0 ) {
					return;
				}

				$( '.mw-pager-navigation-bar' )
				.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( $.createSpinner( {
								size: 'small',
								type: 'inline',
							} ) );
							processNext( queue )
							.then( function () {
								$( '.mark-all-as-patrolled' ).remove();
								$( '.unpatrolled' ).remove();
								mw.notify( 'All user\'s displayed revisions have been marked as patrolled' );
							} /* TODO: report error */ );
						} ),
						']'
					)
				);
			} );
		} );
	}

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

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

		const
			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;
			const len = revisions.length;
			if ( len < 3 ) {
				return {};
			}
			return queryRevToRcIdMapping( {
				'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 ( revToRcIdMapping ) {
			var queue = [];
			for ( var revid in revToRcIdMapping ) {
				if ( oldId < revid && revid <= newId ) {
					queue.push( revToRcIdMapping[ revid ] );
				}
			}

			if ( queue.length === 0 ) {
				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( $.createSpinner( {
								size: 'small',
								type: 'inline',
							} ) );
							processNext( queue )
							.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' );
							} /* TODO: report error */ );
						} ),
						']'
					)
				);
			} );
		} );
	}

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

} )( mediaWiki, jQuery );