User:PaulGamerBoy360/AddMe.js

/* ______________________________________________________________________________________ * |                                                                                     | * |                    === WARNING: GADGET FILE ===                                     | * |                 Changes to this page affect many users. | * | Please discuss changes on the talk page or on MediaWiki_talk:Gadgets-definition | * | before editing. | * |_____________________________________________________________________________________| * * "Endorse & Join" feature, to be used by the Wikimedia Foundation's Grants Programme */ // /* global RJSON */ /* eslint-disable no-implicit-globals, one-var, vars-on-top, no-jquery/no-global-selector */ /* eslint-disable no-jquery/no-trim, new-cap, no-useless-concat */ /* eslint-disable no-jquery/no-parse-html-literal, no-multi-str */ /* eslint-disable camelcase, no-console */ /* * Common utilities for both the endorse & the join gadget */ var gadgetUtilities = function { // A reference to the object var that = this;

/*	 * The interface messages or strings are maintained in interfaceMessagesPath & config values eg, * section-header, the section where the comments are added etc are maintained in configPath */	this.interfaceMessagesPath = 'Meta:AddMe/InterfaceText'; this.configPath = 'Meta:AddMe/Config';

// 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 ) { $.cookie( value, true ); };	/*	 * 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 ) { if ( $.cookie( value ) ) { $.cookie( value, null ); return true; } 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 type of grant. IEG,PEG etc */	this.grantType = function ( config ) { var grant = mw.config.get( 'wgTitle' ).split( '/' )[ 0 ].replace( / /g, '_' ); if ( grant in config ) { return config[ grant ]; } else { return config.default; }	};	/*	 * 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 ) { text = $.trim( text ) + ' '; var indexOf = text.indexOf( '~' ); if ( indexOf === -1 ) { return text; } else { return text.slice( 0, indexOf ) + text.slice( indexOf + 4 ); }	};	/*	 * 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 ) { var key; for ( key in dict ) { // Temp fix for section header if ( key === 'section-header' ) { dict[ 'section-header-read' ] = dict[ key ].replace( / /g, '_' ); dict[ 'section-header-write' ] = dict[ key ]; }			dict[ key ] = typeof ( dict[ key ] ) === 'object' ? that.stripWhiteSpace( dict[ key ] ) : $.trim( dict[ key ] ); }		return dict; };	/*	 * The function creates the markup for the link to a	 * user's user page */	this.addToInfobox = function ( username ) { return username; };	/*	 * To localize the gadget's interface messages based on the user's language setting */	this.localizeGadget = function ( gadgetClass, localizeDict ) { $( gadgetClass + ' [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 ( config, InterfaceMessages ) { var $li = $( '#' + config[ 'section-header-read' ] ).parent.next.find( 'li' ).eq( -1 ); var $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 ); }; }; /* * The Endorse Gadget */ var endorseGadget = function { /* Variables */ var util = new gadgetUtilities; var dialog = null;

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 { dialog = $( " " ) .html(				' \					 An error occurred \					 An error occurred \				 \				 Explaining your endorsement improves process ' + '\				 \				 Your signature will be added automatically \				 \					Cancel\					 \				 '			).dialog( {				dialogClass: 'grantsGadget endorseGadget',				autoOpen: false,				title: 'Endorse Comment',				width: '495px',				modal: true,				closeOnEscape: true,				resizable: false,				draggable: false,				close: function {					$( '#devEndorseComment' ).val( '' );				}			} );

$( '.add-endorse' ).on( 'click', function {			that.addEndorsement( util.cleanupText( $( '#devEndorseComment' ).val ) );		} );

$( '#devEndorseComment' ).on( 'change keyup paste', function {			util.removeErrorMessage( 'endorseGadget' );			if ( $( this ).val ) {				$( '.add-endorse' ).attr( 'disabled', false );				$( '.messageSignature' ).css( 'visibility', 'visible' );			} else {				$( '.add-endorse' ).attr( 'disabled', true );				$( '.messageSignature' ).css( 'visibility', 'hidden' );			}		} ); $( '.endorseGadget .ui-dialog-title' ).attr( 'localize', 'title' );

$( '.endorseGadget .cancel' ).on( 'click', function {			dialog.dialog( 'close' );		} );

util.localizeGadget( '.endorseGadget', that.interfaceMessages );

$( '.messageSignature' ).css( 'visibility', 'hidden' ); };	this.Dialog = function { if ( dialog === null ) { createDialog; } else { dialog.dialog( 'open' ); }	};	/*	 * The main function to add the feedback/endorsement to the page. It first checks if the page has an endorsement section. * If it dosent it creates a new section called Endorsements and appends the feedback/endorsement comment to that section, * else it appends the feedback/endorsement comment to existing Endorsements section. * The name of the endorsement section is defined in the config. */	this.addEndorsement = function ( text ) { var endorseComment = '\n*' + text + '~' + '\n'; api.get( {			format: 'json',			action: 'parse',			prop: 'sections',			page: mw.config.get( 'wgPageName' )		} ).then( function ( result ) {			var sections = result.parse.sections;			var sectionCount = 1;			var sectionFound = false;			for ( var section in sections ) {				if ( $.trim( sections[ section ].anchor ) === that.config[ 'section-header-read' ] ) {					sectionFound = true;					break;				}				sectionCount++;			}			if ( sectionFound ) {				api.get( { format: 'json', action: 'parse', prop: 'wikitext', page: mw.config.get( 'wgPageName' ), section: sectionCount } ).then( function ( result ) { var wikitext = result.parse.wikitext[ '*' ]; var endorsementSection = wikitext + endorseComment; api.post( {						action: 'edit',						title: mw.config.get( 'wgPageName' ),						text: endorsementSection,						summary: 'Endorsed by ' + mw.user.getName,						section: sectionCount,						watchlist: 'watch',						token: mw.user.tokens.get( 'csrfToken' )					} ).then( function {						console.log( 'Successfully added endorsement' );						window.location.reload( true );						util.setFeedbackCookie( 'endorseFeedback' );					}, function  {						util.showErrorMessage( 'endorseGadget', 'save' );					} ); } );			} else {				var sectionHeader = that.config[ 'section-header-write' ];				api.post( { action: 'edit', title: mw.config.get( 'wgPageName' ), section: 'new', summary: sectionHeader + ' Endorsed by ' + mw.user.getName, sectiontitle: sectionHeader, text: $.trim( endorseComment ), watchlist: 'watch', token: mw.user.tokens.get( 'csrfToken' ) } ).then( function { console.log( 'Successfully added endorsement' ); location.reload; util.setFeedbackCookie( 'endorseFeedback' ); }, function { util.showErrorMessage( 'endorseGadget', 'save' ); } );			}		}, function {			util.showErrorMessage( 'endorseGadget', 'save' );		} ); }; }; /* * The function the create the join gadget and provides * all the needed functionality. */ var joinGadget = function { /* Variables */ var util = new gadgetUtilities; var dialog = null;

this.config = null; this.interfaceMessages = null;

var roleDict = {}; var api = new mw.Api; var that = this; /*	 * A count is maintained of the open '' is encountered the counter is decremented. * If the counter reaches 0 the end of the infobox has been found. * Else the syntax is broken or the end of the infobox is not in * the first section of the page. */	var extractInfobox = function ( markup ) { var startIndex = markup.indexOf( '{{Probox' ); var counter = 0; var endIndex = 0; for ( var i = startIndex; i < markup.length; i++ ) { if ( markup[ i ] === '}' && markup[ i + 1 ] === '}' ) { counter++; }			if ( markup[ i ] === '{' && markup[ i + 1 ] === '{' ) { counter--; }			if ( counter === 0 ) { endIndex = i + 2; break; }		}		if ( counter !== 0 ) { return ''; }		var infobox = { infobox: markup.slice( startIndex, endIndex ), before: markup.slice( 0, startIndex ), after: markup.slice( endIndex ) };		// return markup.slice( startIndex, endIndex ); return infobox; };	/*	 * This function creates the dialog & defines * needed interactions in the dialog. */	var createDialog = function { dialog = $( " " ) .html(				' \					 An error occurred \					 An error occurred \				 \				\					 \				 \				 Tell us how you would like to help \				 \				 Your signature will be added automatically \				 \					Cancel\					 \				 '			).dialog( {				dialogClass: 'grantsGadget joinGadget',				autoOpen: false,				title: 'join Comment',				width: '495px',				modal: true,				closeOnEscape: true,				resizable: false,				draggable: false,				close: function  {					$( '#devJoinComment' ).val( '' ); }			} );		$( '.add-join' ).on( 'click', function { /*				 * Creating the comment to add to the participants section. The comment is of the form * "Role" User comment. Eg, Volunteer I can help out in many ways. */

var joinRole = $( '.roleSelect' ).val.replace( /_/, ' ' ); joinRole = joinRole[ 0 ].toUpperCase + joinRole.slice( 1 ); joinRole = "" + joinRole + "" + ' '; that.addjoinment( joinRole + util.cleanupText( $( '#devJoinComment' ).val ) ); } );

