User:SD0001/GAR-helper.js: Difference between revisions

Content deleted Content added
also notify any previous GAR nominators and GAN reviewers
don't lose nomination text in case of failure
 
(16 intermediate revisions by the same user not shown)
Line 18:
$('#gar-portlet').click(gar.callback);
}
loadTaskManager();
});
 
Line 26 ⟶ 25:
if (e) e.preventDefault();
 
var Window = new Morebits.simpleWindow(600, 450600);
Window.setTitle( "Nominate article for GAR" );
Window.setScriptName('GAR-helper');
Line 33 ⟶ 32:
var form = new Morebits.quickForm(gar.evaluate);
 
mw.util.addCSS('.quickform * { font-size: 12px; }');
var typefield = form.append({
type: 'field',
label: 'GAR type',
id: 'gartype_fieldset'
});
 
typefield.append({
type: 'radio',
name: 'gartype',
event: gar.typechanged,
list: [
{
label: 'Community reassessment',
value: 'garc',
checked: true
},
{
label: 'Individual reassessment',
value: 'gari'
}
]
});
 
var field = form.append({
Line 60 ⟶ 38:
label: 'Details',
name: 'details'
});
 
field.append({
type: 'checkbox',
list: [
{
label: 'Notify article creator',
value: 'notify',
name: 'notify',
tooltip: "A notification template will be placed on the creator's talk page if this is checked.",
checked: true
}
]
});
 
Line 82 ⟶ 47:
tooltip: 'You can expand the rationale after the page has been saved as well.'
});
 
var previewlink = Morebits.htmlNode('a', 'Preview');
previewlink.style.cursor = "pointer";
$(previewlink).click(function() {
// |result| is defined below
gar.preview(result);
});
form.append( { type: 'div', id: 'garpreview', label: [ previewlink ] } );
form.append( { type: 'div', id: 'gar-previewbox', style: 'display: none' } );
 
form.append({ type: 'submit', label: 'Submit' });
Line 88 ⟶ 62:
Window.setContent(result);
Window.display();
gar.previewbox = document.getElementById('gar-previewbox');
result.previewer = new Morebits.wiki.preview(gar.previewbox);
 
};
 
gar.evaluateinitParams = function (eform) {
var form = e.target;
gar.params = {
type: form.gartype.value,
notify: form.notify.checked,
reason: form.reason.value
};
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
gar.garc = gar.params.type === 'garc';
gar.gari = gar.params.type === 'gari';
 
Morebits.simpleWindow.setButtonsEnabled(false);
Morebits.status.init(form);
 
var title_obj = new mw.Title.newFromText(Morebits.pageNameNorm);
gar.title = title_obj.getSubjectPage().toText();
gar.talktitle = title_obj.getTalkPage().toText();
 
gar.usersToNotify = [];
};
 
gar.preview = function(form) {
var tm = new Morebits.taskManagerXXX();
gar.initParams(form);
 
Morebits.status.init(gar.previewbox);
$(gar.previewbox).show();
 
var tm = new Morebits.taskManager();
tm.add(gar.tasks.getNumber, []);
tm.add(gar.tasks.createNomPage, [ gar.tasks.getNumber ]);
tm.add(gar.tasks.editTalkPage, [ gar.tasks.createNomPage ]);
tm.add(gar.tasks.getCreator, []);
tm.add(gar.tasks.getLastGanNominator, []);
tm.add(gar.tasks.getOtherEditors, []);
tm.execute().then(function() {
gar.garpage = 'Wikipedia:Good article reassessment/' + gar.title + '/' + gar.num;
 
var previewText =
'<i>Preview of ' + gar.garpage + ':</i>\n'
+ '----\n'
+ gar.tasks.getNomPageText()
+ '\n----\n'
+ '<i>Notifications will be automatically delivered to the following pages. Uncheck to prevent notification:</i>\n\n'
+ (gar.tasks.getNotificationTargets().length > 0 ?
gar.tasks.getNotificationTargets()
.map(p => '*<span class=gar-user-to-notify>[[User talk:' + p + ']]</span>').join('\n') :
'*<i>None</i>');
 
form.previewer.beginRender(previewText, gar.garpage).then(function () {
$(gar.previewbox).find('.gar-user-to-notify').each(function (_, e) {
$(e).prepend(
$('<input>')
.attr('type', 'checkbox')
.attr('value', mw.Title.newFromText($(e).text()).getMainText())
.prop('checked', true)
);
});
});
}, function () {
form.previewer.beginRender("Unable to render preview", gar.garpage);
});
};
 
