diff --git a/src/modules/twinkletag.js b/src/modules/twinkletag.js index 6a146f5dd..fc0fe6980 100644 --- a/src/modules/twinkletag.js +++ b/src/modules/twinkletag.js @@ -547,46 +547,6 @@ const translationSubgroups = [ } ] : []); -// Subgroups for {{merge}}, {{merge-to}} and {{merge-from}} -const getMergeSubgroups = function(tag) { - let otherTagName = 'Merge'; - switch (tag) { - case 'Merge from': - otherTagName = 'Merge to'; - break; - case 'Merge to': - otherTagName = 'Merge from'; - break; - // no default - } - return [ - { - name: 'mergeTarget', - type: 'input', - label: 'Other article(s):', - tooltip: 'If specifying multiple articles, separate them with pipe characters: Article one|Article two', - required: true - }, - { - type: 'checkbox', - list: [ - { - name: 'mergeTagOther', - label: 'Tag the other article with a {{' + otherTagName + '}} tag', - checked: true, - tooltip: 'Only available if a single article name is entered.' - } - ] - } - ].concat(mw.config.get('wgNamespaceNumber') === 0 ? { - name: 'mergeReason', - type: 'textarea', - label: 'Rationale for merge (will be posted on ' + - (tag === 'Merge to' ? 'the other article\'s' : 'this article\'s') + ' talk page):', - tooltip: 'Optional, but strongly recommended. Leave blank if not wanted. Only available if a single article name is entered.' - } : []); -}; - // Tags arranged by category; will be used to generate the alphabetical list, // but tags should be in alphabetical order within the categories // excludeMI: true indicate a tag that *does not* work inside {{multiple issues}} @@ -930,13 +890,7 @@ Twinkle.tag.article.tagList = { tooltip: 'For complex cases, provide extra instructions for the reviewing administrator.' } ] - }, - { tag: 'Merge', description: 'should be merged with another given article', excludeMI: true, - subgroup: getMergeSubgroups('Merge') }, - { tag: 'Merge from', description: 'another given article should be merged into this one', excludeMI: true, - subgroup: getMergeSubgroups('Merge from') }, - { tag: 'Merge to', description: 'should be merged into another given article', excludeMI: true, - subgroup: getMergeSubgroups('Merge to') } + } ], Splitting: [ { tag: 'Split', description: 'should be split into multiple pages' }, @@ -1402,41 +1356,6 @@ Twinkle.tag.callbacks = { coiTalkPage.newSection(); } - // Special functions for merge tags - // Post a rationale on the talk page (mainspace only) - if (params.mergeReason) { - const mergeTalkPage = new Morebits.wiki.Page('Talk:' + params.discussArticle, 'Posting rationale on talk page'); - mergeTalkPage.setNewSectionText(params.mergeReason.trim() + ' ~~~~'); - mergeTalkPage.setNewSectionTitle(params.talkDiscussionTitleLinked); - mergeTalkPage.setChangeTags(Twinkle.changeTags); - mergeTalkPage.setWatchlist(Twinkle.getPref('watchMergeDiscussions')); - mergeTalkPage.setCreateOption('recreate'); - mergeTalkPage.newSection(); - } - // Tag the target page (if requested) - if (params.mergeTagOther) { - let otherTagName = 'Merge'; - if (params.mergeTag === 'Merge from') { - otherTagName = 'Merge to'; - } else if (params.mergeTag === 'Merge to') { - otherTagName = 'Merge from'; - } - const newParams = { - tags: [otherTagName], - tagsToRemove: [], - tagsToRemain: [], - mergeTarget: Morebits.pageNameNorm, - discussArticle: params.discussArticle, - talkDiscussionTitle: params.talkDiscussionTitle, - talkDiscussionTitleLinked: params.talkDiscussionTitleLinked - }; - const otherpage = new Morebits.wiki.Page(params.mergeTarget, 'Tagging other page (' + - params.mergeTarget + ')'); - otherpage.setChangeTags(Twinkle.changeTags); - otherpage.setCallbackParameters(newParams); - otherpage.load(Twinkle.tag.callbacks.article); - } - // Special functions for {{not English}} and {{rough translation}} // Post at WP:PNT (mainspace only) if (params.translationPostAtPNT) { @@ -1619,30 +1538,6 @@ Twinkle.tag.callbacks = { currentTag += '|listed=yes'; } break; - case 'Merge': - case 'Merge to': - case 'Merge from': - params.mergeTag = tagName; - // normalize the merge target for now and later - params.mergeTarget = Morebits.string.toUpperCaseFirstChar(params.mergeTarget.replace(/_/g, ' ')); - - currentTag += '|' + params.mergeTarget; - - // link to the correct section on the talk page, for article space only - if (mw.config.get('wgNamespaceNumber') === 0 && (params.mergeReason || params.discussArticle)) { - if (!params.discussArticle) { - // discussArticle is the article whose talk page will contain the discussion - params.discussArticle = tagName === 'Merge to' ? params.mergeTarget : mw.config.get('wgTitle'); - // nonDiscussArticle is the article which won't have the discussion - params.nonDiscussArticle = tagName === 'Merge to' ? mw.config.get('wgTitle') : params.mergeTarget; - const direction = '[[' + params.nonDiscussArticle + ']]' + (params.mergeTag === 'Merge' ? ' with ' : ' into ') + '[[' + params.discussArticle + ']]'; - params.talkDiscussionTitleLinked = 'Proposed merge of ' + direction; - params.talkDiscussionTitle = params.talkDiscussionTitleLinked.replace(/\[\[(.*?)\]\]/g, '$1'); - } - const titleWithSectionRemoved = params.discussArticle.replace(/^([^#]*)#.*$/, '$1'); // If article name is Test#Section, delete #Section - currentTag += '|discuss=Talk:' + titleWithSectionRemoved + '#' + params.talkDiscussionTitle; - } - break; default: break; } @@ -1693,15 +1588,11 @@ Twinkle.tag.callbacks = { tags.push(tag); } } else { - if (tag === 'Merge from' || tag === 'History merge') { + if (tag === 'History merge') { tags.push(tag); } else { Morebits.Status.warn('Info', 'Found {{' + tag + '}} on the article already...excluding'); - // don't do anything else with merge tags - if (['Merge', 'Merge to'].includes(tag)) { - params.mergeTarget = params.mergeReason = params.mergeTagOther = null; - } } } }); @@ -2038,17 +1929,6 @@ Twinkle.tag.callback.evaluate = function twinkletagCallbackEvaluate(e) { params.tagsToRemove = form.getUnchecked('existingTags'); // not in `input` params.tagsToRemain = params.existingTags || []; // container not created if none present - if ((params.tags.includes('Merge')) || (params.tags.includes('Merge from')) || - (params.tags.includes('Merge to'))) { - if (Twinkle.tag.checkIncompatible(['Merge', 'Merge from', 'Merge to'], params.tags, 'If several merges are required, use {{Merge}} and separate the article names with pipes (although in this case Twinkle cannot tag the other articles automatically).')) { - return; - } - if ((params.mergeTagOther || params.mergeReason) && params.mergeTarget.includes('|')) { - alert('Tagging multiple articles in a merge, and starting a discussion for multiple articles, is not supported at the moment. Please turn off "tag other article", and/or clear out the "reason" box, and try again.'); - return; - } - } - if (Twinkle.tag.checkIncompatible(['Not English', 'Rough translation'], params.tags)) { return; } diff --git a/src/modules/twinklexfd.js b/src/modules/twinklexfd.js index ef34367bb..8783a029e 100644 --- a/src/modules/twinklexfd.js +++ b/src/modules/twinklexfd.js @@ -317,6 +317,27 @@ Twinkle.xfd.callback.change_category = function twinklexfdCallbackChangeCategory style: 'margin-bottom: 5px; margin-top: -5px;' }); + work_area.append({ + type: 'select', + name: 'outcome', + label: 'Desired outcome:', + event: Twinkle.xfd.callbacks.changeAfdOutcome, + list: [ + { label: 'Delete', value: 'deletion' }, + { label: 'Merge', value: 'merging' }, + { label: 'Redirect', value: 'redirecting' }, + { label: 'Draftify', value: 'draftification' } + ] + }); + + work_area.append({ + name: 'afdtarget', + type: 'input', + label: 'Target page:', + tooltip: 'Target page for the redirect or merge.', + event: Twinkle.xfd.callbacks.changeAfdTarget + }); + work_area.append({ type: 'checkbox', list: [ @@ -373,6 +394,9 @@ Twinkle.xfd.callback.change_category = function twinklexfdCallbackChangeCategory work_area = work_area.render(); old_area.parentNode.replaceChild(work_area, old_area); + // Now that we've rendered the form, hide the target text box. Unhide it later for certain outcomes, using a callback. + $('[name="afdtarget"]').parent().hide(); + Twinkle.makeFindSourcesDiv('#twinkle-xfd-findsources'); $(work_area).find('[name=delsortCats]') @@ -750,7 +774,50 @@ Twinkle.xfd.callback.change_category = function twinklexfdCallbackChangeCategory }; Twinkle.xfd.callbacks = { - // Requires having the tag text (params.tagText) set ahead of time + /** If the user hasn't modified the reason much, modify the reason to include the target article. If the user has modified the reason box with a custom reason, do nothing, since we don't want to blank their work. */ + changeAfdTarget: function() { + const $afdTarget = $('[name="afdtarget"]'); + const $reason = $('[name="reason"]'); + const $outcome = $('[name="outcome"]'); + if ($reason.val().endsWith('because ')) { + // Target has something typed in + if ($afdTarget.val()) { + if ($outcome.val() === 'redirecting') { + $reason.val(`I propose '''redirecting''' to [[${$afdTarget.val()}]] because `); + } else if ($outcome.val() === 'merging') { + $reason.val(`I propose '''merging''' to [[${$afdTarget.val()}]] because `); + } + // Target is blank + } else { + if ($outcome.val() === 'redirecting') { + $reason.val("I propose '''redirecting''' because "); + } else if ($outcome.val() === 'merging') { + $reason.val("I propose '''merging''' because "); + } + } + } + }, + /** Print a default reason in the reason textarea, depending on which outcome is selected from the outcome dropdown list. */ + changeAfdOutcome: function() { + const $outcome = $('[name="outcome"]'); + const $reason = $('[name="reason"]'); + const $afdTarget = $('[name="afdtarget"]'); + $afdTarget.val(''); + if ($outcome.val() === 'redirecting') { + $reason.val("I propose '''redirecting''' because "); + $afdTarget.parent().show(); + } else if ($outcome.val() === 'merging') { + $reason.val("I propose '''merging''' because "); + $afdTarget.parent().show(); + } else if ($outcome.val() === 'draftification') { + $reason.val("I propose '''draftifying''' because "); + $afdTarget.parent().hide(); + } else if ($outcome.val() === 'deletion') { + $reason.val(''); + $afdTarget.parent().hide(); + } + }, + /** Requires having the tag text (params.tagText) set ahead of time */ autoEditRequest: function(pageobj, params) { const talkName = new mw.Title(pageobj.getPageName()).getTalkPage().toText(); if (talkName === pageobj.getPageName()) { @@ -900,11 +967,12 @@ Twinkle.xfd.callbacks = { // Ensure items with User talk or no namespace prefix both end // up at user talkspace as expected, but retain the // prefix-less username for addToLog - notifyTarget = mw.Title.newFromText(notifyTarget, 3); + const userTalkNamespace = 3; + notifyTarget = mw.Title.newFromText(notifyTarget, userTalkNamespace); const targetNS = notifyTarget.getNamespaceId(); - const usernameOrTarget = notifyTarget.getRelativeText(3); + const usernameOrTarget = notifyTarget.getRelativeText(userTalkNamespace); notifyTarget = notifyTarget.toText(); - if (targetNS === 3) { + if (targetNS === userTalkNamespace) { // Disallow warning yourself if (usernameOrTarget === mw.config.get('wgUserName')) { Morebits.Status.warn('You (' + usernameOrTarget + ') created this page; skipping user notification'); @@ -919,25 +987,7 @@ Twinkle.xfd.callbacks = { actionName = actionName || 'Notifying initial contributor (' + usernameOrTarget + ')'; } - let notifytext = '\n{{subst:' + params.venue + ' notice'; - // Venue-specific parameters - switch (params.venue) { - case 'afd': - case 'mfd': - notifytext += params.numbering !== '' ? '|order= ' + params.numbering : ''; - break; - case 'tfd': - if (params.xfdcat === 'tfm') { - notifytext = '\n{{subst:Tfm notice|2=' + params.tfdtarget; - } - break; - case 'cfd': - notifytext += '|action=' + params.action + (mw.config.get('wgNamespaceNumber') === 10 ? '|stub=yes' : ''); - break; - default: // ffd, rfd - break; - } - notifytext += '|1=' + Morebits.pageNameNorm + '}} ~~~~'; + const notifyText = Twinkle.xfd.callbacks.generateUserTalkNoticeWikitext(params); // Link to the venue; object used here rather than repetitive items in switch const venueNames = { @@ -952,7 +1002,7 @@ Twinkle.xfd.callbacks = { Morebits.pageNameNorm + ']] at [[WP:' + venueNames[params.venue] + ']].'; const usertalkpage = new Morebits.wiki.Page(notifyTarget, actionName); - usertalkpage.setAppendText(notifytext); + usertalkpage.setAppendText(notifyText); usertalkpage.setEditSummary(editSummary); usertalkpage.setChangeTags(Twinkle.changeTags); usertalkpage.setCreateOption('recreate'); @@ -980,6 +1030,37 @@ Twinkle.xfd.callbacks = { }); } }, + generateUserTalkNoticeWikitext: function(params) { + // For grep: Afd notice, Mfd notice, Tfd notice, Cfd notice, Ffd notice, Rfd notice + let notifytext = '\n{{subst:' + params.venue + ' notice'; + const templateNamespace = 10; + // Venue-specific parameters + switch (params.venue) { + case 'afd': + notifytext += params.outcome !== 'deletion' ? '|outcome=' + params.outcome : ''; + notifytext += params.afdtarget ? '|target=' + params.afdtarget : ''; + // Tell the template to add " (Xnd nomination)" to the XFD title, if needed. + // The (HTML space character) is needed to overcome MediaWiki's parameter auto-trim. + notifytext += params.numbering !== '' ? '|order= ' + params.numbering : ''; + break; + case 'mfd': + // tell the template to add " (Xnd nomination)" to the XFD title, if needed + notifytext += params.numbering !== '' ? '|order= ' + params.numbering : ''; + break; + case 'tfd': + if (params.xfdcat === 'tfm') { + notifytext = '\n{{subst:Tfm notice|2=' + params.tfdtarget; + } + break; + case 'cfd': + notifytext += '|action=' + params.action + (mw.config.get('wgNamespaceNumber') === templateNamespace ? '|stub=yes' : ''); + break; + default: // ffd, rfd + break; + } + notifytext += '|1=' + Morebits.pageNameNorm + '}} ~~~~'; + return notifytext; + }, addToLog: function(params, initialContrib) { if (!Twinkle.getPref('logXfdNominations') || Twinkle.getPref('noLogOnXfdNomination').includes(params.venue)) { return; @@ -1166,6 +1247,7 @@ Twinkle.xfd.callbacks = { wikipedia_page.setFollowRedirect(true); wikipedia_page.setCallbackParameters(params); wikipedia_page.load(Twinkle.xfd.callbacks.afd.todaysList); + // Notification to first contributor if (params.notifycreator) { const thispage = new Morebits.wiki.Page(mw.config.get('wgPageName')); @@ -1179,11 +1261,20 @@ Twinkle.xfd.callbacks = { Twinkle.xfd.callbacks.addToLog(params, null); } - params.tagText = (params.noinclude ? '{{' : '{{') + (params.number === '' ? 'subst:afd|help=off' : 'subst:afdx|' + - params.number + '|help=off') + (params.noinclude ? '}}\n' : '}}\n'); + // Add AFD tag to article + params.tagText = Twinkle.xfd.callbacks.afd.generateArticleTagWikitext( + params.noinclude, params.outcome, params.afdtarget, params.number + ); + + // If the selected outcome is merge, add {{Merge from}} to the target page + if (params.outcome === 'merging' && params.afdtarget) { + wikipedia_page = new Morebits.wiki.Page(params.afdtarget, 'Tagging the target page with {{Merge from}}'); + wikipedia_page.setCallbackParameters(params); + wikipedia_page.load(Twinkle.xfd.callbacks.afd.tagTargetPageWithMergeFromTag); + } if (pageobj.canEdit()) { - // Remove some tags that should always be removed on AfD. + // Remove some tags that should always be removed on AfD. text = text.replace(/\{\{\s*(dated prod|dated prod blp|Prod blp\/dated|Proposed deletion\/dated|prod2|Proposed deletion endorsed|Userspace draft)\s*(\|(?:\{\{[^{}]*\}\}|[^{}])*)?\}\}\s*/ig, ''); // Then, test if there are speedy deletion-related templates on the article. const textNoSd = text.replace(/\{\{\s*(db(-\w*)?|delete|(?:hang|hold)[- ]?on)\s*(\|(?:\{\{[^{}]*\}\}|[^{}])*)?\}\}\s*/ig, ''); @@ -1204,6 +1295,47 @@ Twinkle.xfd.callbacks = { Twinkle.xfd.callbacks.autoEditRequest(pageobj, params); } }, + tagTargetPageWithMergeFromTag: function(pageobj) { + const statelem = pageobj.getStatusElement(); + if (!pageobj.exists()) { + statelem.warn('Failed. Target page not found.'); + return; + } else if (!pageobj.canEdit()) { + statelem.warn('Failed. Target page is protected from editing.'); + return; + } + + const params = pageobj.getCallbackParameters(); + const tag = `{{Merge from |1=${Morebits.pageNameNorm} |target=${params.afdtarget} |afd=${Morebits.pageNameNorm + params.numbering} |date ={{subst:CURRENTMONTHNAME}} {{subst:CURRENTYEAR}} }}`; + + const wikipage = new Morebits.wikitext.Page(pageobj.getPageText()); + const text = wikipage.insertAfterTemplates(tag, Twinkle.hatnoteRegex).getText(); + pageobj.setPageText(text); + + pageobj.setEditSummary('Nominated for merging; see [[:' + params.discussionpage + ']].'); + pageobj.setCreateOption('nocreate'); + pageobj.save(); + }, + generateArticleTagWikitext: function(noinclude, outcome, afdtarget, number) { + let noIncludeStart = ''; + let noIncludeEnd = ''; + if (noinclude) { + noIncludeStart = ''; + noIncludeEnd = ''; + } + + let templateAndParams = ''; + const outcomeParam = outcome !== 'deletion' ? '|outcome=' + outcome : ''; + const targetParam = afdtarget ? '|target=' + afdtarget : ''; + const isFirstNomination = number === ''; + if (isFirstNomination) { + templateAndParams = 'subst:afd|help=off' + outcomeParam + targetParam; + } else { + templateAndParams = 'subst:afdx|' + number + '|help=off' + outcomeParam + targetParam; + } + + return noIncludeStart + '{{' + templateAndParams + '}}' + noIncludeEnd + '\n'; + }, discussionPage: function(pageobj) { const params = pageobj.getCallbackParameters(); diff --git a/tests/twinklexfd.test.js b/tests/twinklexfd.test.js index c895b249d..aea3fe692 100644 --- a/tests/twinklexfd.test.js +++ b/tests/twinklexfd.test.js @@ -109,4 +109,181 @@ describe('modules/twinklexfd', () => { expect(Twinkle.xfd.insertRMTR(pageWikitext, wikitextToInsert)).toBe(expected); }); }); + + describe('generateArticleTagWikitext', () => { + test('deletion, 1st nomination', () => { + const noinclude = false; + const outcome = 'deletion'; + const afdtarget = ''; + const number = ''; + const expected = '{{subst:afd|help=off}}\n'; + expect(Twinkle.xfd.callbacks.afd.generateArticleTagWikitext(noinclude, outcome, afdtarget, number)).toBe(expected); + }); + test('deletion, 1st nomination, noinclude', () => { + const noinclude = true; + const outcome = 'deletion'; + const afdtarget = ''; + const number = ''; + const expected = '{{subst:afd|help=off}}\n'; + expect(Twinkle.xfd.callbacks.afd.generateArticleTagWikitext(noinclude, outcome, afdtarget, number)).toBe(expected); + }); + test('deletion, nth nomination', () => { + const noinclude = false; + const outcome = 'deletion'; + const afdtarget = ''; + const number = '24th'; + const expected = '{{subst:afdx|24th|help=off}}\n'; + expect(Twinkle.xfd.callbacks.afd.generateArticleTagWikitext(noinclude, outcome, afdtarget, number)).toBe(expected); + }); + test('merging, 1st nomination, blank target', () => { + const noinclude = false; + const outcome = 'merging'; + const afdtarget = ''; + const number = ''; + const expected = '{{subst:afd|help=off|outcome=merging}}\n'; + expect(Twinkle.xfd.callbacks.afd.generateArticleTagWikitext(noinclude, outcome, afdtarget, number)).toBe(expected); + }); + test('merging, 1st nomination, target specified', () => { + const noinclude = false; + const outcome = 'merging'; + const afdtarget = 'TargetPage'; + const number = ''; + const expected = '{{subst:afd|help=off|outcome=merging|target=TargetPage}}\n'; + expect(Twinkle.xfd.callbacks.afd.generateArticleTagWikitext(noinclude, outcome, afdtarget, number)).toBe(expected); + }); + test('merging, nth nomination, target specified', () => { + const noinclude = false; + const outcome = 'merging'; + const afdtarget = 'TargetPage'; + const number = '4th'; + const expected = '{{subst:afdx|4th|help=off|outcome=merging|target=TargetPage}}\n'; + expect(Twinkle.xfd.callbacks.afd.generateArticleTagWikitext(noinclude, outcome, afdtarget, number)).toBe(expected); + }); + test('redirect, 1st nomination, blank target', () => { + const noinclude = false; + const outcome = 'redirecting'; + const afdtarget = ''; + const number = ''; + const expected = '{{subst:afd|help=off|outcome=redirecting}}\n'; + expect(Twinkle.xfd.callbacks.afd.generateArticleTagWikitext(noinclude, outcome, afdtarget, number)).toBe(expected); + }); + test('redirect, 1st nomination, target specified', () => { + const noinclude = false; + const outcome = 'redirecting'; + const afdtarget = 'TargetPage'; + const number = ''; + const expected = '{{subst:afd|help=off|outcome=redirecting|target=TargetPage}}\n'; + expect(Twinkle.xfd.callbacks.afd.generateArticleTagWikitext(noinclude, outcome, afdtarget, number)).toBe(expected); + }); + test('draftify, 1st nomination', () => { + const noinclude = false; + const outcome = 'draftification'; + const afdtarget = ''; + const number = ''; + const expected = '{{subst:afd|help=off|outcome=draftification}}\n'; + expect(Twinkle.xfd.callbacks.afd.generateArticleTagWikitext(noinclude, outcome, afdtarget, number)).toBe(expected); + }); + }); + + describe('generateUserTalkNoticeWikitext', () => { + test('afd, deletion, 1st nomination', () => { + const params = {}; + params.venue = 'afd'; + params.outcome = 'deletion'; + params.afdtarget = ''; + params.numbering = ''; + params.xfdcat = '?'; + params.tfdtarget = undefined; + params.action = undefined; + mw.config.set('wgNamespaceNumber', 0); + Morebits.pageNameNorm = 'NovemTest110'; + const expected = '\n{{subst:afd notice|1=NovemTest110}} ~~~~'; + expect(Twinkle.xfd.callbacks.generateUserTalkNoticeWikitext(params)).toBe(expected); + }); + test('afd, deletion, nth nomination', () => { + const params = {}; + params.venue = 'afd'; + params.outcome = 'deletion'; + params.afdtarget = ''; + params.numbering = ' (4th nomination)'; + params.xfdcat = '?'; + params.tfdtarget = undefined; + params.action = undefined; + mw.config.set('wgNamespaceNumber', 0); + Morebits.pageNameNorm = 'NovemTest110'; + const expected = '\n{{subst:afd notice|order= (4th nomination)|1=NovemTest110}} ~~~~'; + expect(Twinkle.xfd.callbacks.generateUserTalkNoticeWikitext(params)).toBe(expected); + }); + test('afd, merging, 1st nomination, blank target', () => { + const params = {}; + params.venue = 'afd'; + params.outcome = 'merging'; + params.afdtarget = ''; + params.numbering = ''; + params.xfdcat = '?'; + params.tfdtarget = undefined; + params.action = undefined; + mw.config.set('wgNamespaceNumber', 0); + Morebits.pageNameNorm = 'NovemTest110'; + const expected = '\n{{subst:afd notice|outcome=merging|1=NovemTest110}} ~~~~'; + expect(Twinkle.xfd.callbacks.generateUserTalkNoticeWikitext(params)).toBe(expected); + }); + test('afd, merging, 1st nomination, with target', () => { + const params = {}; + params.venue = 'afd'; + params.outcome = 'merging'; + params.afdtarget = 'Testing 123'; + params.numbering = ''; + params.xfdcat = '?'; + params.tfdtarget = undefined; + params.action = undefined; + mw.config.set('wgNamespaceNumber', 0); + Morebits.pageNameNorm = 'NovemTest110'; + const expected = '\n{{subst:afd notice|outcome=merging|target=Testing 123|1=NovemTest110}} ~~~~'; + expect(Twinkle.xfd.callbacks.generateUserTalkNoticeWikitext(params)).toBe(expected); + }); + test('afd, redirecting, 1st nomination, blank target', () => { + const params = {}; + params.venue = 'afd'; + params.outcome = 'redirecting'; + params.afdtarget = ''; + params.numbering = ''; + params.xfdcat = '?'; + params.tfdtarget = undefined; + params.action = undefined; + mw.config.set('wgNamespaceNumber', 0); + Morebits.pageNameNorm = 'NovemTest110'; + const expected = '\n{{subst:afd notice|outcome=redirecting|1=NovemTest110}} ~~~~'; + expect(Twinkle.xfd.callbacks.generateUserTalkNoticeWikitext(params)).toBe(expected); + }); + test('afd, redirecting, 1st nomination, with target', () => { + const params = {}; + params.venue = 'afd'; + params.outcome = 'redirecting'; + params.afdtarget = 'Testing 123'; + params.numbering = ''; + params.xfdcat = '?'; + params.tfdtarget = undefined; + params.action = undefined; + mw.config.set('wgNamespaceNumber', 0); + Morebits.pageNameNorm = 'NovemTest110'; + const expected = '\n{{subst:afd notice|outcome=redirecting|target=Testing 123|1=NovemTest110}} ~~~~'; + expect(Twinkle.xfd.callbacks.generateUserTalkNoticeWikitext(params)).toBe(expected); + }); + test('afd, draftification, 1st nomination', () => { + const params = {}; + params.venue = 'afd'; + params.outcome = 'draftification'; + params.afdtarget = ''; + params.numbering = ''; + params.xfdcat = '?'; + params.tfdtarget = undefined; + params.action = undefined; + mw.config.set('wgNamespaceNumber', 0); + Morebits.pageNameNorm = 'NovemTest110'; + const expected = '\n{{subst:afd notice|outcome=draftification|1=NovemTest110}} ~~~~'; + expect(Twinkle.xfd.callbacks.generateUserTalkNoticeWikitext(params)).toBe(expected); + }); + // TODO: add tests for tfd, cfd, mfd, ffd, rfd + }); });