Check Constraints

Add checkboxes to constraints of an AtCoder problem.

  1. // ==UserScript==
  2. // @name Check Constraints
  3. // @name:ja 制約をチェックする
  4. // @description Add checkboxes to constraints of an AtCoder problem.
  5. // @description:ja AtCoderの問題ページの制約にチェックボックスを追加します。
  6. // @version 1.0.1
  7. // @icon https://www.google.com/s2/favicons?domain=atcoder.jp
  8. // @author w0mbat
  9. // @match https://atcoder.jp/contests/*/tasks/*
  10. // @grant GM_addStyle
  11. // @namespace https://greatest.deepsurf.us/users/754798
  12. // ==/UserScript==
  13.  
  14. (function () {
  15. 'use strict';
  16.  
  17. console.log('😼<「制約をチェックする」を実行します。');
  18. if (location.href.replace(/\?.*$/, '').endsWith('/editorial')) {
  19. console.log('😼< 問題ページではなさそうなので、実行するのをやめます。');
  20. return;
  21. }
  22.  
  23. async function addStyle(src) {
  24. return new Promise((resolve) => {
  25. const link = document.createElement("link");
  26. link.rel = "stylesheet";
  27. link.href = src;
  28. document.getElementsByTagName("head")[0].appendChild(link);
  29. });
  30. }
  31. addStyle('https://cdn.jsdelivr.net/npm/pretty-checkbox@3.0/dist/pretty-checkbox.min.css');
  32. addStyle('https://cdn.jsdelivr.net/npm/@mdi/font@6.4.95/css/materialdesignicons.min.css');
  33. GM_addStyle(`
  34. .pretty.p-icon .state .icon { top: calc(((100% - 1em) - 2px) / 3) !important }
  35. .pretty .state label:after,.pretty .state label:before { top: calc(((100% - 1em) - 2px) / 3) !important }
  36. `);
  37.  
  38. function* getConstraintsSections() {
  39. // <h3>制約</h3>を子要素に持つsectionを取得
  40. for (const section of document.getElementsByTagName('section')) {
  41. for (const child of section.children) {
  42. if (child.tagName.toLowerCase() !== 'h3') continue;
  43. const text = child.textContent;
  44. if (text === '制約' || text === 'Constraints') yield section;
  45. }
  46. }
  47. }
  48.  
  49. function createCheckBox() {
  50. const checkbox = document.createElement('input');
  51. checkbox.type = 'checkbox';
  52. return checkbox;
  53. }
  54.  
  55. /**
  56. * @param {HTMLLIElement} li
  57. */
  58. function insertCheckBox(li) {
  59. // https://lokesh-coder.github.io/pretty-checkbox/
  60. const div = document.createElement('div');
  61. div.className = 'pretty p-icon p-round p-pulse';
  62. div.appendChild(createCheckBox());
  63. const state = div.appendChild(document.createElement('div'));
  64. state.className = 'state p-success';
  65. const icon = state.appendChild(document.createElement('i'));
  66. icon.className = 'icon mdi mdi-check';
  67. const label = state.appendChild(document.createElement('label'));
  68. [...li.childNodes].forEach(e => label.appendChild(e));
  69. li.appendChild(div);
  70. li.style.listStyleType = 'none';
  71. }
  72.  
  73. for (const section of getConstraintsSections()) {
  74. const ul = [...section.getElementsByTagName('ul')].shift();
  75. if (ul) {
  76. ul.style.paddingLeft = '1em';
  77. [...ul.querySelectorAll('li')].forEach(li => insertCheckBox(li));
  78. }
  79. }
  80.  
  81. console.log('😼<「制約をチェックする」を実行しました。');
  82. })();