コンテンツにスキップ

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

利用者:稲垣啓二/SpurLink.js

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

多くの WindowsLinux のブラウザ

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

Mac における Safari

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

Mac における ChromeFirefox

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

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

/************************************************
   Name: SpurLink
   Author: Dragoniez
   Version: 1.2.0
*************************************************/
//<nowiki>

// 依存モジュールとDOMの読み込みが完了したらスクリプトを起動
$.when(
    mw.loader.using(['mediawiki.util', 'mediawiki.api', 'mediawiki.user']),
    $.ready
).then(function() {

    // 編集画面の場合は終了
    if (mw.config.get('wgAction') === 'edit') return;

    // <style> タグを追加
    $('head').append(
        '<style>' +
            '.sl-spurlink-checked::after,' +
            '.sl-ipqslink-checked::after {' +
                'content: "C";' +
                'color: orange;' +
                'font-weight: bold;' +
                'vertical-align: super;' +
                'font-size: smaller;' +
            '}' +
            '.sl-spurlink-proxy::after,' +
            '.sl-ipqslink-proxy::after {' +
                'content: "P";' +
                'color: red;' +
                'font-weight: bold;' +
                'vertical-align: super;' +
                'font-size: smaller;' +
            '}' +
            '.sl-spurlink-invalid,' +
            '.sl-ipqslink-invalid {' +
                'opacity: 0.4;' +
            '}' +
        '</style>'
    );

    // チェック履歴を取得
    var getHistory = function() {
        var history = mw.user.options.get('userjs-sl-history');
        if (history) {
            history = JSON.parse(history);
            // ----- バージョン互換 (v1.1) -----
            if (history.checked) {
                history = {
                    spur: history,
                    ipqs: {
                        checked: [],
                        proxy: []
                    }
                };
            }
            // ------------------------------
        } else {
            history = {
                spur: {
                    checked: [],
                    proxy: []
                },
                ipqs: {
                    checked: [],
                    proxy: []
                }
            };
        }
        return history;
    };
    var history = getHistory();
    console.log('SpurLink', history);

    // ページ内に元からあるSPURへのリンクを、専用のspanタグで囲む
    $(mw.util.$content).find('a').each(function() {
        var href = $(this).attr('href');
        if (!href) return;
        var ip;
        if (ip = href.match(/^(?:https?:)?\/\/spur\.us\/context\/(.*)$/)) {
            if (!(ip = ip[1]) || !mw.util.isIPAddress(ip)) return $(this).addClass('sl-spurlink-invalid');
            $(this).prop('outerHTML', wrapLink('spur', ip, $(this).attr('target', '_blank').prop('outerHTML')));
        }
    });

    // 投稿記録上での個別処理
    var isContribs = mw.config.get('wgCanonicalSpecialPageName') === 'Contributions';
    if (isContribs) {
        (function() { // 途中で処理を中止し次のプロセスに移行したい場合があるため即時関数でスコープを作成

            // 誰の投稿記録かを判別の上、単一IPの場合のみ駆動
            var ip = $('#firstHeading').text().replace(/の投稿記録$/, '');
            if (!mw.util.isIPAddress(ip)) return;

            // Anchorタグを生成
            var spurLink = generateLinks(ip, false);

            // ヘッダーの真下のツールリンクにSpurへのリンクを作成
            $('.mw-changeslist-links').eq(0).children('span').last().after(spurLink);

            // ブロックされている場合、該当メッセージ内部のツールリンクにもSpurへのリンクを追加
            var $blockNotice = $('.mw-logline-block');
            if ($blockNotice) {
                var blockedIp = $blockNotice.children('.mw-anonuserlink').eq(0).text();
                if (mw.util.isIPAddress(blockedIp)) $blockNotice.children('.mw-anonuserlink').next('.mw-usertoollinks').children('span').after(spurLink);
            }

        })();
    }

    // 全てのページ上での処理
    mw.hook('wikipage.content').add(function() { // 最近の更新とウォッチリスト上で画面が更新された際にも駆動

        // IPユーザーのリンクを「(会話)」などが続くもののみに絞り込み
        $('.mw-anonuserlink').filter(function() {

            var nextClass = isContribs ? 'mw-usertoollinks-talk' : 'mw-usertoollinks';
            return $(this).next().hasClass(nextClass) && mw.util.isIPAddress($(this).text());

        }).each(function() { // 絞り込んだリンクをループし適切な場所にSpurへのリンクを追加
            
            if ($(this).hasClass('sl-added')) return;
            $(this).addClass('sl-added');
            var ip = $(this).text();
            var tagName = isContribs ? 'A' : $(this).next().children().eq(0).prop('tagName');
            var $last = isContribs ? $(this).nextAll(tagName).last() : $(this).next().find(tagName).last();
            var addPipe = tagName === 'A';
            $last.after(generateLinks(ip, addPipe));

        });

    });

    // SpurLinkがクリックされた際の処理 (右クリックは処理できないため注意)
    $(document).off('click', '.sl-anchor').on('click', '.sl-anchor', function(e) {

        var $wrapper = $(this).parent('.sl-wrapper');
        var ip = $wrapper.attr('data-ip');
        var linktype = $wrapper.attr('data-linktype');
        var $allLinks = $('.sl-' + linktype + 'link').filter(function() { return $(this).attr('data-ip') === ip; });
        var generateClass = function(status) {
            return 'sl-' + linktype + 'link-' + status;
        };
        var historyCopy = JSON.stringify(history); // 後で比較用にクリック時のリンク参照履歴をStringとしてコピー
        var index;

        // CtrlキーとShiftキーが両方押されている場合
        if (e.ctrlKey && e.shiftKey) {

            // 全ての状態を解除 (「P」も「C」も除去)
            e.preventDefault();
            Object.keys(history[linktype]).forEach(function(key) {
                var i = history[linktype][key].indexOf(ip);
                if (i !== -1) history[linktype][key].splice(i, 1);
            });
            $allLinks.removeClass(generateClass('checked')).removeClass(generateClass('proxy'));

        // Ctrlキーが押されている場合
        } else if (e.ctrlKey) {

            e.preventDefault();

            // クリックされたSpurLinkが「P」の状態なら
            if ($wrapper.hasClass(generateClass('proxy'))) {

                // 「C」の状態に変更
                $allLinks.removeClass(generateClass('proxy')).addClass(generateClass('checked'));
                index = history[linktype].proxy.indexOf(ip);
                if (index !== -1) history[linktype].proxy.splice(index, 1);
                if ($.inArray(ip, history[linktype].checked) === -1) history[linktype].checked.push(ip);

            // クリックされたSpurLinkが「C」の状態、または「P」の状態でも「C」の状態でもなければ
            } else {

                // 「P」の状態に変更
                $allLinks.removeClass(generateClass('checked')).addClass(generateClass('proxy'));
                index = history[linktype].checked.indexOf(ip);
                if (index !== -1) history[linktype].checked.splice(index, 1);
                if ($.inArray(ip, history[linktype].proxy) === -1) history[linktype].proxy.push(ip);

            }

        // Shiftキーが押されている場合
        } else if (e.shiftKey) {

            // リンク先を開かずに「C」の状態に変更
            e.preventDefault();
            $allLinks.removeClass(generateClass('proxy')).addClass(generateClass('checked'));
            index = history[linktype].proxy.indexOf(ip);
            if (index !== -1) history[linktype].proxy.splice(index, 1);
            if ($.inArray(ip, history[linktype].checked) === -1) history[linktype].checked.push(ip);
            

        // キーが何も押されていない場合
        } else {

            // 「C」の状態でも「P」の状態でもなければ
            if (!$wrapper.hasClass(generateClass('checked')) && !$wrapper.hasClass(generateClass('proxy'))) {
                // リンク先を開き「C」の状態に変更
                $allLinks.addClass(generateClass('checked'));
                if ($.inArray(ip, history[linktype].checked) === -1) history[linktype].checked.push(ip);
            }

        }

        // SpurLinkの状態を保存
        var options = JSON.stringify(history); // 履歴を格納しているオブジェクトをString化
        if (historyCopy === options) return; // リンククリック直後と各処理の終了後に履歴の内容が変化していない場合は終了
        new mw.Api().saveOption('userjs-sl-history', options) // APIリクエストを送信し履歴を保存
        .then(function() {
            mw.user.options.set('userjs-sl-history', options);
            history = getHistory();
        }).catch(function(code, err) {
            console.log(err.error.info);
        });

    });

    /**
     * Spurへのアンカータグをspanで囲む関数
     * @param {string} linktype 'spur' or 'ipqs'
     * @param {string} ip 
     * @param {string} anchor 
     * @returns {string}
     */
    function wrapLink(linktype, ip, anchor) {
        var clss = 'sl-' + linktype + 'link';
        if ($.inArray(ip, history[linktype].checked) !== -1) {
            clss += ' ' + clss + '-checked';
        } else if ($.inArray(ip, history[linktype].proxy) !== -1) {
            clss += ' ' + clss + '-proxy';
        }
        return '<span class="sl-wrapper ' + clss + '" data-ip="' + ip + '" data-linktype="' + linktype + '">' + anchor + '</span>';
    }

    /**
     * Spurへのanchorタグを生成する関数
     * @param {string} ip
     * @param {boolean} [addPipe] trueの場合リンクの前にパイプを追加
     * @returns {string}
     */
    function generateLinks(ip, addPipe) {
        ip = ip.toUpperCase();

        var spurA = '<a class="sl-anchor" href="//spur.us/context/' + ip + '" target="_blank">SPUR</a>';
        spurA = wrapLink('spur', ip, spurA); // 擬似要素がリンクに含まれないようにspanで囲む
        if (addPipe) spurA = ' | ' + spurA;

        var ipqsA = '<a class="sl-anchor" href="//www.ipqualityscore.com/free-ip-lookup-proxy-vpn-test/lookup/' + ip + '" target="_blank">IPQS</a>';
        ipqsA = wrapLink('ipqs', ip, ipqsA);
        if (addPipe) ipqsA = ' | ' + ipqsA;
        
        return spurA + ipqsA;
    }

});
//</nowiki>