AtCoder ResultsPage Tweaks

AtCoderの提出結果一覧画面に自動検索機能などを追加します。

Fra 28.03.2021. Se den seneste versjonen.

  1. // ==UserScript==
  2. // @name AtCoder ResultsPage Tweaks
  3. // @namespace https://github.com/yukuse
  4. // @version 1.0.1
  5. // @description AtCoderの提出結果一覧画面に自動検索機能などを追加します。
  6. // @author yukuse
  7. // @include https://atcoder.jp/contests/*/submissions*
  8. // @grant window.jQuery
  9. // @grant window.fixTime
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. jQuery(($) => {
  14. const options = {
  15. // 検索条件変更時に自動検索 on/off
  16. autoSearchOnChange: true,
  17. // 検索結果の動的読み込み on/off
  18. dynamicResult: true,
  19. // 検索条件変更時のフォーカス維持 on/off
  20. keepSelectFocus: true,
  21. };
  22.  
  23. const $container = $('#main-container');
  24. const $panelSubmission = $container.find('.panel-submission');
  25.  
  26. const baseParams = {
  27. 'f.Task': '',
  28. 'f.LanguageName': '',
  29. 'f.Status': '',
  30. 'f.User': '',
  31. page: 1,
  32. };
  33.  
  34. function parseSubmissionsUrl(url) {
  35. const params = { ...baseParams };
  36. if (url) {
  37. Object.keys(params).forEach((key) => {
  38. const regexp = new RegExp(`${key}=([^&]+)`);
  39. const result = url.match(regexp);
  40. if (result) {
  41. [, params[key]] = result;
  42. }
  43. });
  44. }
  45.  
  46. return params;
  47. }
  48.  
  49. /**
  50. * 現在のURLに応じて検索結果表示を更新
  51. * TODO: ジャッジ中表示対応
  52. */
  53. function updateSearchResult() {
  54. const { href } = location;
  55. const params = parseSubmissionsUrl(href);
  56.  
  57. // 検索条件を遷移先の状態にする
  58. // FIXME: ページ遷移によりselectの状態が切り替わったとき、selectの表示が元のままになる
  59. Object.keys(params).forEach((key) => {
  60. $panelSubmission.find(`[name="${key}"]`).val(params[key]).trigger('change');
  61. });
  62.  
  63. const $tmp = $('<div>');
  64. $tmp.load(`${href} #main-container`, '', () => {
  65. const $newTable = $tmp.find('.table-responsive, .panel-body');
  66. // テーブル置換
  67. $panelSubmission.find('.table-responsive, .panel-body').replaceWith($newTable);
  68. // ページネーション置換
  69. if ($newTable.hasClass('table-responsive')) {
  70. $container.find('.pagination').replaceWith($tmp.find('.pagination:first'));
  71. } else {
  72. $container.find('.pagination').empty();
  73. }
  74.  
  75. // 日付を表示
  76. fixTime();
  77. });
  78. }
  79.  
  80. /**
  81. * 検索条件を元にURLを更新し、結果を表示する
  82. */
  83. function showSearchResult(params) {
  84. const paramsStr = Object.keys(params).map((key) => `${key}=${params[key]}`).join('&');
  85. const url = `${location.pathname}?${paramsStr}`;
  86.  
  87. if (options.dynamicResult) {
  88. history.pushState({}, '', url);
  89.  
  90. updateSearchResult();
  91. } else {
  92. location.href = url;
  93. }
  94. }
  95.  
  96. /**
  97. * 選択欄の調整
  98. * - 選択時に自動検索
  99. * - 選択時にフォーカスが飛ばないようにする
  100. */
  101. function initSelectTweaks() {
  102. $panelSubmission.find('#select-task, #select-language, #select-status').on('select2:select', (event) => {
  103. // 選択時に自動検索
  104. if (options.autoSearchOnChange) {
  105. const params = { ...baseParams };
  106. Object.keys(params).forEach((key) => {
  107. params[key] = $panelSubmission.find(`[name="${key}"]`).val();
  108. });
  109. params.page = 1;
  110.  
  111. showSearchResult(params);
  112. }
  113.  
  114. // 選択時にフォーカスが飛ばないようにする
  115. if (options.keepSelectFocus) {
  116. event.target.focus();
  117. }
  118. });
  119. }
  120.  
  121. const urlRegExp = new RegExp(location.pathname);
  122. /**
  123. * 検索結果のリンククリック時のページ遷移をなくし、表示を動的に更新する処理に置き換え
  124. */
  125. function initLinks() {
  126. $container.on('click', '.pagination a, .panel-submission a', (event) => {
  127. const { href } = event.target;
  128. if (!urlRegExp.test(href)) {
  129. return;
  130. }
  131.  
  132. event.preventDefault();
  133.  
  134. showSearchResult(parseSubmissionsUrl(href));
  135. });
  136. }
  137.  
  138. function init() {
  139. initSelectTweaks();
  140. if (options.dynamicResult) {
  141. window.addEventListener('popstate', updateSearchResult);
  142. initLinks();
  143. }
  144. }
  145.  
  146. init();
  147. });