หมายเหตุ: หลังเผยแพร่ คุณอาจต้องล้างแคชเว็บเบราว์เซอร์ของคุณเพื่อดูการเปลี่ยนแปลง

  • ไฟร์ฟอกซ์ / ซาฟารี: กด Shift ค้างขณะคลิก Reload หรือกด Ctrl-F5 หรือ Ctrl-R (⌘-R บนแมค)
  • กูเกิล โครม: กด Ctrl-Shift-R (⌘-Shift-R บนแมค)
  • อินเทอร์เน็ตเอกซ์พลอเรอร์ และ Edge: กด Ctrl ค้างขณะคลิก Refresh หรือกด Ctrl-F5
  • โอเปร่า: กด Ctrl-F5
// ========================================================
// สคริปต์จัดให้: revert module
//
// Copyright (C) 2006-2022, Jutiphan Mongkolsuthree
// 2021-2022, Bebiezaza
// Certain functions are copyrighted by their
// respective copyright holders
//
// Created: 25/02/2007
// Rewritten: 28/10/2021
// Replaced: original twinklefluff
//
// Additional Credits Information:
// ==============================================================
// Original code taken from Wikipedia:WikiProject User scripts/Scripts/Twinkle
// [[User:AzaToth/twinklefluff.js]]
// ========================================================
/* <pre><nowiki> */

var revertWhitelist = ['BotKung', 'TBot', 'JBot', 'NongBot', 'Chobot', 'Escarbot', 'Idioma-bot', 'Nullzerobot', 'Robbot', 'RoboDick', 'SieBot', 'Thijs!bot', 'TuvicBot', 'VolkovBot', 'YurikBot', 'Zwobot', 'InternetArchiveBot'];

function getRevNotice(state, text, error) {
    var gettingRev = "กำลังดึงข้อมูลรุ่นก่อนหน้านี้";
    if (error) {
        if (text) return mw.notify($("<b><span class='" + state + "'>" + gettingRev + ": " + text + "</span></b>"), { tag: 'twinkle_revert_state' });
        else return mw.notify($("<b><span class='" + state + "'>" + gettingRev + "</span></b>"), { tag: 'twinkle_revert_state' });
    } else {
        if (text) return mw.notify($("<span class='" + state + "'>" + gettingRev + ": " + text + "</span>"), { tag: 'twinkle_revert_state' });
        else return mw.notify($("<span class='" + state + "'>" + gettingRev + "</span>"), { tag: 'twinkle_revert_state' });
    }
}

function getCurrentRevInfo(pageName) {
    var info;
    $.ajax({
        url: mw.util.wikiScript('api'),
        dataType: 'json',
        async: false,
        data: {
            format: 'json',
            action: 'query',
            prop: 'revisions',
            indexpageids: true,
            titles: pageName,
            rvprop: 'ids',
            rvslots: 'main'
        },
        success: function(data) {
            var id = data.query.pageids[0];
            if (id == -1) {
                info = "";
            } else {
                info = {
                    revid: data.query.pages[id].revisions[0].revid,
                };
            }
        }
    });
    return info;
}

// this is the first place to get experimental asynchronous API call
function getRevertInfo(revID) {
    var api = new mw.Api();
    return api.get({
        action: 'query',
        prop: 'revisions',
        indexpageids: true,
        revids: revID,
        rvprop: 'ids|user|content',
        rvslots: 'main'
    }).then(function(data) {
        var info;
        var id = data.query.pageids[0];

        if (id == -1) {
            info = "";
        } else {
            info = {
                title: data.query.pages[id].title,
                revid: data.query.pages[id].revisions[0].revid,
                user: data.query.pages[id].revisions[0].user,
                content: data.query.pages[id].revisions[0].slots.main['*']
            };
        }
        return info;
    });
}