$( '#devJoinComment' ).on( 'change keyup paste', function {			util.removeErrorMessage( 'joinGadget' );			if ( $( this ).val ) {				$( '.messageSignature' ).css( 'visibility', 'visible' );				if ( $( '.roleSelect' ).val ) {					$( '.add-join' ).attr( 'disabled', false );				}			} else {				$( '.add-join' ).attr( 'disabled', true );				$( '.messageSignature' ).css( 'visibility', 'hidden' );			}		} ); $( '.joinGadget .ui-dialog-title' ).attr( 'localize', 'title' );

$( '.joinGadget .cancel' ).on( 'click', function {			dialog.dialog( 'close' );		} ); util.localizeGadget( '.joinGadget', that.interfaceMessages ); $( '.messageSignature' ).css( 'visibility', 'hidden' );

/*			 * The code below gets the infobox, check for open roles, * makes sure that these roles are available for other to			 * join by looking up roles in the config and creates a drop down * from which a user can select a role. */

api.get( {			format: 'json',			action: 'parse',			prop: 'wikitext',			page: mw.config.get( 'wgPageName' ),			section: 0		} ).then( function ( result ) {			var roles = that.interfaceMessages.roles;			var wikitext = result.parse.wikitext[ '*' ];

var content = extractInfobox( wikitext ); var infobox = that.infobox = content.infobox; that.before = content.before; that.after = content.after; var units = infobox.split( '\n' ); for ( var unit in units ) { var line = units[ unit ]; var role = line.match( /[a-zA-z]+/g ); if ( role ) { role = role.join( '' ); var elements = line.split( '=' ); var count = elements[ 0 ].match( /[0-9]+/ ) ? elements[ 0 ].match( /[0-9]+/ )[ 0 ] : 1; if ( role.indexOf( 'volunteer' ) !== -1 ) { roleDict.volunteer = count; }					if ( role in roles && line.indexOf( '=' ) !== -1 ) { roleDict[ role ] = count; if ( !$( '.roleSelect option[value="' + role + '"]' ).length ) { $( '.roleSelect' ).append( '' + roles[ role ] + ' ' ); }					}				}			}			if ( !$( '.roleSelect option[value="volunteer"]' ).length ) { $( '.roleSelect' ).append( ' ' + roles.volunteer + ' ' ); }			$( '.roleSelect' ).chosen( {				disable_search: true,				placeholder_text_single: 'Select a role',				width: '50%'			} ); /* Fix this */ /*			$( '.roleSelect' ).on( 'chosen:showing_dropdown', function {				util.removeErrorMessage( 'endorseGadget' );			} ); */			$( '.roleSelect' ).on( 'change', function {				util.removeErrorMessage( 'joinGadget' );				if ( $( this ).val && $( '#devJoinComment' ).val ) {					$( '.add-join' ).attr( 'disabled', false );				} else {					$( '.add-join' ).attr( 'disabled', true );				}			} ); } );	};	this.Dialog = function {		if ( dialog === null ) {			createDialog;		} else {			dialog.dialog( 'open' );		}	};	/*	 * The main function to add the feedback/join comment to the page. It first checks if the page has an Participants section.	 * If it dosent it creates a new section called Participants and appends the fedback/comment to that section,	 * else it appends the feedback/comment to existing Participants section.	 */	this.addjoinment = function ( text ) {		var joinComment = '\n*' + text + '~' + '\n';		// var joinComment = '*' + text + '~' + '\n';		// Editing the infobox		var userName = mw.config.get( 'wgUserName' ) ? mw.config.get( 'wgUserName' ) : ;		var roleSelected = $( '.roleSelect' ).val;		var units = that.infobox.split( '\n' );		var emptyRoleAdded = false;		for ( var unit in units ) {			if ( $.trim( units[ unit ].split( '=' )[ 1 ] ) ===  ) {				var role = units[ unit ].match( /[a-zA-z]+/ ); if ( role ) { role = role[ 0 ]; if ( role === roleSelected ) { units[ unit ] = $.trim( units[ unit ] ) + util.addToInfobox( userName ); emptyRoleAdded = true; break; }				}			}		}		var modifiedInfoBox = units.join( '\n' ); if ( !emptyRoleAdded ) { var paramCount = roleDict.volunteer ? parseInt( roleDict.volunteer ) + 1 : 1; var endIndex = modifiedInfoBox.lastIndexOf( '}}' ); modifiedInfoBox = modifiedInfoBox.slice( 0, endIndex ) + '|volunteer' + paramCount + '=' + util.addToInfobox( userName ) + '\n}}'; }

api.post( {			action: 'edit',			title: mw.config.get( 'wgPageName' ),			text: that.before + modifiedInfoBox + that.after,			summary: 'Joined as ' + roleSelected,			section: 0,			watchlist: 'watch',			token: mw.user.tokens.get( 'csrfToken' )		} ).then( function {			api.get( { format: 'json', action: 'parse', prop: 'sections', page: mw.config.get( 'wgPageName' ) } ).then( function ( result ) { var sections = result.parse.sections; var sectionCount = 1; var sectionFound = false; for ( var section in sections ) { if ( $.trim( sections[ section ].anchor ) === that.config[ 'section-header-read' ] ) { sectionFound = true; break; }					sectionCount++; }				if ( sectionFound ) { api.get( {						format: 'json',						action: 'parse',						prop: 'wikitext',						page: mw.config.get( 'wgPageName' ),						section: sectionCount					} ).then( function ( result ) {						var wikitext = result.parse.wikitext[ '*' ];						var joinmentSection = wikitext + joinComment;						api.post( { action: 'edit', title: mw.config.get( 'wgPageName' ), text: joinmentSection, summary: 'Adding my name to the participants section', section: sectionCount, watchlist: 'watch', token: mw.user.tokens.get( 'csrfToken' ) } ).then( function { console.log( 'Successfully added to participants' ); location.reload; util.setFeedbackCookie( 'joinFeedback' ); }, function { util.showErrorMessage( 'joinGadget', 'save' ); } );					} );				} else { var sectionHeader = that.config[ 'section-header-write' ]; api.post( {						action: 'edit',						title: mw.config.get( 'wgPageName' ),						section: 'new',						summary: sectionHeader,						text: $.trim( joinComment ),						watchlist: 'watch',						token: mw.user.tokens.get( 'csrfToken' )					} ).then( function {						console.log( 'Successfully added to participants' );						location.reload;						util.setFeedbackCookie( 'joinFeedback' );					}, function  {						util.showErrorMessage( 'joinGadget', 'save' );					} ); }			}, function { util.showErrorMessage( 'joinGadget', 'save' ); } );		}, function {			util.showErrorMessage( 'joinGadget', 'save' );		} );

}; };

