MediaWiki:Gadget-addMe.js
Appearance
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)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
// 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.escapeIdForAttribute(sectionName).replace(/\./g, '\\.'))
.closest('h1,h2,h3,h4,h5,h6').nextAll('ul,ol').eq(0).find('li').eq(-1);
speechBubble = li.append($('<div class="grantsSpeechBubbleContainer"></div>').html('<div class="grantsSpeechBubble">\
<span localize="message-feedback">Thank You</span></div><div class="grantsSpeechBubbleArrowDown"></div>')).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 = $( "<div class='devEndorseDialog'></div>" )
.html(
'<div class="mw-ui-vform">\
<div class="error grantsHide" localize="error-save">An error occurred</div>\
<div class="error grantsHide" localize="error-login">An error occurred</div>\
</div>'
+(hasFreeText ?
'<div localize="message-description" class="messageDescription">Endorse the project</div>' + '\
<textarea rows="5" cols="10" placeholder="Please explain why you endorse this project." class="devEndorseComment" class="" localize="placeholder-comment"></textarea>\
<span localize="message-signature" class="messageSignature">Your signature will be added automatically</span>'
: '')+
'<div class="gadgetControls">\
<a href="#" localize="button-cancel" class="mw-ui-button cancel mw-ui-quiet">Cancel</a>\
<input type="submit" localize="button-submit" class="mw-ui-button mw-ui-constructive add-endorse" ' + (hasFreeText ? 'disabled ' : '') + 'localize="button" value="Ok"></input>\
</div>'
);
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', '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();
});
});
});
}