function getRollbackInfo(pageName) {
    var info = [];
    $.ajax({
        url: mw.util.wikiScript('api'),
        dataType: 'json',
        async: false,
        data: {
            format: 'json',
            action: 'query',
            prop: 'revisions',
            indexpageids: true,
            titles: pageName,
            rvprop: 'ids|user',
            rvlimit: 50
        },
        success: function(data) {
            var id = data.query.pageids[0];
            if (id == -1) {
                info = "";
            } else {
                for (var i in data.query.pages[id].revisions) {
                    var parser = {
                        revid: data.query.pages[id].revisions[i].revid,
                        user: data.query.pages[id].revisions[i].user
                    };
                    info.push(parser);
                }
            }
        }
    });
    return info;
}

function revertPage(pageName, editedText, summary, isMinor, willReload, undoRev, undoafterRev) {
    var api = new mw.Api();
    api.postWithEditToken({
        action: "edit",
        title: pageName,
        summary: summary,
        text: editedText,
        minor: isMinor,
        nocreate: true,
        undo: undoRev, // the newer revision
        undoafter: undoafterRev // the older revision
    }).done(function(a, b) {
        mw.log("Saved successfully");
        if (willReload) {
            mw.notify($("<span class='revert_status_confirm'><b>ดำเนินการย้อนเรียบร้อยแล้ว</b> กำลังรีโหลดหน้าใหม่...</span>"), { tag: 'twinkle_revert_editing' });
            window.setTimeout(function() {
                // window.location = Morebits.wiki.actionCompleted.redirect;
                location.reload();
            }, 5000);
        } else {
            mw.notify($("<span class='revert_status_confirm'><b>ดำเนินการย้อนเรียบร้อยแล้ว</b></span>"), { tag: 'twinkle_revert_editing' });
        }
    }).fail(function(a, b) {
        if (a === "http") {
            mw.log("HTTP error: " + b.textStatus);
            mw.notify($("<span class='revert_status_warn'>ขออภัย พบเจอปัญหาทำให้ไม่สามารถบันทึกได้: " + b.textStatus + " กรุณาลองใหม่อีกครั้ง</span>"));
        } else if (a === "ok-but-empty") {
            mw.log("Got an empty response from the server");
            mw.notify($("<span class='revert_status_warn'>ขออภัย พบเจอปัญหาทำให้ไม่สามารถทำเรื่องได้ กรุณาลองใหม่อีกครั้ง</span>"));
        } else {
            mw.log("API error: " + a);
            mw.notify($("<span class='revert_status_warn'>ขออภัย พบเจอปัญหาทำให้ไม่สามารถบันทึกได้: " + a + " กรุณาลองใหม่อีกครั้ง</span>"));
        }
    });
}

function revertToRevision(diffVersion) {
    if (diffVersion === "old") var link = document.querySelector("#mw-diff-otitle1 a").href;
    else if (diffVersion === "new") var link = document.querySelector("#mw-diff-ntitle1 a").href;
    else return mw.notify($("<span class='revert_status_warn'>พบข้อผิดพลาดที่ไม่คาดคิด ยกเลิกการย้อน<br>กรุณาตรวจสอบและลองใหม่อีกครั้ง</span>"));

    getRevNotice('revert_status_status', "");
    var revID = link.slice(link.lastIndexOf("oldid") + 6);

    getRevertInfo(revID).then(function(revertInfo) {
        var currentRevInfo = getCurrentRevInfo(mw.config.get('wgPageName'));

        if (revID != revertInfo.revid) return getRevNotice('revert_status_warn', "พบข้อผิดพลาด รุ่นที่ดึงข้อมูลมา ไม่ตรงกับรุ่นที่ต้องการ ยกเลิกการย้อน", true);
    
        var reason = prompt("กรุณาระบุสาเหตุที่ต้องการย้อนการแก้ไข (เว้นว่างหากไม่ระบุ):                      ", ""); // padded out to widen prompt in Firefox
        if (reason === null) return getRevNotice('revert_status_warn', "ยกเลิกการย้อนกลับโดยผู้ใช้", true);
        
        var userInfo = "[[Special:Contributions/" + revertInfo.user + "|" + revertInfo.user + "]] ([[User talk:" + revertInfo.user + "|พูดคุย]])";
        var summary = "ย้อนกลับไปรุ่นที่ " + revID + " โดย " + userInfo + " " + iScriptConfig.Tagline;
        if (reason) summary += ": " + reason;
    
        // push source
        getRevNotice('revert_status_confirm', "สำเร็จ");
        mw.notify($("<span class='revert_status_status'>กำลังบันทึกข้อมูล...</span>"), { tag: 'twinkle_revert_editing' });
        revertPage(revertInfo.title, revertInfo.content, summary, false, false, currentRevInfo.revid, revertInfo.revid);
    });
}

