MediaWiki:AFC-submit-wizard.js: Difference between revisions

Content deleted Content added
improve variable naming
break up evaluate() - now renamed to handleSubmit(), to smaller functions
Line 47:
"fieldset-label": "Submit your draft for review at Articles for Creation (AfC)",
"title-label": "Draft title",
"title-placeholder": "Enter the draft title, usually begins with \"Draft:\" or \"User:\"",
"title-helptip": "This should be pre-filled if you clicked the link while on the draft page",
"rawclass-label": "Choose the most appropriate category",
Line 114:
items: [
ui.titleLayout = new OO.ui.FieldLayout(ui.titleInput = new mw.widgets.TitleInputWidget({
value: (mw.util.getParamValue('drafttitle') || '').replace(/_/g, ' '),
placeholder: msg('title-placeholder'),
}), {
Line 232:
afc.ibxmapLoaded = getJSONPage('Wikipedia:WikiProject Articles for creation/Infobox WikiProject map.json');
 
ui.submitButton.on('click', evaluatehandleSubmit);
ui.titleInput.on('change', mw.util.debounce(config.debounceDelay, onDraftInputChange));
 
if (mw.util.getParamValue('drafttitle')) {
onDraftInputChange();
}
Line 376:
 
/**
* @param {Object} page - from query API response
* @returns {string[]}
*/
Line 393:
 
/**
* @param {Object} page - from query API response
* @returns {string[]}
*/
Line 408:
}
 
/**
* @param {number} revid
* @returns {jQuery.Promise<string[]>}
*/
function getOresTopics(revid) {
return $.get('https://ores.wikimedia.org/v3/scores/enwiki/?models=drafttopic&revids=' + revid).then(function (json) {
Line 433 ⟶ 437:
return topic.split('.').pop();
})
.filter(function (e) {
return e; // filter out undefined from above
})
.map(function (topic) {
// convert topic string to normalised form
return topic
.replace(/[A-Z]/g, function (match) {
return match[0].toLowerCase();
})
.replace(/ /g, '-')
.replace(/&/g, 'and');
});
});
}
 
/***
* @param {string} text
* @returns {{wikitext: string, name: string}[]}
*/
function extractWikiProjectTagsFromText(text) {
if (!text) {
Line 470 ⟶ 478:
}
 
/**
function evaluate() {
* @param {string} type
 
* @param {string} message
*/
function setMainStatus(type, message) {
if (!ui.mainStatusLayout || !ui.mainStatusLayout.isElementAttached()) {
ui.fieldset.addItems([
ui.mainStatusLayout = new OO.ui.FieldLayout(ui.mainStatusArea = new OO.ui.MessageWidget({))
type: 'notice',
label: msg('status-processing')
}))
]);
}
ui.mainStatusArea.setType(type);
ui.mainStatusArea.setLabel(message);
}
 
 
/**
* @param {string} type
* @param {string} message
*/
function setTalkStatus(type, message) {
if (!ui.talkStatusLayout) {
ui.fieldset.addItems([
ui.talkStatusLayout = new OO.ui.FieldLayout(ui.talkStatusArea = new OO.ui.MessageWidget())
]);
}
ui.talkStatusArea.setType(type);
ui.talkStatusArea.setLabel(message);
}
 
