您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Displays the standings page centered around your rank by default in AtCoder contests.
当前为
// ==UserScript== // @name AtCoder Center Your Standing // @namespace http://tampermonkey.net/ // @version 1.4 // @description Displays the standings page centered around your rank by default in AtCoder contests. // @author haruomaki // @match https://atcoder.jp/contests/*/standings // @match https://atcoder.jp/contests/*/standings/virtual // @match https://atcoder.jp/contests/*/results // @grant none // @license CC0 // ==/UserScript== (function () { 'use strict'; /* global vueStandings, vueResults, userScreenName */ // Configs // --------------------------- const default_center = true; // --------------------------- var first_click = false; var current_row = null; function exists(name) { return typeof window[name] !== 'undefined'; } var vue; if (exists("vueStandings")) { vue = vueStandings; } else if (exists("vueResults")) { vue = vueResults; } else { console.error("順位データが読み込めません"); return; } function getMyStanding() { return document.querySelector("tr.info"); } function myRank(user_id) { if (exists("vueStandings")) { return vue.orderedStandings.findIndex(data => data.UserScreenName == user_id) + 1; } if (exists("vueResults")) { return vue.orderedResults.findIndex(data => data.UserScreenName == user_id) + 1; } } function clickActivePagination() { // ページネーション内のリンク要素を取得 const linkElement = document.querySelector('.pagination .active a') linkElement.click(); } function center_me() { if (!first_click) { first_click = true; clickActivePagination(); // 一度クリックしておかないと、なぜかページ移動が効かない } const user_id = userScreenName; const rank = myRank(user_id); // 存在しなければ0が返る if (rank == 0) return; const target_page = Math.ceil(rank / vue.perPage); console.debug("center me:", { user_id, rank, target_page }); vue.page = target_page; // これで遷移 } function remakeClickable() { if (current_row != null) { //console.debug("クリック機能削除:", current_row); current_row.removeAttribute('title'); current_row.removeEventListener('click', center_me); } const row = getMyStanding(); if (row == null) return; //console.debug("クリック可能にします:", row); row.setAttribute('title', 'Click to center your standing'); row.addEventListener('click', center_me); current_row = row; } function main() { // 自身の行をクリックするとページ移動 remakeClickable(); // 自順位の行が移動もしくは生成されるたびにremake const observer = new MutationObserver(mutations => { for (const mutation of mutations) { if (mutation.type === 'childList') { // 新しいノードが追加された場合 mutation.addedNodes.forEach(node => { if (node.nodeType === 1 && node.classList.contains('info')) { console.debug('<tr class="info"> が追加されました'); remakeClickable(); } }); } else if (mutation.type === 'attributes' && mutation.target.classList.contains('info')) { // 既存のノードにinfoクラスが付与された場合 console.debug('<tr> に infoクラスが付与されました'); remakeClickable(); } } }); // 監視を開始する observer.observe(document.body, { childList: true, attributes: true, attributeFilter: ['class'], subtree: true }); if (default_center) center_me(); } // 順位表本体が読み込まれるまで待機 const interval = setInterval(() => { if (vue.standings || vue.results) { clearInterval(interval); main(); } }, 100); })();