function rollback(type) {
    var pageName = mw.config.get('wgPageName');
    var currentRevID = mw.config.get('wgCurRevisionId');

    getRevNotice('revert_status_status', "");
    var rollbackInfo = getRollbackInfo(pageName);
    var currentRevInfo = getCurrentRevInfo(pageName);

    if (rollbackInfo.length < 1) return getRevNotice('revert_status_warn', "ข้อผิดพลาด: ไม่มีรุ่นก่อนหน้านี้ให้ย้อนกลับได้ จึงไม่สามารถดำเนินการได้ ยกเลิกการย้อน", true);
    if (currentRevID < rollbackInfo[0].revid) return mw.notify($("<b><span class='revert_status_warn'>ข้อผิดพลาด: เนื่องจากว่ารุ่น <strong>" + currentRevID + "</strong> ที่ต้องการย้อนนั้นไม่ใช่รุ่นล่าสุด ซึ่งอาจถูกลบไปแล้ว หรือมีปัญหาการเชื่อมต่อ กรุณาตรวจสอบและลองใหม่อีกครั้ง ยกเลิกการย้อน</span>"));
    if (currentRevID != rollbackInfo[0].revid) return mw.notify($("<span class='revert_status_warn'>คำเตือน: รุ่นล่าสุดที่ " + currentRevID + " ไม่ตรงกับรุ่น " + rollbackInfo[0].revid + " ที่ต้องการ" + /* the original does not have this and continues revert, but I do not have the handler for this part yet */" ยกเลิกการย้อน" + "</span>"));

    if (revertWhitelist.indexOf(rollbackInfo[0].user) !== -1) {
        switch (type) {
            case 'vand':
                mw.notify($("<span class='revert_status_confirm'>ข้อมูล: คุณได้เลือกให้ย้อนการก่อกวนของ <span style='font-weight: bold;'>" + rollbackInfo[0].user + "</span> ซึ่งเป็นบอตที่ได้รับการอนุมัติ ดังนั้นเราเชื่อว่าคุณต้องการย้อนกลับการแก้ไขของผู้ใช้ก่อนหน้านี้แทน</span>"));
                rollbackInfo.shift();
                break;
            case 'agf':
                mw.notify($("<span class='revert_status_warn'>แจ้งให้ทราบ: คุณได้เลือกย้อนเจตนาดีของ <span style='font-weight: bold;'>" + rollbackInfo[0].user + "</span> ซึ่งเป็นบอตที่ได้รับการอนุมัติและมีเจตนาดีโดยเสมอ หากพบว่าการแก้ไขบอตไม่ถูกต้อง และต้องการย้อนกลับ ให้เลือกการย้อนปกติแทน</span>"));
                return;
            case 'norm':
            /* falls through */
            default:
                var skipBot = confirm("การแก้ไขล่าสุดเป็นของ " + rollbackInfo[0].user + " ซึ่งเป็นบอตที่ได้รับการอนุมัติ คุณต้องการย้อนการแก้ไขของผู้ใช้ก่อนหน้านี้ (OK) หรือการแก้ไขของบอต (Cancel)");
                if (skipBot) {
                    rollbackInfo.shift();
                    mw.notify($("<span class='revert_status_confirm'>ข้อมูล: ตามที่คุณยืนยัน เราจะทำการย้อนการแก้ไขไปรุ่นก่อนการแก้ไขของ <span style='font-weight: bold;'>" + rollbackInfo[0].user + "</span></span>"));
                } else mw.notify($("<span class='revert_status_warn'>แจ้งให้ทราบ: คุณได้ยืนยันย้อนการแก้ไขของ <span style='font-weight: bold;'>" + rollbackInfo[0].user + "</span> ซึ่งเป็นบอตที่ได้รับการอนุมัติ แต่คุณยืนยันจึงดำเนินการต่อ</span>"));
                break;
        }
    }

    var offender = rollbackInfo[0].user;
    var revertToInfo;
    var revisionCount = -1;
    for (var i in rollbackInfo) {
        revisionCount++;
        if (rollbackInfo[i].user != offender) {
            revertToInfo = {
                revid: rollbackInfo[i].revid,
                user: rollbackInfo[i].user
            };
            break;
        }
    }

    if (!revertToInfo) return getRevNotice('revert_status_warn', "ไม่พบเจอรุ่นที่จะย้อนกลับ หยุดดำเนินการ อาจเป็นเพราะว่า " + rollbackInfo[0].user + " เป็นผู้แก้ไขหน้านี้แต่เพียงผู้เดียว หรือได้แก้ไขติดต่อกันมากกว่า 50 ครั้ง", true);

    // from here, we use modified revert code
    getRevertInfo(revertToInfo.revid).then(function(revertInfo) {
        if (revisionCount == 0) return mw.notify($("<b><span class='revert_status_warn'>ข้อผิดพลาด: ไม่พบเจอรุ่นที่จะย้อนกลับ หยุดการดำเนินการ ซึ่งอาจเป็นเพราะว่าการแก้ไขได้ถูกย้อนกลับไปแล้ว แต่รหัสรุ่นยังเหมือนเดิม</span></b>"));

        if (type !== 'vand' && revisionCount > 1) {
            if (!confirm(offender + ' ได้ทำการแก้ไขทั้งหมด ' + revisionCount + ' ครั้งติดต่อกัน คุณแน่ใจว่าต้องการย้อนการแก้ไขดังกล่าวทั้งหมด?')) {
                return mw.notify($("<span class='revert_status_confirm'>แจ้งให้ทราบ: ยกเลิกการย้อนกลับตามความต้องการของผู้ใช้</span>"));
            }
        }
        
        getRevNotice('revert_status_status', "พบเจอรุ่นที่ <strong>" + revertToInfo.revid + "</strong> ซึ่งเป็น <strong>" + revisionCount + "</strong> การแก้ไขที่แล้วโดย <strong>" + revertToInfo.user + "</strong>");
        var offenderInfo = "[[Special:Contributions/" + offender + "|" + offender + "]] ([[User talk:" + offender + "|พูดคุย]])";
        var summary;
        switch (type) {
            case 'agf':
                summary = "ย้อนการแก้ไข[[w:th:WP:AGF|เจตนาดี]]ของ " + offenderInfo + " " + iScriptConfig.Tagline;
                break;
            case 'vand':
                summary = "ย้อน[[w:th:WP:VAND|การก่อกวน]] " + revisionCount + " ครั้งของ " + offenderInfo + " ไปยังรุ่นโดย " + revertToInfo.user + " " + iScriptConfig.Tagline;
                break;
            case 'norm':
            default:
                summary = "ย้อน " + revisionCount + " การแก้ไขของ " + offenderInfo + " ไปยังการแก้ไขของ " + revertToInfo.user + " " + iScriptConfig.Tagline;
                break;

        }
        
        if (type == "agf" || type == "norm") {
            var reason = prompt("กรุณาระบุสาเหตุที่ต้องการย้อนการแก้ไข (เว้นว่างหากไม่ระบุ):                      ", ""); // padded out to widen prompt in Firefox
            if (reason === null) return getRevNotice('revert_status_warn', "ยกเลิกการย้อนกลับโดยผู้ใช้", true);
        }
        if (reason) summary += ": " + reason;

        getRevNotice('revert_status_confirm', "สำเร็จ");
        
        if (iScriptConfig.Edition == Editions.Wikipedia) {
            // open user page
            mw.notify($("<span class='revert_status_confirm'>ข้อมูล: กำลังเปิดหน้าพูดคุยกับผู้ใช้ของ <b>" + offender + "</b></span"));
            var r = {
                'title': 'User talk:' + offender,
                'action': 'edit',
                'iScriptAction': 'rollback-' + type,
                // 'preview': 'yes',
                'vanarticle': pageName.replace(/_/g, ' '),
                // 'vanarticlerevid': a.params.revid,
                // 'vanarticlegoodrevid': a.params.goodid,
                // 'type': a.params.type,
                // 'count': a.params.count
            }
            openInNewWindow(mw.util.getUrl('', r));
        }
        
        // push source
        mw.notify($("<span class='revert_status_status'>กำลังบันทึกข้อมูล...</span>"), { tag: 'twinkle_revert_editing' });
        revertPage(revertInfo.title, revertInfo.content, summary, false, true, currentRevInfo.revid, revertInfo.revid);
    });
}

