MediaWiki:Gadget-addMe.js

// AddMe gadget, taken from Meta and heavily edited for the Developer Wishlist. // Supports endorse / join / vote by adding your signature and possibly other text // See https://meta.wikimedia.org/wiki/Meta:AddMe for usage and description.

/* * Common utilities for both the endorse & the join gadget */ var gadgetUtilities = function { //A reference to the object var that = this; //The mw wrapper to access the API var api = new mw.Api; /*	 * The interface messages or strings are maintained in interfaceMessagesPath */	this.interfaceMessagesPath = 'MediaWiki:AddMe/InterfaceText';

//The time taken for the page to scroll to the feedback speech bubble (milliseconds) this.feedbackScrollTime = 2000; //The time taken for the feedback speech bubble to disappear (milliseconds) this.feedbackDisappearDelay = 10000; /*	 * This function is used to set a cookie to show the speech bubble * on page reload */	this.setFeedbackCookie = function(value, domain, section){ $.cookie('addme-'+value, domain+'|'+section); };	/*	 * This function is used to check if a has been set by the above function * to show the speech bubble on page reload */	this.checkFeedbackCookie = function(value){ var val = $.cookie('addme-'+value); if(val){ $.cookie('addme-'+value,null); return val.split('|'); }		else{ return false; }	};	/*	 * To display an error message when an error occurs * in the gadget */	this.showErrorMessage = function(gadget,type){ var errorAttr = '[localize=error-'+type+']'; var gadgetID = '.'+gadget; $(gadgetID + ' ' + errorAttr).show; };	/*	 * To remove the error message displayed by the above function */	this.removeErrorMessage = function(gadget){ var gadgetID = '.'+gadget; $(gadgetID + ' [localize^="error-"]').hide; };	/*	 * To detect the users default language */	this.userLanguage = function{ return mw.config.get('wgUserLanguage'); };	/*	 * To detect the language of the page */	this.contentLanguage = function{ return mw.config.get('wgContentLanguage'); };	/*	 * To remove extra spaces & cleanup the comment string */	this.cleanupText = function(text){ if ( !text ) return ''; return $.trim(text).replace(/~{3,5}/, '')+' '; };	/*	 * The config files which can be translated with the help of the * translation tool generates the dict with the values having a * lot of space in the key value pairs. This function strips the * whitespace. */	this.stripWhiteSpace = function(dict){ // for (var key in dict){ // 	dict[key] = typeof(dict[key]) == 'object' ? that.stripWhiteSpace(dict[key]) : $.trim(dict[key]); // }		return dict; };	/*	 * To localize the gadget's interface messages based on the user's language setting */	this.localizeGadget = function ($dialog,localizeDict){ $dialog.find('[localize]').each(function{			var localizeValue = localizeDict[$(this).attr('localize')];			if($(this).attr('value')){				$(this).attr('value',localizeValue);			}			else if($(this).attr('placeholder')){				$(this).attr('placeholder',localizeValue);			}			else if($(this).attr('data-placeholder')){				$(this).attr('data-placeholder',localizeValue);			}			else{				$(this).html(localizeValue);			}		}); };	/*	 * This function show the feedback speech bubble after an 	 * endorsement has been made or after joining a project */	this.showFeedback = function(sectionName,InterfaceMessages){ var li = $('#'+mw.util.escapeId(sectionName).replace(/\./g, '\\.')) .closest('h1,h2,h3,h4,h5,h6').nextAll('ul,ol').eq(0).find('li').eq(-1); speechBubble = li.append($(' ').html(' \ Thank You  ')).find('.grantsSpeechBubbleContainer'); var width = li.css('display','inline-block').width; li.css('display',''); li.css('position','relative'); speechBubble.css('left',width/2+'px'); $('[localize=message-feedback]').html(InterfaceMessages['message-feedback']); //$("body, html").animate({ scrollTop : li[0].offsetTop}, that.feedbackScrollTime); setTimeout(function{ speechBubble.hide;},that.feedbackDisappearDelay); }; }; var Gadget = function{ /* Variables */ var util = new gadgetUtilities; var dialogs = []; var api = new mw.Api; var that = this;

/*	 * This function creates the dialog box for the gadget. * It is also where all the dialog related interactions are defined. */ 	var createDialog = function{ var hasFreeText = 'message-description' in that.interfaceMessages; function updateDisable( $dialog ) { if($dialog.find('.devEndorseComment').val){ $dialog.find('.add-endorse').attr('disabled',false); $dialog.find('.messageSignature').css('visibility','visible'); }else{ if ($dialog.find('.devEndorseComment').length) { $dialog.find('.add-endorse').attr('disabled',true); }				$dialog.find('.messageSignature').css('visibility','hidden'); }		}		var $dialog = $( " " ) .html(					' \					 	 An error occured \					 	 An error occured \					 '					 +(hasFreeText ? ' Endorse the project ' + '\  \ Your signature will be added automatically ' : '')+					 ' \						Cancel\						 \					 '		); var dialog = $dialog.dialog({			dialogClass: 'grantsGadget endorseGadget',			autoOpen: false,			title: that.interfaceMessages.title + ': ' + that.title,			width: '495px',			modal: true,			closeOnEscape: true,			resizable: false,			draggable: false,			open: function( event, ui ) {				updateDisable( $dialog );			},			close: function( event, ui ) {				$('.devEndorseComment').val('');			}		});

$dialog.find('.add-endorse').click(function{			var text = util.cleanupText($dialog.find('.devEndorseComment').val),				summary = '/* ' + that.title + ' */ ' + that.interfaceMessages.summary + ' ' + mw.user.getName;			that.addEndorsement(that.section, text, summary);		}); $dialog.find('.devEndorseComment').on('change keyup paste',function{			util.removeErrorMessage('endorseGadget');			updateDisable($dialog);		});

$dialog.find('.cancel').click(function{			dialog.dialog('close');		}); util.localizeGadget($dialog,that.interfaceMessages); $dialog.find('.messageSignature').css('visibility','hidden'); return dialog; };	/**	 * Tells which configuration/i18n subset to use. */	this.setDomain = function (domain) { this.domain = domain; this.interfaceMessages = util.stripWhiteSpace(this.allInterfaceMessages[domain]); };	this.Dialog = function { if (!dialogs[that.domain]){ dialogs[that.domain] = createDialog; }		dialogs[that.domain].dialog('open'); };	/*	 * The main function to add text + a signature to the page. */	this.addEndorsement = function( sectionName, text, summary ) { var endorseComment = '\n#' + text +  +  + '\n'; var newText, baseTimestamp, revId, sectionCount; api.get({			'format':'json',			'action':'parse',			'prop':'sections',			'page':mw.config.get('wgPageName')		}).then(function(result){			var sections = result.parse.sections;			sectionCount = 1;			var sectionFound = false;			for (var section in sections ){				if ($.trim(sections[section].line) === sectionName ){					sectionFound = true;					break;				}				sectionCount++;			}			if (sectionFound){				return api.get({ 'format':'json', 'action':'parse', 'prop':'revid|sections|wikitext', 'page': mw.config.get('wgPageName'), 'section': sectionCount });			} else {				return $.Deferred.reject( 'addme-sectionnotfound', 'Did not find the right section to edit!' );			}		}).then(function(result){			if ( result.parse.sections[0].line !== sectionName ) { // sanity				return $.Deferred.reject( 'addme-sectionchanged', 'Edit conflict, please retry' );			}			revId = result.parse.revid;			var wikitext = result.parse.wikitext['*'];			newText = wikitext.replace( /\n#\s*$/, '' );			if ( newText[newText.length - 1] === '\n' ) {				newText = newText.substr(0, -1);			}			newText += endorseComment;			// fetch the base timestamp			return api.get({ 'format':'json', 'action':'query', 'indexpageids': 1, 'prop':'revisions', 'titles': mw.config.get('wgPageName'), 'rvprop': 'ids|timestamp' });		}).then(function(result){			var data = result.query.pages[result.query.pageids[0]].revisions[0];			if ( data.revid !== revId ) { // sanity				return $.Deferred.reject( 'addme-sectionchanged', 'Edit conflict, please retry' );			}			return api.postWithToken( 'edit', { 'action' : 'edit', 'title' : mw.config.get('wgPageName'), 'text' : newText, 'summary' : summary, 'section': sectionCount, 'basetimestamp': baseTimestamp });		}).then(function{			console.log('Successfully added endorsement');			window.location.reload(true);			util.setFeedbackCookie('feedback', that.domain, that.section);			},function(code, data){			console.log('Error!', code, data);			util.showErrorMessage('gadget','save');		}); }; };

/* End of functions */ if ( $('.wp-addme-button').length) { mw.loader.using( ['jquery.ui.dialog', 'mediawiki.util','mediawiki.api', 'mediawiki.ui','jquery.chosen'], function {		var gadget = new Gadget;			var util = new gadgetUtilities;	var api = new mw.Api;	var interfaceMessagesUrl = mw.config.get('wgScript')+'?title='+util.interfaceMessagesPath+'.js'+'&action=raw';

$.get(interfaceMessagesUrl).then(function( interfaceStr ){		var interfaceData = JSON.parse( interfaceStr );		var feedbackData = util.checkFeedbackCookie('feedback');

gadget.allInterfaceMessages = interfaceData;

if(feedbackData){ gadget.setDomain(feedbackData[0]); try { util.showFeedback(feedbackData[1], gadget.interfaceMessages); } catch(e) { console.log('[AddMe] showFeedback error', e); }		}		$('.wp-addme-button').click(function(e){			var $this = $(this),				section = $this.attr('data-addme-section'),				domain = $this.attr('data-addme-domain'),				// hack - proper entity encoding is hard in wikitext				title = decodeURIComponent($this.attr('data-addme-title'));			e.preventDefault;			//Checking if the user is logged in			if(!mw.config.get('wgUserName')){				util.showErrorMessage('gadget','login');				return;			}			gadget.section = section;			gadget.title = title;			gadget.setDomain(domain);			gadget.Dialog;		}); }); }); }