From 97acb8963e514006def49f5333a1654db23117f8 Mon Sep 17 00:00:00 2001 From: MusikAnimal Date: Wed, 11 Nov 2015 02:49:15 -0500 Subject: [PATCH] speedy: allow admins to delete under multiple criteria, generating deletion summaries from parsing the template that would have been placed by a non-admin twinkle: delete talk pages by default --- modules/backup | 27 +++ modules/twinklespeedy.js | 378 ++++++++++++++++++++------------------- twinkle.js | 2 +- 3 files changed, 226 insertions(+), 181 deletions(-) create mode 100644 modules/backup diff --git a/modules/backup b/modules/backup new file mode 100644 index 000000000..5c36bc3ec --- /dev/null +++ b/modules/backup @@ -0,0 +1,27 @@ + // var criteria = [], extendedRationales = []; + // $.each(params.normalizeds, function(index, norm) { + // criteria.push("[[WP:CSD#" + norm.toUpperCase() + "|" + norm.toUpperCase() + "]]"); + // var parameters = params.templateParams[index] || []; + // for (var param in parameters) { + // if (typeof parameters[param] === 'string') { + // var paramStr; + // if (param === 'article' || param === 'source') { + // paramStr = "[[" + parameters[param] + "]]"; + // } else { + // paramStr = parameters[param]; + // } + // extendedRationales.push(paramStr); + // } + // } + // }); + + // var presetReason; + // if (params.normalizeds.length > 1) { + // presetReason = "Multiple reasons: speedy deletion criteria " + criteria.join(", "); + // } else { + // presetReason = criteria.join(",") + ": " + Twinkle.speedy.rationaleData[ params.values[0] ].summary; + // } + + // if (extendedRationales.length) { + // presetReason += ": " + extendedRationales.join(", "); + // } \ No newline at end of file diff --git a/modules/twinklespeedy.js b/modules/twinklespeedy.js index 541f73dfc..133d16704 100644 --- a/modules/twinklespeedy.js +++ b/modules/twinklespeedy.js @@ -40,22 +40,28 @@ Twinkle.speedy.dialog = null; // The speedy criteria list can be in one of several modes Twinkle.speedy.mode = { - sysopSubmit: 1, // radio buttons, no subgroups, submit when "Submit" button is clicked + sysopSingleSubmit: 1, // radio buttons, no subgroups, submit when "Submit" button is clicked sysopRadioClick: 2, // radio buttons, no subgroups, submit when a radio button is clicked - userMultipleSubmit: 3, // check boxes, subgroups, "Submit" button already pressent - userMultipleRadioClick: 4, // check boxes, subgroups, need to add a "Submit" button - userSingleSubmit: 5, // radio buttons, subgroups, submit when "Submit" button is clicked - userSingleRadioClick: 6, // radio buttons, subgroups, submit when a radio button is clicked + sysopMultipleSubmit: 3, // check boxes, subgroups, "Submit" button already present + sysopMultipleRadioClick: 4, // check boxes, subgroups, need to add a "Submit" button + userMultipleSubmit: 5, // check boxes, subgroups, "Submit" button already pressent + userMultipleRadioClick: 6, // check boxes, subgroups, need to add a "Submit" button + userSingleSubmit: 7, // radio buttons, subgroups, submit when "Submit" button is clicked + userSingleRadioClick: 8, // radio buttons, subgroups, submit when a radio button is clicked // are we in "delete page" mode? // (sysops can access both "delete page" [sysop] and "tag page only" [user] modes) isSysop: function twinklespeedyModeIsSysop(mode) { - return mode === Twinkle.speedy.mode.sysopSubmit || - mode === Twinkle.speedy.mode.sysopRadioClick; + return mode === Twinkle.speedy.mode.sysopSingleSubmit || + mode === Twinkle.speedy.mode.sysopMultipleSubmit || + mode === Twinkle.speedy.mode.sysopRadioClick || + mode === Twinkle.speedy.mode.sysopMultipleRadioClick; }, // do we have a "Submit" button once the form is created? hasSubmitButton: function twinklespeedyModeHasSubmitButton(mode) { - return mode === Twinkle.speedy.mode.sysopSubmit || + return mode === Twinkle.speedy.mode.sysopSingleSubmit || + mode === Twinkle.speedy.mode.sysopMultipleSubmit || + mode === Twinkle.speedy.mode.sysopMultipleRadioClick || mode === Twinkle.speedy.mode.userMultipleSubmit || mode === Twinkle.speedy.mode.userMultipleRadioClick || mode === Twinkle.speedy.mode.userSingleSubmit; @@ -63,12 +69,10 @@ Twinkle.speedy.mode = { // is db-multiple the outcome here? isMultiple: function twinklespeedyModeIsMultiple(mode) { return mode === Twinkle.speedy.mode.userMultipleSubmit || - mode === Twinkle.speedy.mode.userMultipleRadioClick; + mode === Twinkle.speedy.mode.sysopMultipleSubmit || + mode === Twinkle.speedy.mode.userMultipleRadioClick || + mode === Twinkle.speedy.mode.sysopMultipleRadioClick; }, - // do we want subgroups? (if not we have to use prompt()) - wantSubgroups: function twinklespeedyModeWantSubgroups(mode) { - return !Twinkle.speedy.mode.isSysop(mode); - } }; // Prepares the speedy deletion dialog and displays it @@ -103,6 +107,9 @@ Twinkle.speedy.initDialog = function twinklespeedyInitDialog(callbackfunc) { // enable/disable redirects checkbox cForm.redirects.disabled = cChecked; cForm.redirects.checked = !cChecked; + // enable/disable delete multiple + cForm.delmultiple.disabled = cChecked; + cForm.delmultiple.checked = false; // enable/disable notify checkbox cForm.notify.disabled = !cChecked; @@ -153,6 +160,21 @@ Twinkle.speedy.initDialog = function twinklespeedyInitDialog(callbackfunc) { } ] } ); + form.append( { + type: 'checkbox', + list: [ + { + label: 'Delete under multiple criteria', + value: 'delmultiple', + name: 'delmultiple', + tooltip: "When selected, you can select several criteria that apply to the page. For example, G11 and A7 are a common combination for articles.", + event: function( event ) { + Twinkle.speedy.callback.modeChanged( event.target.form ); + event.stopPropagation(); + } + } + ] + } ); form.append( { type: 'header', label: 'Tag-related options' } ); } @@ -205,6 +227,19 @@ Twinkle.speedy.initDialog = function twinklespeedyInitDialog(callbackfunc) { dialog.display(); Twinkle.speedy.callback.modeChanged( result ); + + // if sysop, check if CSD is already on the page and fill in custom rationale + if (Morebits.userIsInGroup('sysop') && $("#delete-reason").length) { + var customOption = $("input[name=csd][value=reason]")[0]; + + if (Twinkle.getPref('speedySelectionStyle') !== 'radioClick') { + // force listeners to re-init + customOption.click(); + customOption.parentNode.appendChild(customOption.subgroup); + } + + customOption.subgroup.querySelector('input').value = decodeURIComponent($("#delete-reason").text()).replace(/\+/g, ' '); + } }; Twinkle.speedy.callback.modeChanged = function twinklespeedyCallbackModeChanged(form) { @@ -213,7 +248,11 @@ Twinkle.speedy.callback.modeChanged = function twinklespeedyCallbackModeChanged( // first figure out what mode we're in var mode = Twinkle.speedy.mode.userSingleSubmit; if (form.tag_only && !form.tag_only.checked) { - mode = Twinkle.speedy.mode.sysopSubmit; + if (form.delmultiple.checked) { + mode = Twinkle.speedy.mode.sysopMultipleSubmit; + } else { + mode = Twinkle.speedy.mode.sysopSingleSubmit; + } } else { if (form.multiple.checked) { mode = Twinkle.speedy.mode.userMultipleSubmit; @@ -230,7 +269,9 @@ Twinkle.speedy.callback.modeChanged = function twinklespeedyCallbackModeChanged( name: 'work_area' } ); - if (mode === Twinkle.speedy.mode.userMultipleRadioClick) { + if (mode === Twinkle.speedy.mode.userMultipleRadioClick || mode === Twinkle.speedy.mode.sysopMultipleRadioClick) { + var evaluateType = Twinkle.speedy.mode.isSysop(mode) ? 'evaluateSysop' : 'evaluateUser'; + work_area.append( { type: 'div', label: 'When finished choosing criteria, click:' @@ -240,7 +281,7 @@ Twinkle.speedy.callback.modeChanged = function twinklespeedyCallbackModeChanged( name: 'submit-multiple', label: 'Submit Query', event: function( event ) { - Twinkle.speedy.callback.evaluateUser( event ); + Twinkle.speedy.callback[evaluateType]( event ); event.stopPropagation(); } } ); @@ -248,6 +289,11 @@ Twinkle.speedy.callback.modeChanged = function twinklespeedyCallbackModeChanged( var radioOrCheckbox = (Twinkle.speedy.mode.isMultiple(mode) ? 'checkbox' : 'radio'); + if (Twinkle.speedy.mode.isSysop(mode) && !Twinkle.speedy.mode.isMultiple(mode)) { + work_area.append( { type: 'header', label: 'Custom rationale' } ); + work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.customRationale, mode) } ); + } + if (namespace % 2 === 1 && namespace !== 3) { // show db-talk on talk pages, but not user talk pages work_area.append( { type: 'header', label: 'Talk pages' } ); @@ -298,8 +344,13 @@ Twinkle.speedy.callback.modeChanged = function twinklespeedyCallbackModeChanged( break; } + // custom rationale lives under general criteria when tagging + var generalCriteria = Twinkle.speedy.generalList; + if(!Twinkle.speedy.mode.isSysop(mode)) { + generalCriteria = Twinkle.speedy.customRationale.concat(generalCriteria); + } work_area.append( { type: 'header', label: 'General criteria' } ); - work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.generalList, mode) }); + work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(generalCriteria, mode) }); work_area.append( { type: 'header', label: 'Redirects' } ); work_area.append( { type: radioOrCheckbox, name: 'csd', list: Twinkle.speedy.generateCsdList(Twinkle.speedy.redirectList, mode) } ); @@ -312,7 +363,6 @@ Twinkle.speedy.generateCsdList = function twinklespeedyGenerateCsdList(list, mod // mode switches var isSysop = Twinkle.speedy.mode.isSysop(mode); var multiple = Twinkle.speedy.mode.isMultiple(mode); - var wantSubgroups = Twinkle.speedy.mode.wantSubgroups(mode); var hasSubmitButton = Twinkle.speedy.mode.hasSubmitButton(mode); var openSubgroupHandler = function(e) { @@ -323,17 +373,14 @@ Twinkle.speedy.generateCsdList = function twinklespeedyGenerateCsdList(list, mod e.stopPropagation(); }; var submitSubgroupHandler = function(e) { - Twinkle.speedy.callback.evaluateUser(e); + var evaluateType = Twinkle.speedy.mode.isSysop(mode) ? 'evaluateSysop' : 'evaluateUser'; + Twinkle.speedy.callback[evaluateType](e); e.stopPropagation(); }; return $.map(list, function(critElement) { var criterion = $.extend({}, critElement); - if (!wantSubgroups) { - criterion.subgroup = null; - } - if (multiple) { if (criterion.hideWhenMultiple) { return null; @@ -392,6 +439,21 @@ Twinkle.speedy.generateCsdList = function twinklespeedyGenerateCsdList(list, mod }); }; +Twinkle.speedy.customRationale = [ + { + label: 'Custom rationale' + (Morebits.userIsInGroup('sysop') ? ' (custom deletion reason)' : ' using {{db}} template'), + value: 'reason', + tooltip: '{{db}} is short for "delete because". At least one of the other deletion criteria must still apply to the page, and you must make mention of this in your rationale. This is not a "catch-all" for when you can\'t find any criteria that fit.', + subgroup: { + name: 'reason_1', + type: 'input', + label: 'Rationale: ', + size: 60 + }, + hideWhenMultiple: true + } +]; + Twinkle.speedy.talkList = [ { label: 'G8: Talk pages with no corresponding subject page', @@ -698,19 +760,6 @@ Twinkle.speedy.portalList = [ ]; Twinkle.speedy.generalList = [ - { - label: 'Custom rationale' + (Morebits.userIsInGroup('sysop') ? ' (custom deletion reason)' : ' using {{db}} template'), - value: 'reason', - tooltip: '{{db}} is short for "delete because". At least one of the other deletion criteria must still apply to the page, and you must make mention of this in your rationale. This is not a "catch-all" for when you can\'t find any criteria that fit.', - subgroup: { - name: 'reason_1', - type: 'input', - label: 'Rationale: ', - size: 60 - }, - hideWhenMultiple: true, - hideSubgroupWhenSysop: true - }, { label: 'G1: Patent nonsense. Pages consisting purely of incoherent text or gibberish with no meaningful content or history.', value: 'nonsense', @@ -998,126 +1047,96 @@ Twinkle.speedy.normalizeHash = { 'emptyportal': 'p2' }; -// keep this synched with [[MediaWiki:Deletereason-dropdown]] -Twinkle.speedy.reasonHash = { - 'reason': '', -// General - 'nonsense': '[[WP:PN|Patent nonsense]], meaningless, or incomprehensible', - 'test': 'Test page', - 'vandalism': '[[WP:Vandalism|Vandalism]]', - 'hoax': 'Blatant [[WP:Do not create hoaxes|hoax]]', - 'repost': 'Recreation of a page that was [[WP:DEL|deleted]] per a [[WP:XFD|deletion discussion]]', - 'banned': 'Creation by a [[WP:BLOCK|blocked]] or [[WP:BAN|banned]] user in violation of block or ban', - 'histmerge': 'Temporary deletion in order to merge page histories', - 'move': 'Making way for a non-controversial move', - 'xfd': 'Deleting page per result of [[WP:XfD|deletion discussion]]', - 'disambig': 'Unnecessary disambiguation page', - 'movedab': 'Redirect to [[WP:MALPLACED|malplaced disambiguation page]]', - 'copypaste': '[[WP:CPMV|Copy-and-paste]] page move', - 'g6': 'Housekeeping and routine (non-controversial) cleanup', - 'author': 'One author who has requested deletion or blanked the page', - 'g8': 'Page dependent on a deleted or nonexistent page', - 'talk': '[[Help:Talk page|Talk page]] of a deleted or nonexistent page', - 'subpage': '[[WP:Subpages|Subpage]] of a deleted or nonexistent page', - 'redirnone': '[[Wikipedia:Redirect|redirect]] to a deleted or nonexistent page', - 'templatecat': 'Populated by deleted or retargeted templates', - 'imagepage': 'File description page for a file that does not exist', - 'attack': '[[WP:ATP|Attack page]] or negative unsourced [[WP:BLP|BLP]]', - 'negublp': 'Negative unsourced [[WP:BLP|BLP]]', - 'spam': 'Unambiguous [[WP:NOTADVERTISING|advertising]] or promotion', - 'copyvio': 'Unambiguous [[WP:CV|copyright infringement]]', - 'afc': 'Abandoned [[WP:AFC|Article for creation]] – to retrieve it, see [[WP:REFUND/G13]]', -// Articles - 'nocontext': 'Short article without enough context to identify the subject', - 'foreign': 'Article in a foreign language that exists on another project', - 'nocontent': 'Article that has no meaningful, substantive content', - 'transwiki': 'Article that has been transwikied to another project', - 'a7': 'No credible indication of importance (individuals, animals, organizations, web content, events)', - 'person' : 'No credible indication of importance (real person)', - 'web': 'No credible indication of importance (web content)', - 'corp': 'No credible indication of importance (organization)', - 'club': 'No credible indication of importance (organization)', - 'band': 'No credible indication of importance (band/musician)', - 'animal': 'No credible indication of importance (individual animal)', - 'event': 'No credible indication of importance (event)', - 'a9': 'Music recording by redlinked artist and no indication of importance or significance', - 'a10': 'Recently created article that duplicates an existing topic', - 'madeup': 'Made up by article creator or an associate, and no indication of importance/significance', -// Images and media -// Keep synched with [[MediaWiki:Filedelete-reason-dropdown]] - 'redundantimage': 'Redundant copy of non-Commons file in the same file format', - 'noimage': 'Corrupt or empty file', - 'fpcfail': 'Unneeded file description page for a file on Commons', - 'noncom': 'Invalid licence, eg. "for non-commercial use only" or "for Wikipedia use only"', - 'unksource': 'Lack of licensing information', - 'unfree': 'Unused non-free media', - 'norat': 'Non-free file with no [[WP:RAT|non-free use rationale]]', - 'badfairuse': 'Violates [[WP:F|non-free use policy]]', - 'nowcommons': 'Media file available on Commons', - 'imgcopyvio': 'Unambiguous [[WP:COPYVIO|copyright violation]]', - 'badfiletype': 'Useless media file (not an image, audio or video)', - 'nopermission': 'No evidence of permission', -// Categories - 'catempty': 'Empty category', -// User pages - 'userreq': 'User request to delete page in own userspace', - 'nouser': 'Userpage or subpage of a nonexistent user', - 'gallery': '[[WP:NFC|Non-free]] [[Help:Gallery|gallery]]', - 'notwebhost': '[[WP:NOTWEBHOST|Misuse of Wikipedia as a web host]]', -// Templates - 'policy': 'Template that unambiguously misrepresents established policy', - 'duplicatetemplate': 'Unused, redundant template', -// Portals - 'p1': '[[WP:P|Portal]] page that would be subject to speedy deletion as an article', - 'emptyportal': '[[WP:P|Portal]] without a substantial topic base', -// Redirects - 'rediruser': 'Cross-[[WP:NS|namespace]] [[WP:R|redirect]] from mainspace', - 'redirtypo': 'Recently created, implausible [[WP:R|redirect]]' -}; - Twinkle.speedy.callbacks = { - sysop: { - main: function( params ) { - var thispage; + getTemplateCodeAndParams: function(params) { + var code, parameters, i; + if (params.normalizeds.length > 1) { + code = "{{db-multiple"; + params.utparams = {}; + $.each(params.normalizeds, function(index, norm) { + code += "|" + norm.toUpperCase(); + parameters = params.templateParams[index] || []; + for (var i in parameters) { + if (typeof parameters[i] === 'string' && !parseInt(i, 10)) { // skip numeric parameters - {{db-multiple}} doesn't understand them + code += "|" + i + "=" + parameters[i]; + } + } + $.extend(params.utparams, Twinkle.speedy.getUserTalkParameters(norm, parameters)); + }); + code += "}}"; + } else { + parameters = params.templateParams[0] || []; + code = "{{db-" + params.values[0]; + for (i in parameters) { + if (typeof parameters[i] === 'string') { + code += "|" + i + "=" + parameters[i]; + } + } + if (params.usertalk) { + code += "|help=off"; + } + code += "}}"; + params.utparams = Twinkle.speedy.getUserTalkParameters(params.normalizeds[0], parameters); + } - Morebits.wiki.addCheckpoint(); // prevent actionCompleted from kicking in until user interaction is done + return [code, params.utparams]; + }, - // look up initial contributor. If prompting user for deletion reason, just display a link. - // Otherwise open the talk page directly - if( params.openusertalk ) { - thispage = new Morebits.wiki.page( mw.config.get('wgPageName') ); // a necessary evil, in order to clear incorrect status text - thispage.setCallbackParameters( params ); - thispage.lookupCreator( Twinkle.speedy.callbacks.sysop.openUserTalkPage ); - } + parseWikitext: function(wikitext, callback) { + var query = { + action: "parse", + prop: "text", + pst: "true", + text: wikitext, + title: mw.config.get("wgPageName") + }; + + var statusIndicator = new Morebits.status( 'Building deletion summary' ); + var api = new Morebits.wiki.api( 'Fetching parsing deletion template', query, function(apiObj) { + statusIndicator.info( 'complete' ); + callback(apiObj); + }, statusIndicator); + api.post(); + }, - // delete page + sysop: { + main: function( params ) { var reason; - thispage = new Morebits.wiki.page( mw.config.get('wgPageName'), "Deleting page" ); - if (params.normalized === 'db') { + + if (!params.normalizeds.length && params.normalizeds[0] === 'db') { reason = prompt("Enter the deletion summary to use, which will be entered into the deletion log:", ""); + Twinkle.speedy.callbacks.sysop.deletePage( reason, params ); } else { - var presetReason = "[[WP:CSD#" + params.normalized.toUpperCase() + "|" + params.normalized.toUpperCase() + "]]: " + params.reason; - if (Twinkle.getPref("promptForSpeedyDeletionSummary").indexOf(params.normalized) !== -1) { - reason = prompt("Enter the deletion summary to use, or press OK to accept the automatically generated one.", presetReason); - } else { - reason = presetReason; - } + var code = Twinkle.speedy.callbacks.getTemplateCodeAndParams(params)[0]; + Twinkle.speedy.callbacks.parseWikitext(code, function(apiobj) { + reason = decodeURIComponent($(apiobj.getXML().querySelector('text').childNodes[0].nodeValue).find('#delete-reason').text()).replace(/\+/g, ' '); + if (params.promptForSummary) { + reason = prompt("Enter the deletion summary to use, or press OK to accept the automatically generated one.", reason); + } + Twinkle.speedy.callbacks.sysop.deletePage( reason, params ); + }); } + }, + deletePage: function( reason, params ) { + var thispage = new Morebits.wiki.page( mw.config.get('wgPageName'), "Deleting page" ); + if (reason === null) { - Morebits.status.error("Asking for reason", "User cancelled"); - Morebits.wiki.removeCheckpoint(); - return; + return Morebits.status.error("Asking for reason", "User cancelled"); } else if (!reason || !reason.replace(/^\s*/, "").replace(/\s*$/, "")) { - Morebits.status.error("Asking for reason", "you didn't give one. I don't know... what with admins and their apathetic antics... I give up..."); - Morebits.wiki.removeCheckpoint(); - return; + return Morebits.status.error("Asking for reason", "you didn't give one. I don't know... what with admins and their apathetic antics... I give up..."); } thispage.setEditSummary( reason + Twinkle.getPref('deletionSummaryAd') ); thispage.deletePage(function() { thispage.getStatusElement().info("done"); Twinkle.speedy.callbacks.sysop.deleteTalk( params ); }); - Morebits.wiki.removeCheckpoint(); + + // look up initial contributor. If prompting user for deletion reason, just display a link. + // Otherwise open the talk page directly + if( params.openusertalk ) { + thispage.setCallbackParameters( params ); + thispage.lookupCreator( Twinkle.speedy.callbacks.sysop.openUserTalkPage ); + } }, deleteTalk: function( params ) { // delete talk page @@ -1295,35 +1314,11 @@ Twinkle.speedy.callbacks = { return; } - var code, parameters, i; - if (params.normalizeds.length > 1) { - code = "{{db-multiple"; - params.utparams = {}; - $.each(params.normalizeds, function(index, norm) { - code += "|" + norm.toUpperCase(); - parameters = params.templateParams[index] || []; - for (var i in parameters) { - if (typeof parameters[i] === 'string' && !parseInt(i, 10)) { // skip numeric parameters - {{db-multiple}} doesn't understand them - code += "|" + i + "=" + parameters[i]; - } - } - $.extend(params.utparams, Twinkle.speedy.getUserTalkParameters(norm, parameters)); - }); - code += "}}"; - } else { - parameters = params.templateParams[0] || []; - code = "{{db-" + params.values[0]; - for (i in parameters) { - if (typeof parameters[i] === 'string') { - code += "|" + i + "=" + parameters[i]; - } - } - if (params.usertalk) { - code += "|help=off"; - } - code += "}}"; - params.utparams = Twinkle.speedy.getUserTalkParameters(params.normalizeds[0], parameters); - } + // given the params, builds the template and also adds the user talk page parameters to the params that were passed in + // returns => [ wikitext, utparams] + var buildData = Twinkle.speedy.callbacks.getTemplateCodeAndParams(params), + code = buildData[0]; + params.utparams = buildData[1]; var thispage = new Morebits.wiki.page(mw.config.get('wgPageName')); // patrol the page, if reached from Special:NewPages @@ -1354,9 +1349,9 @@ Twinkle.speedy.callbacks = { editsummary = editsummary.substr(0, editsummary.length - 2); // remove trailing comma editsummary += ').'; } else if (params.normalizeds[0] === "db") { - editsummary = 'Requesting [[WP:CSD|speedy deletion]] with rationale \"' + parameters["1"] + '\".'; + editsummary = 'Requesting [[WP:CSD|speedy deletion]] with rationale \"' + params["1"] + '\".'; } else if (params.values[0] === "histmerge") { - editsummary = "Requesting history merge with [[" + parameters["1"] + "]] ([[WP:CSD#G6|CSD G6]])."; + editsummary = "Requesting history merge with [[" + params["1"] + "]] ([[WP:CSD#G6|CSD G6]])."; } else { editsummary = "Requesting speedy deletion ([[WP:CSD#" + params.normalizeds[0].toUpperCase() + "|CSD " + params.normalizeds[0].toUpperCase() + "]])."; } @@ -1800,26 +1795,49 @@ Twinkle.speedy.resolveCsdValues = function twinklespeedyResolveCsdValues(e) { Twinkle.speedy.callback.evaluateSysop = function twinklespeedyCallbackEvaluateSysop(e) { var form = (e.target.form ? e.target.form : e.target); + if (e.target.type === "checkbox" || e.target.type === "text" || + e.target.type === "select") { + return; + } + var tag_only = form.tag_only; if( tag_only && tag_only.checked ) { Twinkle.speedy.callback.evaluateUser(e); return; } - var value = Twinkle.speedy.resolveCsdValues(e)[0]; - if (!value) { + var values = Twinkle.speedy.resolveCsdValues(e); + if (!values) { return; } - var normalized = Twinkle.speedy.normalizeHash[ value ]; + + var normalizeds = values.map(function(value) { + return Twinkle.speedy.normalizeHash[ value ]; + }); + + // analyse each criterion to determine whether to watch the page, prompt for summary, or open user talk page + var watchPage, promptForSummary, openUserTalk; + normalizeds.forEach(function(norm) { + if (Twinkle.getPref("watchSpeedyPages").indexOf(norm) !== -1) { + watchPage = true; + } + if (Twinkle.getPref("promptForSpeedyDeletionSummary").indexOf(norm) !== -1) { + promptForSummary = true; + } + if (Twinkle.getPref('openUserTalkPageOnSpeedyDelete').indexOf(norm) !== -1) { + openUserTalk = true; + } + }); var params = { - value: value, - normalized: normalized, - watch: Twinkle.getPref('watchSpeedyPages').indexOf( normalized ) !== -1, - reason: Twinkle.speedy.reasonHash[ value ], - openusertalk: Twinkle.getPref('openUserTalkPageOnSpeedyDelete').indexOf( normalized ) !== -1, + values: values, + normalizeds: normalizeds, + watch: watchPage, + openusertalk: openUserTalk, deleteTalkPage: form.talkpage && form.talkpage.checked, - deleteRedirects: form.redirects.checked + deleteRedirects: form.redirects.checked, + promptForSummary: promptForSummary, + templateParams: Twinkle.speedy.getParameters( form, values ) }; Morebits.simpleWindow.setButtonsEnabled( false ); diff --git a/twinkle.js b/twinkle.js index dfdc7b1bd..e5abeaa7a 100644 --- a/twinkle.js +++ b/twinkle.js @@ -79,7 +79,7 @@ Twinkle.defaultConfig.twinkle = { welcomeUserOnSpeedyDeletionNotification: [ "db", "g1", "g2", "g3", "g4", "g6", "g10", "g11", "g12", "g13", "a1", "a2", "a3", "a5", "a7", "a9", "a10", "a11", "f1", "f2", "f3", "f7", "f9", "f10", "u3", "u5", "t2", "t3", "p1", "p2" ], promptForSpeedyDeletionSummary: [ "db", "g1", "g2", "g3", "g4", "g6", "g7", "g8", "g10", "g11", "g12", "a1", "a2", "a3", "a5", "a7", "a9", "a10", "a11", "f2", "f4", "f7", "f8", "f10", "u5", "t2", "t3", "p1", "p2" ], openUserTalkPageOnSpeedyDelete: [ "db", "g1", "g2", "g3", "g4", "g5", "g10", "g11", "g12", "a1", "a3", "a7", "a9", "a10", "a11", "f3", "f7", "f9", "u3", "u5", "t2", "p1" ], - deleteTalkPageOnDelete: false, + deleteTalkPageOnDelete: true, deleteRedirectsOnDelete: true, deleteSysopDefaultToTag: false, speedyWindowHeight: 500,