您需要先安装一个扩展,例如 篡改猴、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);
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址