AtCoder Jump to Submissions from Standings

順位表の得点をダブルクリックすると、該当するコンテスタントの実装を見ることができます。

  1. // ==UserScript==
  2. // @name AtCoder Jump to Submissions from Standings
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description 順位表の得点をダブルクリックすると、該当するコンテスタントの実装を見ることができます。
  6. // @match https://atcoder.jp/contests/*/standings*
  7. // @require https://code.jquery.com/jquery-3.6.1.min.js
  8. // @author hiro_hiro
  9. // @license CC0
  10. // @supportURL https://github.com/KATO-Hiro/AtCoder-Jump-to-Submissions-from-Standings/issues
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. $(function () {
  15. 'use strict';
  16.  
  17. $(document).on('dblclick', '.standings-result', function () {
  18. const $standingsType = getStandingsType($('body'));
  19.  
  20. const $prefix = addPrefixIfNeeds($standingsType);
  21.  
  22. const $clickedColumnIndex = getClickedColumnIndex(this, $standingsType);
  23. const $taskUrls = $('body').find('thead a');
  24. const $taskId = getTaskId($taskUrls, $clickedColumnIndex);
  25.  
  26. const $username = getUserName(this);
  27.  
  28. const $displayLanguage = getDisplayLanguage($(location));
  29. const $suffix = addSuffixIfNeeds($displayLanguage);
  30.  
  31. // 順位表の範囲外なら、提出ページに遷移しない
  32. if ($clickedColumnIndex < $taskUrls.length) {
  33. jumpToPersonalSubmissions($prefix, $taskId, $username, $suffix);
  34. }
  35. });
  36. })();
  37.  
  38. function getStandingsType(object) {
  39. let $standingsType = '';
  40. let isVirtual = $(object).find('script:contains("virtual")')[0];
  41. let isMultiply = $(object).find('script:contains("multiply_ranks")')[0];
  42. let isTeam = $(object).find('script:contains("team")')[0];
  43. let isExtended = $(object).find('script:contains("extended")')[0];
  44.  
  45. // HACK: if分岐はメンテナンス的によくないかも
  46. // HACK: 他の言語のEnumに相当する構文がデフォルトで存在しない?
  47. if (isVirtual) {
  48. $standingsType = 'virtual';
  49. } else if (isMultiply) {
  50. $standingsType = 'multiply';
  51. } else if (isTeam) {
  52. $standingsType = 'team';
  53. } else if (isExtended) {
  54. $standingsType = 'extended';
  55. } else {
  56. $standingsType = 'general';
  57. }
  58.  
  59. return $standingsType
  60. }
  61.  
  62. function addPrefixIfNeeds(standingsType) {
  63. let prefix = '';
  64.  
  65. if (standingsType != 'general') {
  66. prefix = '../';
  67. }
  68.  
  69. return prefix
  70. }
  71.  
  72. function getTaskId(taskUrls, clickedColumnIndex) {
  73. let $taskId = '';
  74.  
  75. taskUrls.each((index) => {
  76. if (index == clickedColumnIndex) {
  77. const $url = taskUrls[index].pathname;
  78. const $elements = $url.split('/');
  79. const $length = $elements.length;
  80.  
  81. $taskId = $elements[$length - 1]; // 0-indexed
  82. }
  83. });
  84.  
  85. return $taskId
  86. }
  87.  
  88. // HACK: 順位表の列数に応じた処理をしているため、AtCoderのUIが変更されると動かなくなる可能性がある
  89. // WHY : 順位表の得点の欄に、問題のIDが含まれていないため
  90. function getClickedColumnIndex(object, standingsType) {
  91. let $clickedColumnIndex = $(object)[0].cellIndex;
  92.  
  93. // コンテスト当日の順位表と延長戦順位表・バーチャル順位表の列の並びに違いがある
  94. // 当日の順位表の並びに合わせる
  95. if (standingsType == 'virtual' || standingsType == 'extended') {
  96. $clickedColumnIndex -= 1
  97. }
  98.  
  99. // 順位とユーザ名の欄を扱わずに済むようにインデックスを補正
  100. // A問題がindex = 0となるようにしている
  101. $clickedColumnIndex -= 3
  102.  
  103. return $clickedColumnIndex
  104. }
  105.  
  106. function getUserName(object) {
  107. const $standings = $(object).siblings('td');
  108. const $username = $standings.find('.username span').text();
  109.  
  110. return $username
  111. }
  112.  
  113. function getDisplayLanguage(location) {
  114. let language = 'jp';
  115. const params = location.attr('search');
  116.  
  117. if (params.match(/lang=en/)) {
  118. language = 'en';
  119. }
  120.  
  121. return language
  122. }
  123.  
  124. function addSuffixIfNeeds($displayLanguage) {
  125. let suffix = '&lang=';
  126.  
  127. if ($displayLanguage == 'en') {
  128. suffix += 'en';
  129. } else {
  130. suffix = '';
  131. }
  132.  
  133. return suffix
  134. }
  135.  
  136. function jumpToPersonalSubmissions(prefix, taskId, username, suffix) {
  137. setTimeout(function () {
  138. location.href = `${prefix}submissions?f.Task=${taskId}&f.Language=&f.Status=AC&f.User=${username}${suffix}`;
  139. }, 250)
  140. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址