function makeTwinkleLink(color, text) {
    var before = createElement('span', "[", {
        'style': "color: black;"
    });
    var main = createElement('span', text, {
        'style': "color: " + color + ";"
    });
    var after = createElement('span', "]", {
        'style': "color: black;"
    });
    var link = createElement('a', [before, main, after], {
        'href': "#",
        'style': "font-weight: bold;"
    });
    return link;
}

function twinkleStarter() {
    if (!document.getElementById('mw-diff-otitle1') || !document.getElementById('mw-diff-ntitle1')) return;
    var diffOld = document.getElementById('mw-diff-otitle1').parentNode;
    var diffNew = document.getElementById('mw-diff-ntitle1').parentNode;

    var revertToOld = makeTwinkleLink("SaddleBrown", "ย้อนกลับมาเป็นรุ่นนี้");
    var revertToOldDiv = createElement('div', revertToOld, { 'id': "iS-tw-revert-orevision" });
    diffOld.insertBefore(revertToOldDiv, diffOld.firstChild);
    
    if (document.getElementById('differences-nextlink')) {
        var revertToNew = makeTwinkleLink("SaddleBrown", "ย้อนกลับมาเป็นรุ่นนี้");
        var revertToNewDiv = createElement('div', revertToNew, { 'id': "iS-tw-revert-nrevision" });
        diffNew.insertBefore(revertToNewDiv, diffNew.firstChild);
    } else {
        var rollbackAGF = createElement('span', makeTwinkleLink("DarkOliveGreen", "ย้อนเจตนาดี"), { 'id': "iS-tw-rollback-agf" });
        var rollbackNorm = createElement('span', makeTwinkleLink("SteelBlue", "ย้อน"), { 'id': "iS-tw-rollback-normal" });
        var rollbackVand = createElement('span', makeTwinkleLink("Red", "ย้อนก่อกวน"), { 'id': "iS-tw-rollback-vand" });

        var rollbackButton = createElement('div', [rollbackAGF, " || ", rollbackNorm, " || ", rollbackVand], { 'id': "iS-tw-revert" });
        diffNew.insertBefore(rollbackButton, diffNew.firstChild);
    }

    $(revertToOld).click(function() { 
        revertToRevision("old");
    });
    $(revertToNew).click(function() { 
        revertToRevision("new");
    });
    $(rollbackAGF).click(function() { 
        rollback("agf");
    });
    $(rollbackNorm).click(function() { 
        rollback("norm");
    });
    $(rollbackVand).click(function() { 
        rollback("vand");
    });
}

$(document).ready(function() {
    if (mw.config.get('wgIsProbablyEditable')) {
        twinkleStarter();
    }
});