利用者:Dragoniez/Template Paster.js
表示
お知らせ: 保存した後、ブラウザのキャッシュをクリアしてページを再読み込みする必要があります。
多くの Windows や Linux のブラウザ
- Ctrl を押しながら F5 を押す。
Mac における Safari
Mac における Chrome や Firefox
- ⌘ Cmd と ⇧ Shift を押しながら R を押す。
詳細についてはWikipedia:キャッシュを消すをご覧ください。
/*************************************
* Template Paster (TP)
* Author: Dragoniez
* Version: 1.1
*************************************/
//<nowiki>
$(function(){
// Don't run the scipt if the page is a special page or an edit page
if (mw.config.get('wgNamespaceNumber') != -1 && mw.config.get("wgAction") != 'edit') {
// Load external scripts
mw.loader.load('jquery.ui.dialog');
// Add TP tab
$(mw.util.addPortletLink('p-cactions', '#', 'TP', 'tp', 'Template Paster'))
.click(function(e){
// Cancel event that redirects the user to the href destination
e.preventDefault();
// ----- CREATE DIALOG -----
//CSS for elements in dialog
var labelCSS = 'display: inline-block; width: 8ch;';
var missingCSS = 'display: inline-block; font-size: larger; width: 1.5ch; font-weight: bold; margin: 0; line-height: normal;';
var marginCSS = 'margin: 1em 0';
//Asterik mark in red for required entries
var rq = '<span style="color:red; font-size: larger">*</span>';
//Create the html contour (CO parts are added later in the code)
var modalHtml =
// <div class="tp-modal-dialog" title="Template Paster">
` <div class="tp-modal-header">` +
` <h2>ノート用テンプレートの添付</h2>` +
` </div>` +
` <div class="tp-modal-body" >` +
` <form>` +
` <div class="tp-select-div" style="${marginCSS}">` +
` <label for="tp-select-options" style="${labelCSS}">区分${rq}</label>` +
` <p class="tp-p tp-select-p" style="${missingCSS}"></p>` +
` <select class="tp-select" id="tp-select-options">` +
` <option selected disabled hidden>選択してください</option>` +
` <option>統合</option>` +
` <option>分割</option>` +
` </select>` +
` </div>` +
` <div class="tp-dynamic-div">` +
// modalSelDyna
` </div>` +
` </form>` +
` </div>`;
// </div>`
// Add the frame div to the page
$('body').append($('<div class="tp-modal-dialog" title="Template Paster" />'));
// Create html elements inside the div
$('.tp-modal-dialog').html(modalHtml);
// Show dialog
$('.tp-modal-dialog').dialog({
'minHeight': 50,
'width': 'auto',
'modal': true,
'position': { my: 'center', at: 'top+20%', of: window },
'buttons': [{
'text': '貼り付け',
// Event to trigger when the "貼り付け" button is hit
'click': function() {
// ----- BEFORE EDIT -----
// Variables
var $dialog = $(this);
var sel = $('.tp-select').find(':selected').text(); // Selection - 'Merge' or 'Split'
var srcGoal = '', srcGoalEn = '', srcGoalReverted = '', srcGoalRevertedEn = '';
if (sel === '統合') {
srcGoal = '元';
srcGoalEn = 'src';
srcGoalReverted = '先';
srcGoalRevertedEn = 'goal';
} else if (sel === '分割') {
srcGoal = '先';
srcGoalEn = 'goal';
srcGoalReverted = '元';
srcGoalRevertedEn = 'src';
}
var pagenames = []; // Store target page names
var rqPage = ''; // Required field
var optPages = []; // Optional fields
var dPage = ''; // Discussion page
// Check if the necessary fields are filled
if (trimA($(`#tp-${srcGoalRevertedEn}-input-1`).val()) === '') {
alert(`${sel}${srcGoalReverted}が入力されていません`); // 統合先・分割元
return;
} else {
rqPage = trimA($(`#tp-${srcGoalRevertedEn}-input-1`).val());
if (sel === '分割') {
pagenames.push(rqPage); // 分割元
}
}
// Check if at least one of the necessary and optional fields is filled
var notFilled = true;
var $val;
for (let i = 1; i <= 10; i++) {
// If ID is not found, exit for
if ($(`#tp-${srcGoalEn}-input-${i}`).length === 0) {
break;
}
// If any of the fields is filled, set notFilled = false and get the value in each field
$val = trimA($(`#tp-${srcGoalEn}-input-${i}`).val());
if ($val !== '') {
if (notFilled) {
notFilled = false;
}
if (isInArray($val, pagenames)) {
alert('重複入力があります\n\n' + $val);
return;
}
pagenames.push($val); // 統合元1-10 or 分割先1-10
optPages.push($val);
}
}
// Show error message and exit function if any of the necessary fields is NOT filled
if (notFilled) {
alert(`${sel}${srcGoal}が入力されていません`);
return;
}
// Push the values in the rest of the boxes into the array
if (sel === '統合') {
if (isInArray(rqPage, pagenames)) {
alert('重複入力があります\n\n' + rqPage);
return;
}
pagenames.push(rqPage); // 統合先
}
// Check if the discussion page field is filled
dPage = trimA($('#tp-disc-input').val());
if (dPage === '') {
alert(`議論場所が入力されていません`);
return;
} else {
pagenames.push(dPage); // 議論場所
}
// Check if the pages exist
var notFnd = false;
$('.tp-p').each(function(){
if ($(this).text() === '✗') {
notFnd = true;
}
});
// If the boxes include pages that don't exist, ask whether to proceed
if (notFnd) {
if (confirm('存在しないページ名が含まれています。このまま入力してよろしいですか?') === false ) {
return;
}
}
// ----- EDIT -----
/*********************************************************************************
* {{統合元ノート|統合提案がされたページ名|統合先の記事名}}
* {{統合先ノート|統合元の記事名1|統合元の記事名2...|d=統合提案がされたページ名}}
* {{分割元ノート|分割先の記事名1|分割先の記事名2...|d=分割提案がされたページ名}}
* {{分割先ノート|分割提案がされたノート名|分割元の記事名}}
***********************************************************************************/
var TP1 = `\n{{${sel}${srcGoalReverted}ノート|${optPages.join('|')}|d=${dPage}}}`;
var TP2 = `\n{{${sel}${srcGoal}ノート|${dPage}|${rqPage}}}`;
var cnt = 0;
var msg = '編集が完了しました';
var err = '以下のページは、エラーにより編集できませんでした';
var msgDone = '';
var TPcopy = sel === '統合' ? TP2 + TP1: TP1 + TP2;
var sig = ' ([[User:Dragoniez/Template Paster|Template Paster]])';
var editTar = [];
// Hide elements
$dialog.dialog({"buttons": []}); // Hide button
$('.tp-modal-body form').css('display','none'); // Hide form
$('.tp-modal-body').append($(`<p class="doing">編集中...</p>`)); // Show message
// Templates to paste (debugger)
//console.log(TP1 + '\n' + TP2);
// Edit the talk page of merge goal or split source
$.ajax({
url: mw.util.wikiScript('api'),
data: {
format: 'json',
action: 'edit',
title: ConvToTalk(rqPage),
section: 0,
summary: `{{[[Template:${sel}${srcGoalReverted}ノート|${sel}${srcGoalReverted}ノート]]}}${sig}`,
watchlist: 'watch',
appendtext: TP1,
token: mw.user.tokens.get('csrfToken')
},
dataType: 'json',
type: 'POST',
success: function(result) {
if(result && result.edit &&result.edit.result == 'Success' ) {// if edit was successful
editTar.push(ConvToTalk(rqPage)); // Get the page edited
} else if(result && result.error) { // if error occured
err += `<br><br>ページ名: ${ConvToTalk(rqPage)}<br>コード: ${result.error.code}<br>詳細: ${result.error.info}`;
} else { //if unknown error occurred
err += `<br><br>ページ名: ${ConvToTalk(rqPage)}<br>コード: N/A<br>詳細: Unknown error`;
}
// Edit the talk page(s) of merge source(s) or split goal(s)
for (let i = 0; i < optPages.length; i++) {
setTimeout(function(){ // Set a 0.1s dalay to get the right error details
$.ajax({
url: mw.util.wikiScript('api'),
data: {
format: 'json',
action: 'edit',
title: ConvToTalk(optPages[i]),
section: 0,
summary: `{{[[Template:${sel}${srcGoal}ノート|${sel}${srcGoal}ノート]]}}${sig}`,
watchlist: 'watch',
appendtext: TP2,
token: mw.user.tokens.get('csrfToken')
},
dataType: 'json',
type: 'POST',
success: function(result) {
cnt++;
if(result && result.edit &&result.edit.result == 'Success' ) {// if edit was successful
editTar.push(ConvToTalk(optPages[i])); // Get the page edited
} else if(result && result.error) { // if error occured
err += `<br><br>ページ名: ${ConvToTalk(optPages[i])}<br>コード: ${result.error.code}<br>詳細: ${result.error.info}`;
} else { //if unknown error occurred
err += `<br><br>ページ名: ${ConvToTalk(optPages[i])}<br>コード: N/A<br>詳細: Unknown error`;
}
// In the last iteration
if (cnt === optPages.length) {
// Ending message
if (err === '以下のページは、エラーにより編集できませんでした') {
msgDone = msg;
} else {
msgDone = msg + '<br><br>' + err +
'<br><br>手動入力用:<br><textarea disabled rows="2" style="width: 100%">' +
TPcopy + '</textarea>';
}
console.log(editTar);
$('.doing').remove(); // Remove '編集中...'
$('.tp-modal-body').append($(`<p>${msgDone}</p>`)); // Show message
$dialog.dialog({ // Show close button
'position': { my: 'center', at: 'top+20%', of: window },
'buttons': [{
'text': '閉じる',
'click': function(){
$(this).dialog('close');
if (isInArray(mw.config.get('wgPageName'), editTar)) { // Reload page
location.reload();
}
}
}]
});
}
}
});
}, 100);
}
}
});
// Function that checks if an element is already in an array
function isInArray (el, arr) {
if (arr.indexOf(el) !== -1) {
return true;
} else {
return false;
}
}
}
}]
});
//Reset dialog when closed
$('.tp-modal-dialog').on('dialogclose', function() {
$(this).remove();
});
// When selection is changed between 統合 and 分割
$('.tp-select').change(function(){
var sel = $(this).find(':selected').text();
// Reset content
$('.tp-dynamic-div').empty();
// Html for 'Add' button
var optNum = 1;
var btnDivSrc = '', btnDivGoal = '';
var btnDiv =
` <div class="tp-btn-div">` +
` <button type="button" class="addBtn">追加</button>` +
` </div>`;
// Variable substitution to insert the html into the right place
if (sel === '統合') {
btnDivSrc = btnDiv;
} else if (sel === '分割') {
btnDivGoal = btnDiv;
} else {
alert('エラーが発生しました。');
return;
}
// Html for the dynamic elements
var modalSelDyna =
` <div class="tp-src-div" style="${marginCSS}">` +
` <label for="tp-src-input-${optNum}" style="${labelCSS}">${sel}元${rq}</label>` +
` <p class="tp-p tp-src-p" id="tp-src-p-${optNum}" style="${missingCSS}"></p>` +
` <input class="tp-src-input" id="tp-src-input-${optNum}">` +
btnDivSrc +
` </div>` +
` <div class="tp-goal-div" style="${marginCSS}">` +
` <label for="tp-goal-input-${optNum}" style="${labelCSS}">${sel}先${rq}</label>` +
` <p class="tp-p tp-goal-p" id="tp-goal-p-${optNum}" style="${missingCSS}"></p>` +
` <input class="tp-goal-input" id="tp-goal-input-${optNum}">` +
btnDivGoal +
` </div>` +
` <div class="tp-disc-div" style="${marginCSS}">` +
` <label for="tp-disc-input" style="${labelCSS}">議論場所${rq}</label>` +
` <p class="tp-p" id="tp-disc-p" style="${missingCSS}"></p>` +
` <input id="tp-disc-input">` +
` </div>`;
// Show the dynamic elements
$('.tp-dynamic-div').html(modalSelDyna);
// Function to add optional inputboxes when addBtn is hit
$('.addBtn').click(function(){
// Html for the optional box
var srcGoal = '', srcGoalEn = '';
if (sel === '統合') {
srcGoal = '元';
srcGoalEn = 'src';
} else if (sel === '分割') {
srcGoal = '先';
srcGoalEn = 'goal';
}
optNum++; // 1 is added every time the addBtn is hit
var modalOptDyna =
` <br>` +
` <label for="tp-${srcGoalEn}-input-${optNum}" style="${labelCSS}; margin-top: 0.5em">${sel}${srcGoal}${optNum}</label>` +
` <p class="tp-p tp-${srcGoalEn}-p" id="tp-${srcGoalEn}-p-${optNum}" style="${missingCSS}"></p>` +
` <input class="tp-${srcGoalEn}-input" id="tp-${srcGoalEn}-input-${optNum}">`;
// Show the box
$('.tp-btn-div').before(modalOptDyna);
// Hide addBtn if optNum === 10
if (optNum === 10) {
$('.tp-btn-div').hide();
}
// Check the existence of the pagenames in the addional inputboxes
var isRunning = '';
$('.tp-modal-dialog input').on('input', function(e){
setTimeout(function(){ // Delay by 0.5s
if (isRunning === e.target.id) { // Don't run when the code is already running
return;
}
isRunning = e.target.id;
var $tar = $('#' + e.target.id);
var tarVal = trimA($tar.val());
var $tarP = $('#' + e.target.id.replace('input', 'p'));
if (tarVal === '') {
$tarP.text('');
isRunning = '';
} else {
new mw.Api().get({
action: 'query',
titles: tarVal,
formatversion: 2
}).done(function(res){
var missing = res.query.pages[0].missing == true ? true: false;
if (missing) {
$tarP.text('✗').css('color', 'red');
} else if (missing === false) {
$tarP.text('✓').css('color', 'limegreen');
}
isRunning = '';
});
}
}, 500);
});
return;
});
// Check the existence of the pagenames in the default inputboxes
var isRunning = '';
$('.tp-modal-dialog input').on('input', function(e){
setTimeout(function(){ // Delay by 0.5s
if (isRunning === e.target.id) { // Don't run when the code is already running
return;
}
isRunning = e.target.id;
var $tar = $('#' + e.target.id);
var tarVal = trimA($tar.val());
var $tarP = $('#' + e.target.id.replace('input', 'p'));
if (tarVal === '') {
$tarP.text('');
isRunning = '';
} else {
new mw.Api().get({
action: 'query',
titles: tarVal,
formatversion: 2
}).done(function(res){
var missing = res.query.pages[0].missing == true ? true: false;
if (missing) {
$tarP.text('✗').css('color', 'red');
} else if (missing === false) {
$tarP.text('✓').css('color', 'limegreen');
}
isRunning = '';
});
}
}, 500);
});
});
});
// Function to convert the name of a main-space page to that of its talk page
function ConvToTalk(page){
var ns = page.split(':');
var pageNoNs = page.replace(ns[0] + ':', '');
switch(ns[0]) {
case 'ノート':
return 'ノート:' + pageNoNs;
case '利用者':
case '利用者‐会話':
case '利用者-会話':
case '利用者・トーク':
case 'User':
case 'User talk':
return '利用者‐会話:' + pageNoNs;
case 'Wikipedia':
case 'Wikipedia‐ノート':
case 'Wikipedia-ノート':
case 'Wikipedia talk':
case 'Project':
case 'Project talk':
case 'WP':
case 'WT':
return 'Wikipedia‐ノート:' + pageNoNs;
case 'ファイル':
case 'ファイル‐ノート':
case 'ファイル-ノート':
case 'ファイル・トーク':
case 'File':
case 'File talk':
case '画像':
case '画像‐ノート':
case '画像-ノート':
case 'Image':
case 'Image talk':
return 'ファイル‐ノート:' + pageNoNs;
case 'MediaWiki':
case 'MediaWiki‐ノート':
case 'MediaWiki-ノート':
case 'MediaWiki・トーク':
case 'MediaWiki talk':
return 'MediaWiki‐ノート:' + pageNoNs;
case 'Template':
case 'Template‐ノート':
case 'Template-ノート':
case 'テンプレート':
case 'テンプレート・トーク':
case 'Template talk':
return 'Template‐ノート:' + pageNoNs;
case 'Help':
case 'Help‐ノート':
case 'Help-ノート':
case 'ヘルプ':
case 'ヘルプ・トーク':
case 'Help talk':
return 'Help‐ノート:' + pageNoNs;
case 'Category':
case 'Category‐ノート':
case 'Category-ノート':
case 'カテゴリ':
case 'カテゴリ・トーク':
case 'Category talk':
return 'Category‐ノート:' + pageNoNs;
case 'Portal':
case 'Portal‐ノート':
case 'Portal-ノート':
case 'ポータル‐ノート':
case 'ポータル-ノート':
case 'Portal・トーク':
return 'Portal‐ノート:' + pageNoNs;
case 'プロジェクト':
case 'プロジェクト‐ノート':
case 'プロジェクト-ノート':
case 'プロジェクト・トーク':
return 'プロジェクト‐ノート:' + pageNoNs;
case 'モジュール':
case 'モジュール‐ノート':
case 'モジュール-ノート':
case 'モジュール・トーク':
case 'Module':
case 'Module talk':
return 'モジュール‐ノート:' + pageNoNs;
case 'Gadget':
case 'Gadget talk':
return 'Gadget talk:' + pageNoNs;
case 'Gadget definition':
case 'Gadget definition talk':
return 'Gadget definition talk:' + pageNoNs;
default:
return 'ノート:' + page;
}
}
// Function to trim U+200E space
function trimA(str) {
return str.trim().replaceAll(/\u200e/g, '').replaceAll('_', ' ');
}
}
});
//</nowiki>