function handleSubmit() {
 
setMainStatus('notice', msg('status-processing'));
ui.submitButton.setDisabled(true);
ui.mainStatusLayout.scrollElementIntoView();
Line 494 ⟶ 523:
"rvslots": "main",
}).then(function (json) {
var pageapiPage = json.query.pages[0];
 
var errors = errorsFromPageData(pageapiPage);
if (errors.length) {
ui.titleLayout.setErrors(errors);
Line 505 ⟶ 534:
}
 
var text = page.revisions[0].slots.main.contentprepareDraftText(apiPage);
 
setMainStatus('notice', msg('status-saving'));
var header = '';
 
 
// Handle short description
var shortDescTemplateExists = /\{\{[Ss]hort ?desc(ription)?\s*\|/.test(text);
var shortDescExists = !!page.description;
var existingShortDesc = page.description;
 
if (ui.shortdescInput.getValue()) {
// 1. No shortdesc - insert the one provided by user
if (!shortDescExists) {
header += '{{Short description|' + ui.shortdescInput.getValue() + '}}\n';
 
// 2. Shortdesc exists from {{short description}} template - replace it
} else if (shortDescExists && shortDescTemplateExists) {
text = text.replace(/\{\{[Ss]hort ?desc(ription)?\s*\|.*?\}\}\n*/g, '');
header += '{{Short description|' + ui.shortdescInput.getValue() + '}}\n';
 
// 3. Shortdesc exists, but not generated by {{short description}}, if the user
// has changed the value, save the new value
} else if (shortDescExists && existingShortDesc !== ui.shortdescInput.getValue()) {
header += '{{Short description|' + ui.shortdescInput.getValue() + '}}\n';
 
// 4. Shortdesc exists, but not generated by {{short description}}, and user hasn't changed the value
} else {
// Do nothing
}
} else {
// User emptied the shortdesc field (or didn't exist from before): remove any existing shortdesc.
// This doesn't remove any shortdesc that is generated by other templates
// Race condition (FIXME): if someone else added a shortdesc to the draft after this user opened the wizard,
// that shortdesc gets removed
text = text.replace(/\{\{[Ss]hort ?desc(ription)?\s*\|.*?\}\}\n*/g, '');
}
 
 
// Draft topics
debug(ui.oresTopicInput);
if (ui.oresTopicLayout.isVisible()) {
afc.oresTopics = ui.oresTopicInput.getValue();
}
if (afc.oresTopics.length) {
text = text.replace(/\{\{[Dd]raft topics\|.*?\}\}\n*/g, '');
header += '{{Draft topics|' + afc.oresTopics.join('|') + '}}\n';
}
 
// Add AfC topic
text = text.replace(/\{\{AfC topic\|(.*?)\}\}/g, '');
header += '{{AfC topic|' + ui.afcTopicInput.getValue() + '}}\n';
 
// put AfC submission template
header += '{{subst:submit|' + (mw.util.getParamValue('username') || mw.config.get('wgUserName')) + '}}\n';
 
// insert everything to the top
text = header + text;
debug(text);
 
ui.mainStatusArea.setType('notice');
ui.mainStatusArea.setLabel(msg('status-saving'));
 
// saving draft page
afc.api.postWithEditToken({
"action": "edit",
Line 575 ⟶ 544:
}).then(function (data) {
if (data.edit && data.edit.result === 'Success') {
ui.mainStatusArea.setTypesetMainStatus('success', msg('status-redirecting'));
ui.mainStatusArea.setLabel(msg('status-redirecting'));
 
setTimeout(function () {
Line 585 ⟶ 553:
}
}).catch(function (code, err) {
setMainStatus('error', msg('error-saving-main', makeErrorMessage(code, err)));
ui.mainStatusArea.setType('error');
ui.mainStatusArea.setLabel(msg('error-saving-main', makeErrorMessage(code, err)));
ui.submitButton.setDisabled(false);
});
 
var talktext = prepareTalkText(afc.talktext);
ui.fieldset.addItems([
ui.talkStatusLayout = new OO.ui.FieldLayout(ui.talkStatusArea = new OO.ui.MessageWidget({
type: 'notice',
label: msg('status-saving-talk')
}))
]);
 
 
// Process text of the talk page
var alreadyExistingWikiProjects = extractWikiProjectTagsFromText(afc.talktext);
var alreadyExistingTags = alreadyExistingWikiProjects.map(function (e) {
return e.name;
});
var tagsToAdd = ui.talkTagsInput.getValue().filter(function (tag) {
return alreadyExistingTags.indexOf(tag) === -1;
});
var tagsToRemove = alreadyExistingTags.filter(function (tag) {
return ui.talkTagsInput.getValue().indexOf(tag) === -1;
});
 
tagsToRemove.forEach(function (tag) {
afc.talktext = afc.talktext.replace(new RegExp('\\{\\{\\s*' + tag + '\\s*(\\|.*?)?\\}\\}\\n?'), '');
});
 
var tagsToAddText = tagsToAdd.map(function (tag) {
return '{{' + tag + '}}';
}).join('\n') + (tagsToAdd.length ? '\n' : '');
 
afc.talktext = tagsToAddText + (afc.talktext || '');
 
setTalkStatus('notice', msg('status-saving-talk'));
afc.api.postWithEditToken({
"action": "edit",
"title": new mw.Title(draft).getTalkPage().toText(),
"text": afc.talktext,
"summary": msg('editsummary-talk')
}).then(function (data) {
if (data.edit && data.edit.result === 'Success') {
ui.talkStatusArea.setTypesetTalkStatus('success', msg('status-talk-success'));
ui.talkStatusArea.setLabel(msg('status-talk-success'));
} else {
return $.Deferred().reject('unexpected-result');
}
}).catch(function (code, err) {
setTalkStatus('error', msg('error-saving-talk', makeErrorMessage(code, err)));
ui.talkStatusArea.setType('error');
ui.talkStatusArea.setLabel(msg('error-saving-talk', makeErrorMessage(code, err)));
});
 
 
}).catch(function (code, err) {
setMainStatus('error', msg('error-main', makeErrorMessage(code, err)));
ui.mainStatusArea.setType('error');
ui.mainStatusArea.setLabel(msg('error-main', makeErrorMessage(code, err)));
ui.submitButton.setDisabled(false);
});
 
}
 
/**
* @param {Object} page - page information from the API
* @returns {string} final draft page text to save
*/
function prepareDraftText(page) {
var text = page.revisions[0].slots.main.content;
 
var header = '';
 
// Handle short description
var shortDescTemplateExists = /\{\{[Ss]hort ?desc(ription)?\s*\|/.test(text);
var shortDescExists = !!page.description;
var existingShortDesc = page.description;
 
if (ui.shortdescInput.getValue()) {
// 1. No shortdesc - insert the one provided by user
if (!shortDescExists) {
header += '{{Short description|' + ui.shortdescInput.getValue() + '}}\n';
 
// 2. Shortdesc exists from {{short description}} template - replace it
} else if (shortDescExists && shortDescTemplateExists) {
text = text.replace(/\{\{[Ss]hort ?desc(ription)?\s*\|.*?\}\}\n*/g, '');
header += '{{Short description|' + ui.shortdescInput.getValue() + '}}\n';
 
// 3. Shortdesc exists, but not generated by {{short description}}, if the user
// has changed the value, save the new value
} else if (shortDescExists && existingShortDesc !== ui.shortdescInput.getValue()) {
header += '{{Short description|' + ui.shortdescInput.getValue() + '}}\n';
 
// 4. Shortdesc exists, but not generated by {{short description}}, and user hasn't changed the value
} else {
// Do nothing
}
} else {
// User emptied the shortdesc field (or didn't exist from before): remove any existing shortdesc.
// This doesn't remove any shortdesc that is generated by other templates
// Race condition (FIXME): if someone else added a shortdesc to the draft after this user opened the wizard,
// that shortdesc gets removed
text = text.replace(/\{\{[Ss]hort ?desc(ription)?\s*\|.*?\}\}\n*/g, '');
}
 
 
// Draft topics
debug(ui.oresTopicInput);
if (ui.oresTopicLayout.isVisible()) {
afc.oresTopics = ui.oresTopicInput.getValue();
}
if (afc.oresTopics.length) {
text = text.replace(/\{\{[Dd]raft topics\|.*?\}\}\n*/g, '');
header += '{{Draft topics|' + afc.oresTopics.join('|') + '}}\n';
}
 
// Add AfC topic
text = text.replace(/\{\{AfC topic\|(.*?)\}\}/g, '');
header += '{{AfC topic|' + ui.afcTopicInput.getValue() + '}}\n';
 
// put AfC submission template
header += '{{subst:submit|' + (mw.util.getParamValue('username') || mw.config.get('wgUserName')) + '}}\n';
 
// insert everything to the top
text = header + text;
debug(text);
 
return text;
}
 
 
/**
* @param {string} initialText - initial talk page text
* @returns {string} - final talk page text to save
*/
function prepareTalkText(initialText) {
var text = initialText;
 
// Process text of the talk page
var alreadyExistingWikiProjects = extractWikiProjectTagsFromText(text);
var alreadyExistingTags = alreadyExistingWikiProjects.map(function (e) {
return e.name;
});
var tagsToAdd = ui.talkTagsInput.getValue().filter(function (tag) {
return alreadyExistingTags.indexOf(tag) === -1;
});
var tagsToRemove = alreadyExistingTags.filter(function (tag) {
return ui.talkTagsInput.getValue().indexOf(tag) === -1;
});
 
tagsToRemove.forEach(function (tag) {
text = text.replace(new RegExp('\\{\\{\\s*' + tag + '\\s*(\\|.*?)?\\}\\}\\n?'), '');
});
 
var tagsToAddText = tagsToAdd.map(function (tag) {
return '{{' + tag + '}}';
}).join('\n') + (tagsToAdd.length ? '\n' : '');
 
text = tagsToAddText + (text || '');
return text;
}