gar.evaluate = function(e) {
var form = e.target;
gar.initParams(form);
 
gar.usersNotToNotify = new Set($(gar.previewbox)
.find('.gar-user-to-notify input:not(:checked)')
.get()
.map(e => e.value));
 
Morebits.simpleWindow.setButtonsEnabled(false);
Morebits.status.init(form);
 
var tm = new Morebits.taskManager();
tm.add(gar.tasks.getNumber, []);
tm.add(gar.tasks.editTalkPage, [ gar.tasks.getNumber ]);
tm.add(gar.tasks.createNomPage, [ gar.tasks.editTalkPage ], function () {
Morebits.status.printUserText(gar.tasks.getNomPageText(),
'Your nomination text is provided below, with which you can manually create the page [[' + gar.garpage + ']].');
});
tm.add(gar.tasks.getCreator, []);
tm.add(gar.tasks.getLastGanNominator, []);
tm.add(gar.tasks.getOtherEditors, []);
tm.add(gar.tasks.notify, [ gar.tasks.getCreator, gar.tasks.getLastGanNominator, gar.tasks.getOtherEditors ]);
 
tm.execute().then(function() {
Morebits.status.actionCompleted('Nomination completed. Redirecting to nomination page in 3 seconds...');
new Morebits.status('Notifications', ['The script has notified the the reviewer and page creator. ' +
setTimeout(function() {
'Please consider manually notifying other involved editors and WikiProjects using ',
___location.href = mw.util.getUrl(gar.garpage);
Morebits.htmlNode('code', '{{subst:GARMessage|' + gar.title + '|GARpage=' + gar.num + '}} ~~~~') ], 'warn');
}, 300000);
});
 
Line 136 ⟶ 160:
formatversion: '2',
list: 'allpages',
apnamespace: '4', // WP
apprefix: 'Good article reassessment/' + gar.title + '/',
aplimit: 'max'
};
if (gar.garc) {
query.apnamespace = '4', // WP
query.apprefix = 'Good article reassessment/' + gar.title + '/';
} else {
query.apnamespace = '1', // Talk
query.apprefix = gar.title + '/GA'; // name without namespace
}
var api = new Morebits.wiki.api('Getting numbering', query);
api.post().then(function(apiobj) {
var pages = apiobj.response.query.allpages;
gar.num = pages.length + 1; // HACK
apiobj.getStatusElement().info('Next number is ' + gar.num);
def.resolve();
}, def.reject);
return def;
},
 
getNomPageText: function() {
return '{{subst:GAR/header}}\n' + gar.params.reason.trim() +
(gar.params.reason.trim().endsWith('~~~~') ? '' : ' ~~~~');
},
 
createNomPage: function() {
var def = $.Deferred();
var appendtext = gar.tasks.getNomPageText();
if (gar.garc) {
gar.garpage = 'Wikipedia:Good article reassessment/' + gar.title + '/' + gar.num;
appendtext =
'{{subst:GAR/header}}\n' +
gar.params.reason;
} else {
gar.garpage = gar.talktitle + '/GA' + gar.num;
appendtext =
'==GA Reassessment==\n' +
'{{subst:GAR/subst|{{subst:PAGENAME}}}}\n' +
gar.params.reason;
}
var pageobj = new Morebits.wiki.page(gar.garpage, 'Creating nomination page');
pageobj.setAppendText(appendtext);
Line 179 ⟶ 193:
editTalkPage: function() {
var def = $.Deferred();
gar.garpage = 'Wikipedia:Good article reassessment/' + gar.title + '/' + gar.num;
var talkpage = new Morebits.wiki.page(gar.talktitle, 'Editing talk page');
talkpage.load(function(talkpage) {
Line 185 ⟶ 200:
text = '{{subst:GAR}}\n' + text;
// append transclusion:
text += '\n\n==GA Reassessment==\n' +
if (gar.garc) {
'{{' + gar.garpage + '}}';
text += '\n\n==GA Reassessment==\n' +
'{{' + gar.garpage + '}}';
} else {
text += '\n\n{{' + gar.garpage + '}}';
}
talkpage.setPageText(text);
talkpage.setEditSummary('Nominating for Goodgood Articlearticle Reassessment (GAR)reassessment' + gar.advert);
talkpage.save(def.resolve, def.reject);
}, def.reject);
Line 209 ⟶ 220:
}, def.reject);
return def;
},
 
