Skip to content

Commit

Permalink
Merge branch 'master' into test-check-incompatible
Browse files Browse the repository at this point in the history
  • Loading branch information
NovemLinguae authored Dec 9, 2024
2 parents e2cff9f + e40b960 commit 59c074c
Show file tree
Hide file tree
Showing 19 changed files with 302 additions and 244 deletions.
4 changes: 0 additions & 4 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,9 @@
"no-new": "warn",
"no-return-assign": "warn",
"no-script-url": "warn",
"no-throw-literal": "warn",
"no-underscore-dangle": "warn",
"no-unused-expressions": "warn",
"no-use-before-define": "warn",
"no-useless-concat": "warn",
"no-var": "warn",
"prefer-const": "warn",
"unicorn/prefer-string-slice": "warn"
}
}
11 changes: 11 additions & 0 deletions DEVELOPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,14 @@ All the dependencies that Twinkle uses are JavaScript **dev** dependencies. They
- mwn - Used when you run `npm start`. `npm start` is what enables localhost testing.

When updating dependencies, CI should take care of testing most of that. Manually testing `npm start` should be the only additional check needed.

### Adding a CSD

Here is a checklist for writing a patch to add a speedy deletion criteria called A1:

* Write a patch similar to this one: https://github.com/wikimedia-gadgets/twinkle/pull/2097/files
* If you want any of the config options to be on by default (instead of off by default), modify twinkle.js -> Twinkle.defaultConfig.
* On wiki, create these pages. Copy an existing template and adjust as needed.
* Template:Db-a1, which will be placed on the page tagged for deletion.
* Template:Db-a1-notice, which will be placed on the user talk page of the author of the page tagged for deletion.
* Template:Db-a1-deleted, which will be placed on the user talk page of the author of the page deleted.
86 changes: 47 additions & 39 deletions modules/twinklearv.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ Twinkle.arv.callback.changeCategory = function (e) {
work_area.append(
{
type: 'dyninput',
name: 'sockpuppet',
name: 'sockpuppets',
label: 'Sockpuppets',
sublabel: 'Sock:',
tooltip: 'The username of the sockpuppet without the "User:" prefix',
Expand Down Expand Up @@ -574,26 +574,32 @@ Twinkle.arv.callback.evaluate = function(e) {
case 'sock':
/* falls through */
case 'puppet':
var sockParameters = {
evidence: form.evidence.value.trim(),
checkuser: form.checkuser.checked
};
var reportData = Twinkle.arv.callback.getSpiReportData(input);

var puppetReport = form.category.value === 'puppet';
if (puppetReport && !form.sockmaster.value.trim()) {
alert('You have not entered a sockmaster account for this puppet. Consider reporting this account as a sockpuppeteer instead.');
return;
} else if (!puppetReport && !form.sockpuppet[0].value.trim()) {
alert('You have not entered any sockpuppet account(s) for this sockmaster. Consider reporting this account as a sockpuppet instead.');
if (reportData.error) {
alert(reportData.error);
return;
}

sockParameters.uid = puppetReport ? form.sockmaster.value.trim() : uid;
sockParameters.sockpuppets = puppetReport ? [uid] : Morebits.array.uniq($.map($('input:text[name=sockpuppet]', form), (o) => $(o).val() || null));

Morebits.SimpleWindow.setButtonsEnabled(false);
Morebits.Status.init(form);
Twinkle.arv.processSock(sockParameters);

Morebits.wiki.addCheckpoint(); // prevent notification events from causing an erronous "action completed"

var reportpage = 'Wikipedia:Sockpuppet investigations/' + reportData.sockmaster;

Morebits.wiki.actionCompleted.redirect = reportpage;
Morebits.wiki.actionCompleted.notice = 'Reporting complete';

var spiPage = new Morebits.wiki.page(reportpage, 'Retrieving discussion page');
spiPage.setFollowRedirect(true);
spiPage.setEditSummary('Adding new report for [[Special:Contributions/' + reportData.sockmaster + '|' + reportData.sockmaster + ']].');
spiPage.setChangeTags(Twinkle.changeTags);
spiPage.setAppendText(reportData.wikitext);
spiPage.setWatchlist(Twinkle.getPref('spiWatchReport'));
spiPage.append();

Morebits.wiki.removeCheckpoint(); // all page updates have been started
break;

case 'an3':
Expand Down Expand Up @@ -818,32 +824,34 @@ Twinkle.arv.callback.getUsernameReportWikitext = function(input) {
return text;
};

Twinkle.arv.processSock = function(params) {
Morebits.wiki.addCheckpoint(); // prevent notification events from causing an erronous "action completed"
Twinkle.arv.callback.getSpiReportData = function(input) {
const isPuppetReport = input.category === 'puppet';

// prepare the SPI report
let text = '\n{{subst:SPI report|' +
params.sockpuppets.map((sock, index) => (index + 1) + '=' + sock).join('|') + '\n|evidence=' + params.evidence + ' \n';
if (!isPuppetReport) {
input.sockpuppets = input.sockpuppets.filter((sock) => sock !== ''); // ignore empty sockpuppet inputs
}

if (params.checkuser) {
text += '|checkuser=yes';
if (isPuppetReport && !input.sockmaster) {
return { error: 'You have not entered a sockmaster account for this puppet. Consider reporting this account as a sockpuppeteer instead.' };
} else if (!isPuppetReport && input.sockpuppets.length === 0) {
return { error: 'You have not entered any sockpuppet account(s) for this sockmaster. Consider reporting this account as a sockpuppet instead.' };
}
text += '}}';

const reportpage = 'Wikipedia:Sockpuppet investigations/' + params.uid;
input.sockmaster = input.sockmaster || input.uid;
input.sockpuppets = isPuppetReport ? [input.uid] : Morebits.array.uniq(input.sockpuppets);

Morebits.wiki.actionCompleted.redirect = reportpage;
Morebits.wiki.actionCompleted.notice = 'Reporting complete';
let text = '\n{{subst:SPI report|' +
input.sockpuppets.map((sock, index) => (index + 1) + '=' + sock).join('|') + '\n|evidence=' + input.evidence + ' \n';

const spiPage = new Morebits.wiki.Page(reportpage, 'Retrieving discussion page');
spiPage.setFollowRedirect(true);
spiPage.setEditSummary('Adding new report for [[Special:Contributions/' + params.uid + '|' + params.uid + ']].');
spiPage.setChangeTags(Twinkle.changeTags);
spiPage.setAppendText(text);
spiPage.setWatchlist(Twinkle.getPref('spiWatchReport'));
spiPage.append();
if (input.checkuser) {
text += '|checkuser=yes';
}
text += '}}';

Morebits.wiki.removeCheckpoint(); // all page updates have been started
return {
sockmaster: input.sockmaster,
wikitext: text
};
};

Twinkle.arv.processAN3 = function(params) {
Expand Down Expand Up @@ -921,19 +929,19 @@ Twinkle.arv.processAN3 = function(params) {
ret += sub.reverse().map((v) => (sub.length >= 2 ? '#' : '') + '# {{diff2|' + v.revid + '|' + new Morebits.Date(v.timestamp).format('HH:mm, D MMMM YYYY', 'utc') + ' (UTC)}} ' + hasHiddenComment(v)).join('\n');
return ret;
}).reverse().join('\n');
const warningtext = params.warnings.reverse().map((v) => '# ' + ' {{diff2|' + v.revid + '|' + new Morebits.Date(v.timestamp).format('HH:mm, D MMMM YYYY', 'utc') + ' (UTC)}} ' + hasHiddenComment(v)).join('\n');
let resolvetext = params.resolves.reverse().map((v) => '# ' + ' {{diff2|' + v.revid + '|' + new Morebits.Date(v.timestamp).format('HH:mm, D MMMM YYYY', 'utc') + ' (UTC)}} ' + hasHiddenComment(v)).join('\n');
const warningtext = params.warnings.reverse().map((v) => '# {{diff2|' + v.revid + '|' + new Morebits.Date(v.timestamp).format('HH:mm, D MMMM YYYY', 'utc') + ' (UTC)}} ' + hasHiddenComment(v)).join('\n');
let resolvetext = params.resolves.reverse().map((v) => '# {{diff2|' + v.revid + '|' + new Morebits.Date(v.timestamp).format('HH:mm, D MMMM YYYY', 'utc') + ' (UTC)}} ' + hasHiddenComment(v)).join('\n');

if (params.free_resolves) {
const page = params.free_resolves;
if (page.compare) {
resolvetext += '\n# ' + ' {{diff|oldid=' + page.compare.fromrevid + '|diff=' + page.compare.torevid + '|label=Consecutive edits on ' + page.compare.totitle + '}}';
resolvetext += '\n# {{diff|oldid=' + page.compare.fromrevid + '|diff=' + page.compare.torevid + '|label=Consecutive edits on ' + page.compare.totitle + '}}';
} else if (page.revisions) {
const revCount = page.revisions.length;
let rev;
if (revCount < 3) { // diff=prev or next
rev = revCount === 1 ? page.revisions[0] : page.revisions[1];
resolvetext += '\n# ' + ' {{diff2|' + rev.revid + '|' + new Morebits.Date(rev.timestamp).format('HH:mm, D MMMM YYYY', 'utc') + ' (UTC) on ' + page.title + '}} ' + hasHiddenComment(rev);
resolvetext += '\n# {{diff2|' + rev.revid + '|' + new Morebits.Date(rev.timestamp).format('HH:mm, D MMMM YYYY', 'utc') + ' (UTC) on ' + page.title + '}} ' + hasHiddenComment(rev);
} else { // diff and oldid are nonconsecutive
rev = page.revisions[0];
const revLatest = page.revisions[revCount - 1];
Expand All @@ -949,7 +957,7 @@ Twinkle.arv.processAN3 = function(params) {
comment += ' ~~~~';
}

const text = '\n\n' + '{{subst:AN3 report|diffs=' + difftext + '|warnings=' + warningtext + '|resolves=' + resolvetext + '|pagename=' + params.page + '|orig=' + origtext + '|comment=' + comment + '|uid=' + params.uid + '}}';
const text = '\n\n{{subst:AN3 report|diffs=' + difftext + '|warnings=' + warningtext + '|resolves=' + resolvetext + '|pagename=' + params.page + '|orig=' + origtext + '|comment=' + comment + '|uid=' + params.uid + '}}';

const reportpage = 'Wikipedia:Administrators\' noticeboard/Edit warring';

Expand Down
10 changes: 5 additions & 5 deletions modules/twinklebatchdelete.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,9 @@ Twinkle.batchdelete.callback.toggleSubpages = function twDbatchToggleSubpages(e)
if (subpagesLoaded) {

$.each(Twinkle.batchdelete.pages, (i, el) => {
// Get back the subgroup from subgroup_, where we saved it
if (el.subgroup === null && el.subgroup_) {
el.subgroup = el.subgroup_;
// Get back the subgroup from subgroupBeforeDeletion, where we saved it
if (el.subgroup === null && el.subgroupBeforeDeletion) {
el.subgroup = el.subgroupBeforeDeletion;
}
});

Expand Down Expand Up @@ -388,10 +388,10 @@ Twinkle.batchdelete.callback.toggleSubpages = function twDbatchToggleSubpages(e)

$.each(Twinkle.batchdelete.pages, (i, el) => {
if (el.subgroup) {
// Remove subgroup after saving its contents in subgroup_
// Remove subgroup after saving its contents in subgroupBeforeDeletion
// so that it can be retrieved easily if user decides to
// delete the subpages again
el.subgroup_ = el.subgroup;
el.subgroupBeforeDeletion = el.subgroup;
el.subgroup = null;
}
});
Expand Down
3 changes: 2 additions & 1 deletion modules/twinklebatchprotect.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ Twinkle.batchprotect.callback = function twinklebatchprotectCallback() {
pages.sort(Twinkle.sortByNamespace);
pages.forEach((page) => {
const metadata = [];
let missing = !!page.missing, editProt;
const missing = !!page.missing;
let editProt;

if (missing) {
metadata.push('page does not exist');
Expand Down
58 changes: 37 additions & 21 deletions modules/twinkleblock.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

(function() {

let api = new mw.Api(), relevantUserName, blockedUserName;
const api = new mw.Api();
let relevantUserName, blockedUserName;
const menuFormattedNamespaces = $.extend({}, mw.config.get('wgFormattedNamespaces'));
menuFormattedNamespaces[0] = '(Article)';

Expand Down Expand Up @@ -156,8 +157,8 @@ Twinkle.block.fetchedData = {};
// Processes the data from a a query response, separated from
// Twinkle.block.fetchUserInfo to allow reprocessing of already-fetched data
Twinkle.block.processUserInfo = function twinkleblockProcessUserInfo(data, fn) {
let blockinfo = data.query.blocks[0],
userinfo = data.query.users[0];
let blockinfo = data.query.blocks[0];
const userinfo = data.query.users[0];
// If an IP is blocked *and* rangeblocked, the above finds
// whichever block is more recent, not necessarily correct.
// Three seems... unlikely
Expand Down Expand Up @@ -296,7 +297,8 @@ Twinkle.block.callback.change_block64 = function twinkleblockCallbackChangeBlock
};

Twinkle.block.callback.change_action = function twinkleblockCallbackChangeAction(e) {
let field_preset, field_template_options, field_block_options, $form = $(e.target.form);
let field_preset, field_template_options, field_block_options;
const $form = $(e.target.form);
// Make ifs shorter
const blockBox = $form.find('[name=actiontype][value=block]').is(':checked');
const templateBox = $form.find('[name=actiontype][value=template]').is(':checked');
Expand Down Expand Up @@ -1534,7 +1536,7 @@ Twinkle.block.callback.change_expiry = function twinkleblockCallbackChangeExpiry
Twinkle.block.seeAlsos = [];
Twinkle.block.callback.toggle_see_alsos = function twinkleblockCallbackToggleSeeAlso() {
const reason = this.form.reason.value.replace(
new RegExp('( <!--|;) ' + 'see also ' + Twinkle.block.seeAlsos.join(' and ') + '( -->)?'), ''
new RegExp('( <!--|;) see also ' + Twinkle.block.seeAlsos.join(' and ') + '( -->)?'), ''
);

Twinkle.block.seeAlsos = Twinkle.block.seeAlsos.filter((el) => el !== this.value);
Expand Down Expand Up @@ -1572,7 +1574,8 @@ Twinkle.block.callback.toggle_ds_reason = function twinkleblockCallbackToggleDSR
};

Twinkle.block.callback.update_form = function twinkleblockCallbackUpdateForm(e, data) {
let form = e.target.form, expiry = data.expiry;
const form = e.target.form;
let expiry = data.expiry;

// don't override original expiry if useInitialOptions is set
if (!data.useInitialOptions) {
Expand Down Expand Up @@ -1723,11 +1726,11 @@ Twinkle.block.callback.preview = function twinkleblockcallbackPreview(form) {
};

Twinkle.block.callback.evaluate = function twinkleblockCallbackEvaluate(e) {
let $form = $(e.target),
const $form = $(e.target),
toBlock = $form.find('[name=actiontype][value=block]').is(':checked'),
toWarn = $form.find('[name=actiontype][value=template]').is(':checked'),
toPartial = $form.find('[name=actiontype][value=partial]').is(':checked'),
blockoptions = {}, templateoptions = {};
toPartial = $form.find('[name=actiontype][value=partial]').is(':checked');
let blockoptions = {}, templateoptions = {};

Twinkle.block.callback.saveFieldset($form.find('[name=field_block_options]'));
Twinkle.block.callback.saveFieldset($form.find('[name=field_template_options]'));
Expand Down Expand Up @@ -1899,13 +1902,14 @@ Twinkle.block.callback.issue_template = function twinkleblockCallbackIssueTempla
// "talk page" of an IP range (which does not exist)
const userTalkPage = 'User_talk:' + mw.config.get('wgRelevantUserName');

const params = $.extend(formData, {
messageData: Twinkle.block.blockPresetsInfo[formData.template],
reason: Twinkle.block.field_template_options.block_reason,
disabletalk: Twinkle.block.field_template_options.notalk,
noemail: Twinkle.block.field_template_options.noemail_template,
nocreate: Twinkle.block.field_template_options.nocreate_template
});
const params = Twinkle.block.combineFormDataAndFieldTemplateOptions(
formData,
Twinkle.block.blockPresetsInfo[formData.template],
Twinkle.block.field_template_options.block_reason,
Twinkle.block.field_template_options.notalk,
Twinkle.block.field_template_options.noemail_template,
Twinkle.block.field_template_options.nocreate_template
);

Morebits.wiki.actionCompleted.redirect = userTalkPage;
Morebits.wiki.actionCompleted.notice = 'Actions complete, loading user talk page in a few seconds';
Expand All @@ -1915,8 +1919,19 @@ Twinkle.block.callback.issue_template = function twinkleblockCallbackIssueTempla
wikipedia_page.load(Twinkle.block.callback.main);
};

Twinkle.block.combineFormDataAndFieldTemplateOptions = function(formData, messageData, reason, disabletalk, noemail, nocreate) {
return $.extend(formData, {
messageData: messageData,
reason: reason,
disabletalk: disabletalk,
noemail: noemail,
nocreate: nocreate
});
};

Twinkle.block.callback.getBlockNoticeWikitext = function(params) {
let text = '{{', settings = Twinkle.block.blockPresetsInfo[params.template];
let text = '{{';
const settings = Twinkle.block.blockPresetsInfo[params.template];
if (!settings.nonstandard) {
text += 'subst:' + params.template;
if (params.article && settings.pageParam) {
Expand Down Expand Up @@ -1990,10 +2005,10 @@ Twinkle.block.callback.getBlockNoticeWikitext = function(params) {
};

Twinkle.block.callback.main = function twinkleblockcallbackMain(pageobj) {
let params = pageobj.getCallbackParameters(),
const params = pageobj.getCallbackParameters(),
date = new Morebits.Date(pageobj.getLoadTime()),
messageData = params.messageData,
text;
messageData = params.messageData;
let text;

params.indefinite = Morebits.string.isInfinity(params.expiry);

Expand All @@ -2003,7 +2018,8 @@ Twinkle.block.callback.main = function twinkleblockcallbackMain(pageobj) {
} else {
text = pageobj.getPageText();

let dateHeaderRegex = date.monthHeaderRegex(), dateHeaderRegexLast, dateHeaderRegexResult;
const dateHeaderRegex = date.monthHeaderRegex();
let dateHeaderRegexLast, dateHeaderRegexResult;
while ((dateHeaderRegexLast = dateHeaderRegex.exec(text)) !== null) {
dateHeaderRegexResult = dateHeaderRegexLast;
}
Expand Down
17 changes: 9 additions & 8 deletions modules/twinkleconfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
and adds an ad box to the top of user subpages belonging to the
currently logged-in user which end in '.js'
* Active on: What I just said. Yeah.
I, [[User:This, that and the other]], originally wrote this. If the code is misbehaving, or you have any
questions, don't hesitate to ask me. (This doesn't at all imply [[WP:OWN]]ership - it's just meant to
point you in the right direction.) -- TTO
*/

Twinkle.config = {};
Expand Down Expand Up @@ -1075,7 +1071,8 @@ Twinkle.config.init = function twinkleconfigInit() {
}
cell = document.createElement('td');

let label, input, gotPref = Twinkle.getPref(pref.name);
let label, input;
const gotPref = Twinkle.getPref(pref.name);
switch (pref.type) {

case 'boolean': // create a checkbox
Expand Down Expand Up @@ -1295,9 +1292,11 @@ Twinkle.config.init = function twinkleconfigInit() {
// Styled in twinkle.css
box.setAttribute('id', 'twinkle-config-headerbox');

let link,
scriptPageName = mw.config.get('wgPageName').slice(mw.config.get('wgPageName').lastIndexOf('/') + 1,
mw.config.get('wgPageName').lastIndexOf('.js'));
let link;
const scriptPageName = mw.config.get('wgPageName').slice(
mw.config.get('wgPageName').lastIndexOf('/') + 1,
mw.config.get('wgPageName').lastIndexOf('.js')
);

if (scriptPageName === 'twinkleoptions') {
// place "why not try the preference panel" notice
Expand Down Expand Up @@ -1694,13 +1693,15 @@ Twinkle.config.writePrefs = function twinkleconfigWritePrefs(pageobj) {
'// changing the configuration parameters in a valid-JavaScript way) will be\n' +
'// overwritten the next time you click "save" in the Twinkle preferences\n' +
'// panel. If modifying this file, make sure to use correct JavaScript.\n' +
// eslint-disable-next-line no-useless-concat
'// <no' + 'wiki>\n' +
'\n' +
'window.Twinkle.prefs = ';
text += JSON.stringify(newConfig, null, 2);
text +=
';\n' +
'\n' +
// eslint-disable-next-line no-useless-concat
'// </no' + 'wiki>\n' +
'// End of twinkleoptions.js\n';

Expand Down
Loading

0 comments on commit 59c074c

Please sign in to comment.