コンテンツにスキップ

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

利用者:Syunsyunminmin/script/archiver.js

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

多くの WindowsLinux のブラウザ

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

Mac における Safari

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

Mac における ChromeFirefox

  • Cmd Shift を押しながら R を押す。

詳細についてはWikipedia:キャッシュを消すをご覧ください。

/*
forked from:
https://en-two.iwiki.icu/w/index.php?title=User:%CE%A3/Testing_facility/Archiver.js&oldid=1003561411 by [[:w:en:User:Enterprisey]]
https://en-two.iwiki.icu/w/index.php?title=User:Enterprisey/archiver.js&oldid=1113588553 by [[:w:ja:User:Syunsyunminmin]]
*/
$.when( mw.loader.using(['mediawiki.util','mediawiki.api']), $.ready).done( function () {
    if (mw.config.get("wgNamespaceNumber") % 2 == 0 && mw.config.get("wgNamespaceNumber") != 4) {
        // not a talk page and not project namespace
        return;
    }
    if (mw.config.get("wgNamespaceNumber") == -1) {
        // is a special page
        return;
    }

    mw.util.addCSS(".arky-selected-section { background-color:#D9E9FF } .arky-selected-section .arky-span a { font-weight:bold }");

    var sectionCodepointOffsets = new Object();
    var wikiText = "";
    var revStamp; // The timestamp when we originally got the page contents - we pass it to the "edit" API call for edit conflict detection

    var portletLink = mw.util.addPortletLink("p-cactions", "#", "ØCA", "pt-oeca", "Enter/exit the archival process", null, null);
    var archiveButton = $(document.createElement("button"));
    $(portletLink).click(function(e) {
        $(".arky-selected-section").removeClass('.arky-selected-section');
        $(".arky-span").toggle();
        $("#arky-archive-button").toggle();
    });

    archiveButton.html("選択したスレッドすべてを過去ログ化する")
        .attr("id", 'arky-archive-button')
        .css("position", 'sticky')
        .css("bottom", 0)
        .css("width", '100%')
        .css("font-size", '200%');
    $(document.body).append(archiveButton);
    archiveButton.toggle();
    archiveButton.click(function(e) {
        // returns `s` without the substring starting at `start` and ending at `end`
        function cut(s, start, end) {
            return s.substr(0, start) + s.substring(end);
        }
        var selectedSections = $(".arky-selected-section .arky-span").map(function() {
            return $(this).data("section");
        }).toArray();
        if (selectedSections.length === 0) {
            return alert("選択しているスレッドがないため、中止します");
        }

        var archivePageName = prompt(selectedSections.length + "件のスレッドを過去ログ化します: どこに移動させますか? (例: Wikipedia:サンドボックス/過去ログ1)", mw.config.get("wgPageName"));
        if (!archivePageName || archivePageName == mw.config.get("wgPageName")) {
            return alert("過去ログ先が選択されていないため、中止します");
        }

        // codepointToUtf16Idx maps codepoint idx (i.e. MediaWiki index into page text) to utf-16 idx (i.e. JavaScript index into wikiText)
        var codepointToUtf16Idx = {};

        // Initialize "important" (= either a section start or end) values to 0
        selectedSections.forEach(function(n) {
            codepointToUtf16Idx[sectionCodepointOffsets[n].start] = 0;
            codepointToUtf16Idx[sectionCodepointOffsets[n].end] = 0;
        });
        codepointToUtf16Idx[Infinity] = Infinity; // Because sometimes we'll have Infinity as an "end" value

        // fill in our mapping from codepoints (MediaWiki indices) to utf-16 (i.e. JavaScript).
        // yes, this loops through every character in the wikitext. very unfortunate.
        var codepointPos = 0;
        for (var utf16Pos = 0; utf16Pos < wikiText.length; utf16Pos++, codepointPos++) {
            if (codepointToUtf16Idx.hasOwnProperty(codepointPos)) {
                codepointToUtf16Idx[codepointPos] = utf16Pos;
            }

            if ((0xD800 <= wikiText.charCodeAt(utf16Pos)) && (wikiText.charCodeAt(utf16Pos) <= 0xDBFF)) {
                // high surrogate! utf16Pos goes up by 2, but codepointPos goes up by only 1.
                utf16Pos++; // skip the low surrogate
            }
        }

        var newTextForArchivePage = selectedSections.map(function(n) {
            return wikiText.substring(
                codepointToUtf16Idx[sectionCodepointOffsets[n].start],
                codepointToUtf16Idx[sectionCodepointOffsets[n].end]
            );
        }).join("");

        selectedSections.reverse(); // go in reverse order so that we don't invalidate the offsets of earlier sections
        var newWikiText = wikiText;
        selectedSections.forEach(function(n) {
            newWikiText = cut(
                newWikiText,
                codepointToUtf16Idx[sectionCodepointOffsets[n].start],
                codepointToUtf16Idx[sectionCodepointOffsets[n].end]
            );
        });

        console.log("archive this:" + newTextForArchivePage);
        console.log("revised page:" + newWikiText);
        var pluralizedThreads = selectedSections.length + '件のスレッド';
        new mw.Api().postWithToken("csrf", {
            action: 'edit',
            title: mw.config.get("wgPageName"),
            text: newWikiText,
            summary: "[[" + archivePageName + "]]へ移動予定の" + pluralizedThreads + "を除去",
            basetimestamp: revStamp,
            starttimestamp: revStamp
        }).done(function(res1) {
            alert("会話ページからのスレッド除去に成功しました");
            console.log(res1);
            new mw.Api().postWithToken("csrf", {action: 'edit', title: archivePageName, appendtext: "\n" + newTextForArchivePage, summary: "[[Special:Permalink/" + mw.config.get("wgRevisionId") + "|" + mw.config.get("wgPageName") + "]]から" + pluralizedThreads + "を追加"})
                .done(function(res2) {
                    alert("過去ログページへのスレッド追加に成功しました");
                })
                .fail(function(res2) {
                    alert("スレッドを過去ログページに追加するのに失敗しました。手動で追加する必要があります。");
                })
                .always(function(res2) {
                    console.log(res2);
                    window.location.reload();
                });
            })
            .fail(function(res1) {
                alert("会話ページからのスレッド除去に失敗しました。過去ログ処理を中止します。");
                console.log(res1);
                window.location.reload();
            });
    }); // end of archiveButton click handler

    // grab page sections and wikitext so we can add the "archive" links to appropriate sections
    new mw.Api().get({action: 'parse', page: mw.config.get("wgPageName")}).done(function(parseApiResult) {
        new mw.Api().get({action: 'query', pageids: mw.config.get("wgArticleId"), prop: ['revisions'], rvprop: ['content', 'timestamp']}).done(function(revisionsApiResult) {
            var rv;
            rv = revisionsApiResult.query.pages[mw.config.get("wgArticleId")].revisions[0];
            wikiText = rv["*"];
            revStamp = rv['timestamp'];
        });

        var validSections = {};

        $(parseApiResult.parse.sections)
            // For sections transcluded from other pages, s.index will look
            // like T-1 instead of just 1. Remove those.
            .filter(function(i, s) { return s.index == parseInt(s.index) })

            .each(function(i, s) { validSections[s.index] = s });

        for (var i in validSections) {
            i = parseInt(i);
            // What MediaWiki calls "byteoffset" is actually a codepoint offset!! Drat!!
            sectionCodepointOffsets[i] = {
                start: validSections[i].byteoffset,
                end: validSections.hasOwnProperty(i+1)?validSections[i+1].byteoffset:Infinity
            };
        }
        $("#mw-content-text").find(":header").find("span.mw-headline").each(function(i, title) {
            var header, headerLevel, editSection, sectionNumber;
            header = $(this).parent();
            headerLevel = header.prop("tagName").substr(1, 1) * 1; // wtf javascript
            editSection = header.find(".mw-editsection"); // 1st child
            var editSectionLink = header.find(".mw-editsection a:last");
            var sectionNumber = undefined;

            if (editSectionLink[0]) {
                // Note: href may not be set.
                var sectionNumberMatch = editSectionLink.attr("href") && editSectionLink.attr("href").match(/&section=(\d+)/);
                if (sectionNumberMatch) {
                    sectionNumber = sectionNumberMatch[1];
                }
            }
            // if the if statement fails, it might be something like <h2>not a real section</h2>
            if (validSections.hasOwnProperty(sectionNumber)){
                $(editSection[0]).append(
                    "&nbsp;",
                    $("<span>", { "class": "arky-span" })
                    .css({'display':'none'})
                    .data({'header-level': headerLevel, 'section': sectionNumber})
                    .append(
                        $('<span>', { 'class': 'mw-editsection-bracket' }).text('['),
                        $('<a>')
                        .text('過去ログ化')
                        .click(function(){
                            var parentHeader = $(this).parents(':header');
                            parentHeader.toggleClass('arky-selected-section');

                            // now, click all sub-sections of this section
                            var isThisSectionSelected = parentHeader.hasClass('arky-selected-section');
                            var thisHeaderLevel = $(this).parents('.arky-span').data('header-level');

                            // starting from the current section, loop through each section
                            var allArchiveSpans = $('.arky-span');
                            var currSectionIdx = allArchiveSpans.index($(this).parents('.arky-span'));
                            for(var i = currSectionIdx + 1; i < allArchiveSpans.length; i++) {
                                if($(allArchiveSpans[i]).data('header-level') <= thisHeaderLevel) {
                                    // if this isn't a subsection, quit
                                    break;
                                }
                                var closestHeader = $(allArchiveSpans[i]).parents(':header');
                                if(closestHeader.hasClass('arky-selected-section') != isThisSectionSelected) {
                                    // if this section needs toggling, toggle it
                                    closestHeader.toggleClass('arky-selected-section');
                                }
                            }

                            // finally, update button
                            $('#arky-archive-button')
                                .prop('disabled', !$('.arky-selected-section').length)
                                .text('選択している' + $('.arky-selected-section').length + '件のスレッドを過去ログ化');
                        }),
                        $('<span>', { 'class': 'mw-editsection-bracket' }).text(']')
                    ));
            }
        });
    });
});