getLastGanNominator: function () {
return $.get({
url: 'https://sdzerobot.toolforge.org/gans/credit/' + mw.util.wikiUrlencode(gar.title) + '?raw=1',
timeout: 4000
}).then(function (nom) {
if (nom === '<Unknown>') {
return;
}
gar.usersToNotify.push(nom);
}).catch(function () {
return $.Deferred().resolve(); // might be some server issue; don't fail
});
},
 
getOtherEditors: function() {
var def = $.Deferred();
var query = {
"action": "query",
Line 218 ⟶ 242:
"formatversion": "2",
"list": "allpages",
"aplimit": "max"
};
var api_gan = new Morebits.wiki.api('Getting previous GAN reviewers', $.extend(query, {
Line 228 ⟶ 253:
})).post();
 
return $.when(api_gar, api_gan).then(function(result_gan, result_gar) {
var pages = result_gar.response.query.allpages
.concat(result_gan.response.query.allpages);
var lookupsDonedefs = 0;pages.map(function(page) {
var def = $.Deferred();
pages.forEach(function(page) {
var p = new Morebits.wiki.page(page.title, 'Looking up creator of ' + page.title);
p.lookupCreation(function() {
gar.usersToNotify.push(p.getCreator());
p.getStatusElement().info('found ' + p.getCreator());
def.resolve();
if (++lookupsDone === pages.length) { // Hack: #911
}, def.resolve(reject);
}return def;
});
});
return $.when.apply($, defs);
});
},
 
getNotificationTargets: function() {
return Morebits.array.uniq(gar.usersToNotify).filter(function (user) {
return user !== mw.config.get('wgUserName');
});
return def;
},
 
notify: function() {
var usersToNotify = gar.tasks.getNotificationTargets().filter(name => !gar.usersNotToNotify.has(name));
var def = $.Deferred();
var users = Morebits.array.uniq(gar.usersToNotify);
var appendtext = '\n\n' +
'{{subst:GARMessage|' + gar.title + '|GARpage=' + gar.num + '}} ~~~~';
(gar.garc ?
var editsummary = '{{subst:GARMessage|[[' + gar.title + '|GARpage=']] +listed gar.numfor +good '}}article ~~~~reassessment' :+ gar.advert;
var defs = usersToNotify.map(function(user) {
'{{subst:GARMessage|' + gar.title + '|page=' + gar.num + '}} ~~~~');
var def = $.Deferred();
var editsummary = '[[' + gar.title + ']] listed for Good article reassessment' + gar.advert;
users.forEach(function(user, idx) {
var usertalk = new Morebits.wiki.page('User talk:' + user, 'Notifying ' + user);
usertalk.setAppendText(appendtext);
usertalk.setEditSummary(editsummary);
usertalk.append(function()def.resolve, {def.reject);
return def;
if (idx === users.length - 1) { // Hack: till .append() is promisified (#911)
def.resolve();
}
});
});
return def$.when.apply($, defs);
}
 
};
 
function loadTaskManager() {
Morebits.taskManagerXXX = function() { // named so to avoid naming conflict with real one
this.taskDependencyMap = new Map();
this.deferreds = new Map();
this.allDeferreds = []; // Hack: IE doesn't support Map.prototype.values
 
/**
* Register a task along with its dependencies (tasks which should have
* finished execution before we can begin this one).
* Each task is a function that must return a promise.
* @param {function} func - a task
* @param {function[]} deps - its dependencies
*/
this.add = function(func, deps) {
this.taskDependencyMap.set(func, deps);
var deferred = $.Deferred();
this.deferreds.set(func, deferred);
this.allDeferreds.push(deferred);
};
 
/**
* Run all the tasks in correct sequence. Multiple tasks may be run at once.
*/
this.execute = function() {
var self = this; // proxy for `this` for use inside functions where `this` is something else
this.taskDependencyMap.forEach(function(deps, task) {
var depsPromisesArray = deps.map(function(dep) {
return self.deferreds.get(dep);
});
 
$.when.apply(null, depsPromisesArray).then(function() {
console.log('Executing ' + task.name);
task().then(function() {
console.log(task.name + ' is resolved');
self.deferreds.get(task).resolve();
});
});
 
});
 
return $.when.apply(null, this.allDeferreds); // resolved when eveything is done!
};
};
}
 
/* </nowiki> */