/* End of functions */ $( function {	if ( !$( '.wp-join-button,.wp-endorse-button' ).length ) {		// Ignore this page		return;	}	mw.loader.using( [ 'jquery.ui', 'mediawiki.api', 'mediawiki.ui', 'jquery.chosen' ], function  { /*		 * Fix mw.config.get('wgPageContentLanguage') == 'en') checking with a better solution,		 * either when pages can be tagged with arbitary language or when we set langauge markers later on.		 *		 */		if ( mw.config.get( 'wgPageContentLanguage' ) === 'en' ) {

var endorse = new endorseGadget; var join = new joinGadget; var util = new gadgetUtilities; var api = new mw.Api; var interfaceMessagesFullPath = util.interfaceMessagesPath + '/' + util.userLanguage; var configFullPath = util.configPath + '/' + util.contentLanguage;

/*			 * To detect if we have the gadget translations and config in the desired languages. * Currently page language is English always. So the config returned is in en. The InterfaceMessages is			 * in the user's language */			api.get( { action: 'query', titles: interfaceMessagesFullPath + '|' + configFullPath, format: 'json' } ).then( function ( data ) {

for ( var id in data.query.pages ) { if ( data.query.pages[ id ].title === util.interfaceMessagesPath + '/' + util.userLanguage && id === -1 ) { interfaceMessagesFullPath = util.interfaceMessagesPath + '/en'; }					if ( data.query.pages[ id ].title === util.configPath + '/' + util.contentLanguage && id === -1 ) { configFullPath = util.configPath + '/en'; }				}

var interfaceMessagesUrl = 'https://meta.wikimedia.org/w/index.php?title=' + interfaceMessagesFullPath + '&action=raw'; var configUrl = 'https://meta.wikimedia.org/w/index.php?title=' + configFullPath + '&action=raw'; // Get the config for the detected language $.when( $.get( interfaceMessagesUrl ), $.get( configUrl ) ).then( function ( interfaceStr, configStr ) {					var interfaceData = RJSON.parse( interfaceStr[ 0 ] ),						configData = RJSON.parse( configStr[ 0 ] );

// Stripping Whitespace join.config = util.stripWhiteSpace( util.grantType( configData.join ) ); join.interfaceMessages = util.stripWhiteSpace( util.grantType( interfaceData.join ) );

endorse.config = util.stripWhiteSpace( util.grantType( configData.endorse ) ); endorse.interfaceMessages = util.stripWhiteSpace( util.grantType( interfaceData.endorse ) );

join.Dialog; $( '.wp-join-button' ).off; $( '.wp-join-button' ).on( 'click', function ( e ) {						e.preventDefault;						join.Dialog;					} ); if ( util.checkFeedbackCookie( 'joinFeedback' ) ) { util.showFeedback( join.config, join.interfaceMessages ); }					endorse.Dialog; $( '.wp-endorse-button' ).off; $( '.wp-endorse-button' ).on( 'click', function ( e ) {						e.preventDefault;						endorse.Dialog;					} );

// Checking if the user is logged in					if ( !mw.config.get( 'wgUserName' ) ) { util.showErrorMessage( 'endorseGadget', 'login' ); util.showErrorMessage( 'joinGadget', 'login' ); }

if ( util.checkFeedbackCookie( 'endorseFeedback' ) ) { util.showFeedback( endorse.config, endorse.interfaceMessages ); }				} );			} );		} else { $( '.wp-join-button' ).hide; $( '.wp-endorse-button' ).hide; }	} ); } );

//