User:Thehelpfulone/babelmigrator.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.
/*********
** {{user language}} => {{#babel}} migration
*********/
var pathoschild = pathoschild || {};
pathoschild.BabelMigrator = {
	/*********
	** Properties
	*********/
	/* validation */
	RequiredUrlKeyword: 'babelmigrator=6',
	RequiredNamespaces: [2, 3],
	RequiredElements: '.userlang:first, .user-lang:first, .mw-babel-wrapper:first',
 
	/* migrator */
	Pattern: '{{ *(?:user language|babelold) *\\| *([^\\|}]+?)(?: *\\| *([^}]+?))? *}}',
	BabelPattern: '{{ *#?babel *\\| *([^}]+?) *}}',
	InsertPattern: '{{ *(?:user language|babelold|#?babel)[^}]*}}',
	Summary: 'migrated to [[user language|new #babel extension]]',
 
	/*********
	** Public methods
	*********/
	Execute: function() {
		/* get page details */
		var namespace = mw.config.get('wgNamespaceNumber');
		var action = mw.config.get('wgAction');
		var title = mw.config.get('wgTitle');
		var pageUrl = mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace('$1', mw.config.get('wgPageName'));
		var pageName = mw.config.get('wgPageName');
 
		/* validate */
		if(this.RequiredNamespaces.indexOf(namespace) == -1) {
			this.Log('exit: this namespace is not migrateable.');
			return;
		}
		if(!location.href.match(this.RequiredUrlKeyword)) {
			this.Log('exit: the URL does not contain "' + this.RequiredUrlKeyword + '".');
			return;
		}
 
		/* handle action */
		switch(action) {
			/* first view */
			case 'view':
				/* validate */
				if($(this.RequiredElements).length == 0) {
					this.Log('exit: there are no user language boxes to migrate.');
					return;
				}
 
				/* switch to edit view */
				location.href = pageUrl + '?action=edit&preview=no&' + this.RequiredUrlKeyword;				
				break;
 
			/* initial edit */
			case 'edit':
				/* find edit box */
				var $textbox = $('#wpTextbox1');
				var text = $textbox.val();
 
				/* validate */
				if(!text.match(new RegExp(this.Pattern, 'i')) && !text.match(new RegExp(this.BabelPattern, 'i'))) {
					this.Log('exit: the edit box does not contain the pattern.');
					return;
				}
 
				/* migrate templates */
				$textbox.val(this.Migrate(text));
 
				/* add keyword to form submission */
				var $editForm = $('#editform');
				$editForm.attr('action', $editForm.attr('action') + '&' + this.RequiredUrlKeyword);
 
				/* set summary & show diff */
				$('#wpSummary').val(this.Summary);
				$('#wpDiff').click();
				break;
 
			/* diff */
			case 'submit':
				/* show preview & set focus */
				$('#wpPreview').click();
				$('#wpSave').focus();
				location.href = '#top';
				break;
 
			default:
				this.Log('exit: there is no migration behaviour defined for this action (' + action + ').');
		}
	},
 
	MarkTransclusionUrls: function() {
		var _this = this;
		$('#mw-whatlinkshere-list > li > a').each(function(i, item) {
			item = $(item);
			item.attr('href', item.attr('href') + '?' + _this.RequiredUrlKeyword);
		});
	},
 
	/*********
	** Private methods
	*********/
	Log: function(message) {
		console.log('BabelMigrator: ' + message);
	},
 
	Migrate: function(text) {
		var matches = [];
 
		/* extract language codes from {{babelold}}, {{user language}}, and {{user XX}} */
		var iteratorPattern = new RegExp(this.Pattern, 'ig');
		var match;
		while(match = iteratorPattern.exec(text)) {
			this.Log('match: ' + match);
			matches.push({code: match[1], level: match[2]});
		}
 
		/* extract language codes from {{babel}} and {{#babel}} */
		iteratorPattern = new RegExp(this.BabelPattern, 'ig');
		while(match = iteratorPattern.exec(text)) {
			match = match[1];
			console.log('match: ' + match);
 
			/* extract codes */
			var pairs = match.split('|');
			for(var p = 0; p < pairs.length; p++) {
				var parts = pairs[p].split('-');
				if(parts && parts[0]) {
					matches.push({code: parts[0], level: parts[1]});
				}
			}
		}
 
		/* clean up */
		for(var i = 0; i < matches.length; i++) {
			if(!matches[i].level) {
				matches[i].level = 'N';
			}
		}
 
		/* sort */
		matches.sort(function(a, b) {
			if(a.level < b.level)
				return 1;
			if(a.level > b.level)
				return -1;
			if(a.code < b.code)
				return -1;
			if(a.code > b.code)
				return 1;
			return 0;
		});
 
		/* format */
		var codes = [];
		for(var i = 0; i < matches.length; i++) {
			var code = matches[i].code + '-' + matches[i].level;
			if(codes.indexOf(code) == -1) {
				codes.push(code);
			}
		}
 
		/* replace first instance */
		var template = '{{#babel:' + codes.join('|') + '}}';
		console.log('template: ' + template);
		text = text.replace(new RegExp(this.InsertPattern, 'i'), template);
 
		/* remove all remaining instances */
		text = text.replace(new RegExp(this.Pattern + '\\n?', 'ig'), '');
 
		return text;
	}
}
 
$(function() { pathoschild.BabelMigrator.Execute(); });