Domjudge-UI-for-Codeforces

For ICPC competitors practicing for the DOMjudge UI in codeforces.

  1. // ==UserScript==
  2. // @name Domjudge-UI-for-Codeforces
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1.0
  5. // @license MIT
  6. // @description For ICPC competitors practicing for the DOMjudge UI in codeforces.
  7. // @author jakao
  8. // @match https://codeforces.com/gym/*/submit*
  9. // @match https://codeforces.com/contest/*/submit*
  10. // @icon https://i.imgur.com/RwGYTmF.png
  11. // @grant GM_addStyle
  12. // ==/UserScript==
  13.  
  14. const css = `
  15. .summary-table {
  16. text-align: center;
  17. }
  18. table {
  19. width: 100%;
  20. border-collapse: collapse;
  21. }
  22. .score-penalty-table {
  23. display: flex;
  24. align-items: center;
  25. }
  26. .score-penalty-table > div {
  27. flex: 1;
  28. padding: 5px;
  29. border-right: 1px solid #ccc; /* Optional border for visual separation */
  30. }
  31. .score-penalty-table > div:first-child {
  32. border-right: 1px solid transparent; /* Transparent border between left and right */
  33. }
  34. .badge {
  35. display: inline-block;
  36. padding: .25em .4em;
  37. font-size: 75%;
  38. font-weight: 700;
  39. line-height: 1;
  40. text-align: center;
  41. white-space: nowrap;
  42. vertical-align: baseline;
  43. border-radius: .25rem;
  44. transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
  45. }
  46. .problem-badge {
  47. font-size: 100%;
  48. }
  49. td.score_cell {
  50. min-width: 4.2em;
  51. padding: 2px 1px 2px 1px;
  52. border-right: none;
  53. }
  54. .summary-table td.score_cell {
  55. min-width: 4.2em;
  56. border-right: none;
  57. }
  58. thead {
  59. display: table-header-group;
  60. vertical-align: middle;
  61. unicode-bidi: isolate;
  62. border-color: inherit;
  63. }
  64. .sortorderswitch {
  65. border-top: 2px solid black;
  66. }
  67. .summary-table {
  68. margin-top: 2.5em;
  69. }
  70. .summary-table a {
  71. display: block;
  72. padding: 2px 1px 2px 1px;
  73. text-decoration: none;
  74. color: black;
  75. }
  76. .scorenc, .scorett, .scorepl {
  77. text-align: center;
  78. width: 2ex;
  79. }
  80. .scorenc {
  81. font-weight: bold;
  82. }
  83. .summary-table .scoreaf { white-space: nowrap; border: 0; text-align: center; }
  84. .summary-table tr {
  85. border-bottom: 1px solid black;
  86. border-bottom-width: 1px;
  87. border-bottom-style: solid;
  88. border-bottom-color: black;
  89. height: 42px;
  90. }
  91. .summary-table .scoretn {
  92. padding: 0px 5px 0px;
  93. text-align: right;
  94. font-weight: bold;
  95. overflow: hidden;
  96. text-overflow: ellipsis;
  97. white-space: nowrap;
  98. }
  99. .summary-table td, .summary-table th {
  100. border-right: 1px solid silver;
  101. padding: 0px;
  102. }
  103. .summary-table-header {
  104. font-variant: small-caps;
  105. border-bottom: 2px solid black;
  106. white-space: nowrap;
  107. }
  108. .summary-table-header th{
  109. text-align: center;
  110. box-shadow: -1px 0px 0px 0px silver inset, 0px 2px 0px 0px black;
  111. border: none;
  112. background: var(--background-color);
  113. position: sticky;
  114. top: 0px;
  115. z-index: 1;
  116. }
  117. col {
  118. display: table-column;
  119. unicode-bidi: isolate;
  120. }
  121. colgroup {
  122. display: table-column-group;
  123. unicode-bidi: isolate;
  124. }
  125. .summary-table td {
  126. font-size: small;
  127. vertical-align: middle;
  128. text-align: center;
  129. }
  130. .summary-table td div {
  131. width: 4em;
  132. font-size: 120%;
  133. display: inline-block;
  134. }
  135. .summary-table td div span {
  136. font-weight: normal;
  137. font-size: 70%;
  138. display: block;
  139. }
  140. .summary-table th {
  141. text-align: center;
  142. box-shadow: -1px 0px 0px 0px silver inset, 0px 2px 0px 0px black;
  143. border: none;
  144. background: var(--background-color);
  145. position: sticky;
  146. top: 0px;
  147. z-index: 1;
  148. }
  149. td.scorenc {
  150. border-color: silver;
  151. border-right: 0;
  152. }
  153. *, ::after, ::before {
  154. box-sizing: border-box;
  155. }
  156. .row {
  157. display: -ms-flexbox;
  158. display: flex;
  159. -ms-flex-wrap: wrap;
  160. flex-wrap: wrap;
  161. margin-right: -15px;
  162. margin-left: -15px;
  163. }
  164. .col {
  165. -ms-flex-preferred-size: 0;
  166. flex-basis: 0;
  167. -ms-flex-positive: 1;
  168. flex-grow: 1;
  169. max-width: 100%;
  170. }
  171. .teamoverview {
  172. border-top: solid 1px darkgray;
  173. border-bottom: solid 1px darkgray;
  174. background-color: #c4d8ff;
  175. margin-top: 2ex;
  176. padding-left: 1ex;
  177. font-size: 1.17em;
  178. text-align: center;
  179. }
  180. .h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
  181. margin-bottom: .5rem;
  182. font-weight: 500 !important;
  183. line-height: 1.2;
  184. }
  185. h1 {
  186. display: block !important;
  187. font-size: 2em;
  188. margin-block-start: 0.67em !important;
  189. margin-block-end: 0.67em !important;
  190. margin-inline-start: 0px !important;
  191. margin-inline-end: 0px !important;
  192. font-weight: bold;
  193. unicode-bidi: isolate !important;
  194. }
  195. .data-table tr {
  196. border-bottom: 1px solid silver;
  197. }
  198. .table td, .table th {
  199. padding: .75rem;
  200. vertical-align: top;
  201. border-top: 1px solid #dee2e6;
  202. }
  203. .table-sm td, .table-sm th {
  204. padding: .3rem;
  205. }
  206. .table thead th {
  207. vertical-align: bottom;
  208. border-bottom: 2px solid #dee2e6;
  209. }
  210. .table .thead-light th {
  211. color: #495057;
  212. background-color: #e9ecef;
  213. border-color: #dee2e6;
  214. }
  215. table {
  216. border-collapse: collapse;
  217. }
  218. .table {
  219. width: 100%;
  220. margin-bottom: 1rem;
  221. color: #212529;
  222. }
  223. th {
  224. display: table-cell;
  225. vertical-align: inherit;
  226. font-weight: bold !important;
  227. text-align: -internal-center;
  228. unicode-bidi: isolate;
  229. }
  230. .sol {
  231. font-weight: bold;
  232. font-variant: small-caps;
  233. }
  234. .sol_queued {
  235. color: gray;
  236. }
  237. .sol_incorrect, .compile-unsuccessful {
  238. color: red;
  239. }
  240. .sol_correct, .compile-successful {
  241. color: green;
  242. }
  243. .probid, .langid {
  244. font-variant: small-caps;
  245. }
  246. .data-table td a, .data-table td a:hover {
  247. display: block;
  248. text-decoration: none;
  249. color: inherit;
  250. padding: 3px 5px;
  251. }
  252. .table-striped tbody tr:nth-of-type(odd) {
  253. background-color: rgba(0, 0, 0, .05);
  254. }
  255. body {
  256. color: var(--text-color);
  257. background-color: var(--background-color);
  258. font-family: Roboto, sans-serif !important;
  259. padding-bottom: 4em;
  260. padding-top: 4.5rem;
  261. }
  262.  
  263. div {
  264. display: block;
  265. unicode-bidi: isolate;
  266. }
  267. .navbar-collapse {
  268. -ms-flex-preferred-size: 100%;
  269. flex-basis: 100%;
  270. -ms-flex-positive: 1;
  271. flex-grow: 1;
  272. -ms-flex-align: center;
  273. align-items: center;
  274. }
  275. ul {
  276. display: block;
  277. list-style-type: disc;
  278. margin-block-start: 1em;
  279. margin-block-end: 1em;
  280. margin-inline-start: 0px;
  281. margin-inline-end: 0px;
  282. padding-inline-start: 40px;
  283. unicode-bidi: isolate;
  284. }
  285. dl, ol, ul {
  286. margin-top: 0;
  287. margin-bottom: 1rem;
  288. }
  289. .mr-auto, .mx-auto {
  290. margin-right: auto !important;
  291. }
  292. .navbar-nav {
  293. display: -ms-flexbox;
  294. display: flex;
  295. -ms-flex-direction: column;
  296. flex-direction: row;
  297. padding-left: 0;
  298. margin-bottom: 0;
  299. list-style: none;
  300. }
  301. li {
  302. display: list-item;
  303. text-align: -webkit-match-parent;
  304. unicode-bidi: isolate;
  305. }
  306. #menuDefault ul li.nav-item {
  307. white-space: nowrap;
  308. white-space-collapse: collapse;
  309. text-wrap: nowrap;
  310. }
  311. #menuDefault {
  312. display: flex;
  313. }
  314. .nav-link {
  315. display: block;
  316. padding: .5rem 1rem;
  317. }
  318. .navbar-dark .navbar-nav .active>.nav-link, .navbar-dark .navbar-nav .nav-link.active, .navbar-dark .navbar-nav .nav-link.show, .navbar-dark .navbar-nav .show>.nav-link {
  319. color: #fff !important;
  320. }
  321. .navbar-dark .navbar-nav .nav-link {
  322. color: #FFFFFF80 !important;
  323. font-size: 16px;
  324. }
  325. .fa, .fa-brands, .fa-classic, .fa-regular, .fa-sharp, .fa-solid, .fab, .far, .fas {
  326. -moz-osx-font-smoothing: grayscale;
  327. -webkit-font-smoothing: antialiased;
  328. display: var(--fa-display, inline-block);
  329. font-style: normal;
  330. font-variant: normal;
  331. line-height: 1;
  332. text-rendering: auto;
  333. }
  334. .fa-classic, .fa-regular, .fa-solid, .far, .fas {
  335. font-family: "Font Awesome 6 Free";
  336. }
  337. .fa-solid, .fas {
  338. font-weight: 900;
  339. }
  340. a {
  341. color: #007bff;
  342. text-decoration: none;
  343. background-color: transparent;
  344. }
  345. .navbar-brand {
  346. display: inline-block;
  347. padding-top: .3125rem;
  348. padding-bottom: .3125rem;
  349. margin-right: 1rem;
  350. /* font-size: 1.25rem; */
  351. font-size: 20px !important;
  352. line-height: inherit;
  353. white-space: nowrap;
  354. }
  355. .navbar-dark .navbar-brand {
  356. color: #fff;
  357. }
  358. .navbar-dark .navbar-text {
  359. color: rgba(255, 255, 255, .5);
  360. font-size: 16px;
  361. }
  362. .navbar-text {
  363. display: inline-block;
  364. padding-top: .5rem;
  365. padding-bottom: .5rem;
  366. }
  367. nav {
  368. display: block;
  369. unicode-bidi: isolate;
  370. }
  371. .navbar {
  372. position: relative;
  373. justify-content: space-between;
  374. -ms-flex-pack: justify;
  375. -ms-flex-wrap: wrap;
  376. -ms-flex-align: center;
  377. align-items: center;
  378. flex-direction: row;
  379. display: flex;
  380. display: -ms-flexbox;
  381. padding-top: 8px;
  382. padding-right: 16px;
  383. padding-bottom: 8px;
  384. padding-left: 16px;
  385. }
  386. .bg-dark {
  387. background-color: #343a40 !important;
  388. }
  389. .fixed-top {
  390. position: fixed;
  391. top: 0;
  392. right: 0;
  393. left: 0;
  394. z-index: 1030;
  395. }
  396.  
  397. /* submit button */
  398. .justify-content-center {
  399. -ms-flex-pack: center !important;
  400. justify-content: center !important;
  401. }
  402. .btn {
  403. display: inline-block;
  404. font-weight: 400;
  405. color: #212529;
  406. text-align: center;
  407. vertical-align: middle;
  408. -webkit-user-select: none;
  409. -moz-user-select: none;
  410. -ms-user-select: none;
  411. user-select: none;
  412. background-color: transparent;
  413. border: 1px solid transparent;
  414. padding: 6px 12px;
  415. font-size: 16px;
  416. line-height: 1.5;
  417. border-radius: .25rem;
  418. transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
  419. }
  420. .btn:not(:disabled):not(.disabled) {
  421. cursor: pointer;
  422. }
  423. .btn-success {
  424. color: #fff !important;
  425. background: #0a8927 !important;
  426. }
  427. .btn-info {
  428. color: #fff !important;
  429. background-color: #17a2b8 !important;
  430. }
  431. .score_pending {
  432. background: #6666FF !important;
  433. }
  434. .btn-secondary {
  435. color: #fff;
  436. background-color: #6c757d;
  437. border-color: #6c757d;
  438. }
  439. .modal-footer>* {
  440. margin: .25rem;
  441. }
  442. .btn-group-sm>.btn, .btn-sm {
  443. padding: .25rem .5rem;
  444. font-size: 14px;
  445. line-height: 1.5;
  446. border-radius: .2rem;
  447. }
  448. .modal-header {
  449. display: -ms-flexbox;
  450. display: flex;
  451. -ms-flex-align: start;
  452. align-items: flex-start;
  453. -ms-flex-pack: justify;
  454. justify-content: space-between;
  455. padding: 1rem 1rem;
  456. border-bottom: 1px solid #dee2e6;
  457. border-top-left-radius: calc(.3rem - 1px);
  458. border-top-right-radius: calc(.3rem - 1px);
  459. }
  460. .modal-title {
  461. margin-bottom: 0;
  462. line-height: 1.5;
  463. }
  464. .modal-header .close {
  465. padding: 1rem 1rem;
  466. margin: -1rem -1rem -1rem auto;
  467. }
  468. button.close {
  469. padding: 0;
  470. background-color: transparent;
  471. border: 0;
  472. }
  473. .close {
  474. float: right;
  475. font-size: 1.5rem;
  476. font-weight: 700;
  477. line-height: 1;
  478. color: #000;
  479. text-shadow: 0 1px 0 #fff;
  480. opacity: .5;
  481. }
  482. [type=button], [type=reset], [type=submit], button {
  483. -webkit-appearance: button;
  484. }
  485. button, select {
  486. text-transform: none;
  487. }
  488.  
  489. button, input {
  490. overflow: visible;
  491. }
  492. button, input, optgroup, select, textarea {
  493. margin: 0;
  494. font-family: inherit;
  495. font-size: inherit;
  496. line-height: inherit;
  497. }
  498. button {
  499. border-radius: 0;
  500. }
  501.  
  502. .close {
  503. color: #aaa;
  504. float: right;
  505. font-size: 28px;
  506. font-weight: bold;
  507. }
  508. .close:hover,
  509. .close:focus {
  510. color: black;
  511. text-decoration: none;
  512. cursor: pointer;
  513. }
  514. .modal-open .modal {
  515. overflow-x: hidden;
  516. overflow-y: auto;
  517. }
  518. .modal {
  519. position: fixed;
  520. top: 0;
  521. left: 0;
  522. z-index: 1050;
  523. display: none;
  524. width: 100%;
  525. height: 100%;
  526. overflow: hidden;
  527. outline: 0;
  528. }
  529. .fade {
  530. transition: opacity .15s linear;
  531. }
  532. .modal-header {
  533. display: -ms-flexbox;
  534. display: flex;
  535. -ms-flex-align: start;
  536. align-items: flex-start;
  537. -ms-flex-pack: justify;
  538. justify-content: space-between;
  539. padding: 16px 16px;
  540. border-bottom: 1px solid #dee2e6;
  541. border-top-left-radius: calc(.3rem - 1px);
  542. border-top-right-radius: calc(.3rem - 1px);
  543. }
  544. .modal-body {
  545. position: relative;
  546. -ms-flex: 1 1 auto;
  547. flex: 1 1 auto;
  548. padding: 1rem;
  549. }
  550. form {
  551. display: block;
  552. margin-top: 0em;
  553. unicode-bidi: isolate;
  554. }
  555. .modal-content {
  556. position: relative;
  557. display: -ms-flexbox;
  558. display: flex;
  559. -ms-flex-direction: column;
  560. flex-direction: column;
  561. width: 100%;
  562. pointer-events: auto;
  563. background-color: #fff;
  564. background-clip: padding-box;
  565. border: 1px solid rgba(0, 0, 0, .2);
  566. border-radius: 4.8px;
  567. outline: 0;
  568. }
  569. .modal-footer {
  570. display: -ms-flexbox;
  571. display: flex;
  572. -ms-flex-wrap: wrap;
  573. flex-wrap: wrap;
  574. -ms-flex-align: center;
  575. align-items: center;
  576. -ms-flex-pack: end;
  577. justify-content: flex-end;
  578. padding: .75rem;
  579. border-top: 1px solid #dee2e6;
  580. border-bottom-right-radius: calc(.3rem - 1px);
  581. border-bottom-left-radius: calc(.3rem - 1px);
  582. }
  583. h5 {
  584. font-size: 20px !important;
  585. }
  586. .modal.fade .modal-dialog {
  587. transition: -webkit-transform .3s ease-out;
  588. transition: transform .3s ease-out;
  589. transition: transform .3s ease-out, -webkit-transform .3s ease-out;
  590. -webkit-transform: translate(0, -50px);
  591. transform: translate(0, -50px);
  592. }
  593. .modal.show .modal-dialog {
  594. -webkit-transform: none;
  595. transform: none;
  596. }
  597. .modal-dialog {
  598. position: relative;
  599. width: auto;
  600. margin: .5rem;
  601. pointer-events: none;
  602. }
  603. @media (min-width: 576px) {
  604. .modal-dialog {
  605. max-width: 500px;
  606. margin: 1.75rem auto;
  607. }
  608. }
  609. @media (min-width: 992px) {
  610. .modal-lg, .modal-xl {
  611. max-width: 800px;
  612. }
  613. }
  614. label {
  615. display: inline-block;
  616. margin-bottom: .5rem;
  617. }
  618. label {
  619. cursor: default;
  620. }
  621. .form-group {
  622. margin-bottom: 1rem;
  623. }
  624. .custom-file {
  625. position: relative;
  626. display: inline-block;
  627. width: 100%;
  628. height: calc(1.5em + .75rem + 2px);
  629. margin-bottom: 0;
  630. }
  631. input:not([type="image" i], [type="range" i], [type="checkbox" i], [type="radio" i]) {
  632. overflow-clip-margin: 0px !important;
  633. overflow: clip !important;
  634. }
  635. input[type="file" i] {
  636. appearance: none;
  637. background-color: initial;
  638. cursor: default;
  639. align-items: baseline;
  640. color: inherit;
  641. text-overflow: ellipsis;
  642. text-align: start !important;
  643. padding: initial;
  644. border: initial;
  645. white-space: pre;
  646. }
  647. input {
  648. font-style: ;
  649. font-variant-ligatures: ;
  650. font-variant-caps: ;
  651. font-variant-numeric: ;
  652. font-variant-east-asian: ;
  653. font-variant-alternates: ;
  654. font-variant-position: ;
  655. font-weight: ;
  656. font-stretch: ;
  657. font-size: ;
  658. font-family: ;
  659. font-optical-sizing: ;
  660. font-size-adjust: ;
  661. font-kerning: ;
  662. font-feature-settings: ;
  663. font-variation-settings: ;
  664. text-rendering: auto;
  665. color: fieldtext;
  666. letter-spacing: normal;
  667. word-spacing: normal;
  668. line-height: normal;
  669. text-transform: none;
  670. text-indent: 0px;
  671. text-shadow: none;
  672. display: inline-block;
  673. text-align: start;
  674. appearance: auto;
  675. -webkit-rtl-ordering: logical;
  676. cursor: text;
  677. background-color: field;
  678. margin: 0em;
  679. padding: 1px 0px;
  680. border-width: 2px;
  681. border-style: inset;
  682. border-color: light-dark(rgb(118, 118, 118), rgb(133, 133, 133));
  683. border-image: initial;
  684. padding-block: 1px;
  685. padding-inline: 2px;
  686. }
  687. .text-muted {
  688. color: #6c757d !important;
  689. }
  690. .text-truncate {
  691. overflow: hidden;
  692. text-overflow: ellipsis;
  693. white-space: nowrap;
  694. }
  695. file-label, .custom-select {
  696. transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
  697. }
  698. .custom-select {
  699. display: inline-block;
  700. width: 100%;
  701. height: calc(1.5em + .75rem + 2px);
  702. padding: .375rem 1.75rem .375rem .75rem;
  703. font-size: 14px;
  704. font-weight: 400;
  705. line-height: 1.5;
  706. color: #495057;
  707. vertical-align: middle;
  708. border: 1px solid #ced4da;
  709. border-radius: .25rem;
  710. -webkit-appearance: none;
  711. -moz-appearance: none;
  712. appearance: none;
  713. }
  714. .form-control {
  715. display: block;
  716. width: 100%;
  717. height: calc(1.5em + .75rem + 2px);
  718. padding: .375rem .75rem;
  719. font-size: 14px;
  720. font-family: Roboto, sans-serif;
  721. font-weight: 400;
  722. line-height: 1.5;
  723. color: #495057;
  724. background-color: #fff;
  725. background-clip: padding-box;
  726. border: 1px solid #ced4da;
  727. border-radius: .25rem;
  728. transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
  729. }
  730. select {
  731. word-wrap: normal;
  732. }
  733. .custom-file-label {
  734. position: absolute;
  735. top: 0;
  736. right: 0;
  737. left: 0;
  738. z-index: 1;
  739. height: calc(1.5em + .75rem + 2px);
  740. padding: .375rem .75rem;
  741. overflow: hidden;
  742. font-weight: 400;
  743. line-height: 1.5;
  744. color: #495057;
  745. background-color: #fff;
  746. border: 1px solid #ced4da;
  747. border-radius: .25rem;
  748. }
  749. .custom-file-label::after {
  750. position: absolute;
  751. top: 0;
  752. right: 0;
  753. bottom: 0;
  754. z-index: 3;
  755. display: block;
  756. height: calc(1.5em + .75rem);
  757. padding: .375rem .75rem;
  758. line-height: 1.5;
  759. color: #495057;
  760. content: "Browse";
  761. background-color: #e9ecef;
  762. border-left: inherit;
  763. border-radius: 0 .25rem .25rem 0;
  764. }
  765. .alert-warning {
  766. color: #856404;
  767. background-color: #fff3cd;
  768. border-color: #ffeeba;
  769. }
  770. .alert {
  771. position: relative;
  772. padding: .75rem 1.25rem;
  773. margin-bottom: 1rem;
  774. border: 1px solid transparent;
  775. border-radius: .25rem;
  776. }
  777. option {
  778. font-weight: normal;
  779. display: block;
  780. padding-block-start: 0px;
  781. padding-block-end: 1px;
  782. min-block-size: 1.2em;
  783. padding-inline: 2px;
  784. white-space: nowrap;
  785. }
  786. .modal-backdrop.fade {
  787. opacity: 0;
  788. }
  789. .modal-backdrop.show {
  790. opacity: .5;
  791. }
  792. .modal-backdrop {
  793. position: fixed;
  794. top: 0;
  795. left: 0;
  796. z-index: 1040;
  797. width: 100vw;
  798. height: 100vh;
  799. background-color: #000;
  800. }
  801. `;
  802.  
  803. GM_addStyle(css);
  804.  
  805. let contestStartTime = -1;
  806. // let contestStartTime = 1726755078;
  807. let blueLine;
  808. let submissionResult;
  809. let contestProblems, contestProblemName, gymRound;
  810. let teamname, rank, penalty, score;
  811. let problemStatus = {};
  812. let timerInterval;
  813. let submitForm;
  814. let contestLength = 18000;
  815.  
  816. function getCurrentURL () {
  817. return window.location.href;
  818. }
  819.  
  820. function parseLanguage(language){
  821. if(language.startsWith('C++')){
  822. return "CPP";
  823. }
  824. if(language.startsWith('Py')){
  825. return "PY3";
  826. }
  827. return language;
  828. }
  829.  
  830. function parseVerdict(verdict){
  831. if(verdict == "OK") return "CORRECT";
  832. if(verdict == "WRONG_ANSWER") return "WRONG-ANSWER";
  833. if(verdict == "TIME_LIMIT_EXCEEDED") return "TIMELIMIT";
  834. if(verdict == "RUNTIME_ERROR") return "RUN-ERROR";
  835. if(verdict == "MEMORY_LIMIT_EXCEEDED") return "RUN-ERROR";
  836. if(verdict == "COMPILATION_ERROR") return "COMPILER-ERROR";
  837. if(verdict == "TESTING") return "PENDING";
  838. return "PENDING";
  839. }
  840.  
  841. function parseSubmission(result){
  842. submissionResult = [];
  843. for(let submission of result){
  844. if(contestStartTime <= submission.creationTimeSeconds && submission.creationTimeSeconds - contestStartTime < contestLength){
  845. const date = new Date(submission.creationTimeSeconds * 1000);
  846. submissionResult.push({
  847. index: submission.problem.index,
  848. verdict: parseVerdict(submission.verdict),
  849. time: date.getHours().toString().padStart(2, '0')+":"+date.getMinutes().toString().padStart(2, '0'),
  850. submitMinute: Math.floor(submission.relativeTimeSeconds/60),
  851. language: parseLanguage(submission.programmingLanguage)
  852. });
  853. }
  854. }
  855. const reversedSubmissionResult = submissionResult.slice().reverse();
  856. for(let submission of reversedSubmissionResult){
  857. if(submission.index in problemStatus){
  858. if(submission.verdict == "CORRECT"){
  859. if(problemStatus[submission.index].passtime == -1)
  860. problemStatus[submission.index].passtime = submission.submitMinute;
  861. }
  862. else if(submission.verdict == "PENDING"){
  863. problemStatus[submission.index].pendingNumber = problemStatus[submission.index].pendingNumber+1;
  864. if(problemStatus[submission.index].pending == -1)
  865. problemStatus[submission.index].pending = submission.submitMinute;
  866. }
  867. else{
  868. problemStatus[submission.index].rejected = problemStatus[submission.index].rejected + (submission.verdict == "COMPILER-ERROR" ? 0 : 1);
  869. }
  870. }
  871. else{
  872. let newStatus;
  873. if(submission.verdict == "PENDING"){
  874. newStatus = {
  875. rejected: 0,
  876. passtime: -1,
  877. pending: submission.submitMinute,
  878. pendingNumber: 1
  879. }
  880. }
  881. else if(submission.verdict != "CORRECT"){
  882. newStatus = {
  883. rejected: submission.verdict == "COMPILER-ERROR" ? 0 : 1,
  884. passtime: -1,
  885. pending: -1,
  886. pendingNumber: 0
  887. }
  888. }
  889. else{
  890. newStatus = {
  891. rejected: 0,
  892. passtime: submission.submitMinute,
  893. pending: -1,
  894. pendingNumber: 0
  895. }
  896. }
  897. problemStatus[submission.index] = newStatus;
  898. }
  899. }
  900. }
  901.  
  902. async function getApiData () {
  903. domjudgeView();
  904. gymRound = getCurrentURL().split('/')[4];
  905. // console.log(gymRound);
  906.  
  907. let links = document.querySelectorAll('a'), username;
  908. // 取得 username
  909. for (let link of links) {
  910. if (link.href.includes('/profile/')) {
  911. username = link.href.split('/')[4];
  912. break;
  913. }
  914. }
  915.  
  916. const SubmissionApiURL = 'https://codeforces.com/api/contest.status?contestId=' + gymRound + '&handle=' + username;
  917. // console.log(SubmissionApiURL);
  918.  
  919. await fetch(SubmissionApiURL)
  920. .then(response => response.json()) // 將回應轉為 JSON 格式
  921. .then(data => {
  922. if (data.result && data.result.length > 0) {
  923. if("startTimeSeconds" in data.result[0].author)
  924. contestStartTime = data.result[0].author.startTimeSeconds;
  925. parseSubmission(data.result);
  926. // return data.result[0].creationTimeSeconds;
  927. } else {
  928. console.log("No result found in Submission API response");
  929. }
  930. })
  931. .then(() => drawHeader())
  932. .catch(error => {
  933. console.error("Error fetching API:", error);
  934. });
  935.  
  936. const ContestApiURL = 'https://codeforces.com/api/contest.standings?contestId=' + gymRound + '&from=1&showUnofficial=true';
  937. // console.log(ContestApiURL);
  938.  
  939. await fetch(ContestApiURL)
  940. .then(response => response.json()) // 將回應轉為 JSON 格式
  941. .then(data => {
  942. if (data.result) {
  943. contestLength = data.result.contest.durationSeconds;
  944.  
  945. contestProblems = [];
  946. for(let problem of data.result.problems){
  947. contestProblems.push(problem.index);
  948. }
  949.  
  950. contestProblemName = [];
  951. for(let problem of data.result.problems){
  952. contestProblemName.push(problem.index + " - " + problem.name);
  953. }
  954.  
  955. for(let team of data.result.rows){
  956. if(team.party.members.some(item => item.handle === username)){
  957. penalty = team.penalty;
  958. rank = team.rank;
  959. score = team.points;
  960. if("teamName" in team.party)
  961. teamname = team.party.teamName;
  962. else
  963. teamname = username;
  964. break;
  965. }
  966. }
  967. } else {
  968. console.log("No result found in Contest API response");
  969. }
  970. })
  971. .then(() => drawTimeLine())
  972. .then(() => updateTimeLine())
  973. .then(() => drawTeamsSummary())
  974. .then(() => drawSubmission())
  975. .then(() => addSubmitPage())
  976. .then(() => submitButtomJquery());
  977. // .catch(error => {
  978. // console.error("Error fetching API:", error);
  979. // });
  980.  
  981. timerInterval = setInterval(updateTimer, 1000);
  982. }
  983.  
  984. function updateTimeLine(){
  985. if(contestStartTime == -1) return;
  986. // console.log((Date.now() / 1000 - contestStartTime), contestLength);
  987. let contestDuringPrecentage = (Date.now() / 1000 - contestStartTime) / contestLength;
  988. // contestDuringPrecentage = Math.random();
  989. if(contestDuringPrecentage > 1) {
  990. return;
  991. }
  992. let pageWidth = window.innerWidth;
  993. let blueLineWidth = contestDuringPrecentage * pageWidth;
  994. blueLine.style.width = blueLineWidth + 'px'; // 設定寬度
  995. }
  996.  
  997. function addFontAwesome(){
  998. // 獲取頁面中的 <header> 元素
  999. let header = document.querySelector('head');
  1000.  
  1001. // 創建一個新的 <script> 元素
  1002. let scriptElement = document.createElement('script');
  1003.  
  1004. // 設置 <script> 標籤的屬性
  1005. scriptElement.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"
  1006. scriptElement.type = "text/javascript";
  1007.  
  1008. let linkElement = document.createElement('link');
  1009.  
  1010. // 設置 <link> 標籤的屬性
  1011. linkElement.href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css";
  1012. linkElement.rel = "stylesheet";
  1013. linkElement.type = "text/css";
  1014. //linkElement.type = "text/javascript";
  1015.  
  1016. // 將 <link> 標籤添加到 <head> 中
  1017.  
  1018.  
  1019. // 將 <script> 元素添加到 <header> 中
  1020. if (header) {
  1021. header.appendChild(scriptElement);
  1022. header.appendChild(linkElement);
  1023. }
  1024. }
  1025. function drawTimeLine(){
  1026. if(contestStartTime == -1) return;
  1027. let contestDuringPrecentage = (Date.now() / 1000 - contestStartTime) / contestLength;
  1028. // contestDuringPrecentage = 0.5;
  1029. if(contestDuringPrecentage > 1) {
  1030. return;
  1031. }
  1032. let pageWidth = window.innerWidth;
  1033. let blueLineWidth = contestDuringPrecentage * pageWidth;
  1034.  
  1035. blueLine = document.createElement('div');
  1036. blueLine.style.position = 'absolute';
  1037. blueLine.style.bottom = '0';
  1038. blueLine.style.left = '0';
  1039. blueLine.style.height = '5.5px'; // 可以調整高度
  1040. blueLine.style.backgroundColor = '#0079ff';
  1041. blueLine.style.zIndex = '9999'; // 保證藍線在最上層
  1042. blueLine.style.width = blueLineWidth + 'px'; // 設定寬度
  1043. document.querySelector('nav').appendChild(blueLine);
  1044.  
  1045. }
  1046.  
  1047. function drawHeader(){
  1048. document.getElementById('body').style.margin = "0";
  1049.  
  1050. // 選擇所有的 <a> 元素
  1051. let links = document.querySelectorAll('a');
  1052. let LogoutLink;
  1053.  
  1054. // 遍歷每個 <a>,檢查其 innerHTML 是否包含 "Logout"
  1055. links.forEach(link => {
  1056. if (link.innerHTML.includes('Logout')) {
  1057. // console.log(link); // 找到的 <a> 元素會被輸出到控制台
  1058. LogoutLink = link;
  1059. }
  1060. });
  1061.  
  1062. document.getElementById('header').remove();
  1063. document.querySelector('.menu-list-container').remove();
  1064. document.querySelector('.menu-box').remove();
  1065. document.querySelector('.alert-success').remove();
  1066.  
  1067. let baseUrl = getCurrentURL().split('/').slice(0, 5).join('/');
  1068.  
  1069. let navElement = document.createElement('nav');
  1070. navElement.classList.add('navbar','navbar-expand-md','navbar-dark','bg-dark','fixed-top');
  1071.  
  1072. let navHTML = "";
  1073.  
  1074. navHTML = `<a class="navbar-brand hidden-sm-down" href="${baseUrl}/submit">DOMjudge</a>`;
  1075.  
  1076. navHTML += '<div class="collapse navbar-collapse" id="menuDefault">';
  1077. navHTML += '<ul class="navbar-nav mr-auto">';
  1078. navHTML += `<li class="nav-item active"><a class="nav-link" href="${baseUrl}/submit"><i class="fas fa-home"></i> Home </a></li>`;
  1079. navHTML += `<li class="nav-item"><a class="nav-link" href="${baseUrl}"><i class="fas fa-book-open"></i> Problemset </a></li>`;
  1080. navHTML += `<li class="nav-item"><a class="nav-link" href="${baseUrl}/standings"><i class="fas fa-list-ol"></i> Scoreboard </a></li>`;
  1081.  
  1082. navHTML += '</ul>';
  1083. navHTML += '<div id="submitbut"><a id="submitLink" class="nav-link justify-content-center" data-ajax-modal="" data-ajax-modal-after="initSubmitModal" href="#"><span class="btn btn-success btn-sm"><i class="fas fa-cloud-upload-alt"></i> Submit</span></a></div>';
  1084. navHTML += `<a class="btn btn-info btn-sm justify-content-center" href="${LogoutLink}" onclick="return confirmLogout();"><i class="fas fa-sign-out-alt"></i> Logout</a>`;
  1085. navHTML += `<div class="navbar-text" style="white-space:nowrap;"><span style="padding-left: 10px;"><i class="fas fa-clock loading-indicator"></i></span><span id="timeleft"> contest over</span></div>`;
  1086. navHTML += '</div>';
  1087.  
  1088. navElement.innerHTML = navHTML;
  1089.  
  1090. let bodyDiv = document.getElementById('body');
  1091. bodyDiv.insertBefore(navElement, bodyDiv.firstChild);
  1092. }
  1093.  
  1094. function updateTimer(){
  1095. if(Math.floor(Date.now()/1000) - contestStartTime > contestLength){
  1096. document.getElementById("timeleft").innerHTML = " contest over";
  1097. clearInterval(timerInterval); // 倒數結束時停止計時
  1098. }
  1099. else{
  1100. let leftSecond = contestLength - (Math.floor(Date.now()/1000) - contestStartTime);
  1101. let minutes = (Math.floor((leftSecond%3600)/60));
  1102. let seconds = leftSecond%60;
  1103. let displayMinutes = minutes < 10 ? '0' + minutes : minutes;
  1104. let displaySeconds = seconds < 10 ? '0' + seconds : seconds;
  1105. if(leftSecond > 3600)
  1106. document.getElementById("timeleft").innerHTML = " " + Math.floor(leftSecond/3600).toString() + ":" + displayMinutes + ":" + displaySeconds;
  1107. else
  1108. document.getElementById("timeleft").innerHTML = " " + displayMinutes + ":" + displaySeconds;
  1109. }
  1110. }
  1111.  
  1112. function drawTeamsSummary(){
  1113. // console.log(contestProblems);
  1114.  
  1115. let tableHTML = '<table class="summary-table center">';
  1116.  
  1117. // Table Header
  1118. tableHTML += '<colgroup><col id="scorerank"><col id="scoreteamname"></colgroup>';
  1119. tableHTML += '<colgroup><col id="scoresolv"><col id="scoretotal"></colgroup>';
  1120. tableHTML += '<colgroup>';
  1121. for(let i = 0; i < contestProblems.length; i++){
  1122. tableHTML += '<col class="scoreprob"';
  1123. }
  1124. tableHTML += '</colgroup>';
  1125. tableHTML += '<thead><tr class="summary-table-header">';
  1126. tableHTML += '<th title="rank" scope="col">rank</th>';
  1127. tableHTML += '<th title="team name" scope="col" colspan="3">team</th>';
  1128. tableHTML += '<th title="# solved / penalty time" colspan="2" scope="col">score</th>';
  1129. // tableHTML += '<th style="text-align: center;">score</th>';
  1130. contestProblems.forEach(problemIndex => {
  1131. const linkURL = `https://codeforces.com/gym/${gymRound}/problem/${problemIndex.toString()}`;
  1132. tableHTML += `<th title="" scope="col"><a href="${linkURL}" target="_blank"><span class="badge problem-badge" style="min-width: 28px; border: 1px solid"><span style="color: #000000;">${problemIndex}</span></span></a></th>`;
  1133. });
  1134. tableHTML += '</tr></thead><tbody>';
  1135.  
  1136. tableHTML += '<tr class="sortorderswitch">';
  1137. tableHTML += `<td class="scorepl">${rank}</td>`;
  1138. tableHTML += `<td class="scoreaf"> </td>`;
  1139. tableHTML += `<td class="scoreaf"> </td>`;
  1140. tableHTML += `<td class="scoretn">${teamname}</td>`;
  1141. // tableHTML += `<td class="score-penalty-table"><div>${score}</div><div>${penalty}</div></td>`;
  1142. tableHTML += `<td class="scorenc">${score}</td>`;
  1143. tableHTML += `<td class="scorett">${penalty}</td>`;
  1144.  
  1145. contestProblems.forEach(problemIndex => {
  1146. if(!(problemIndex in problemStatus))
  1147. tableHTML += `<td class="score_cell"></td>`;
  1148. else if(problemStatus[problemIndex].passtime != -1){
  1149. // console.log(problemIndex, problemStatus[problemIndex].passtime, problemStatus[problemIndex].pending, problemStatus[problemIndex].pendingNumber);
  1150. if(problemStatus[problemIndex].passtime > problemStatus[problemIndex].pending && problemStatus[problemIndex].pendingNumber != 0){
  1151. const tryTime = problemStatus[problemIndex].rejected;
  1152. const tryString = tryTime.toString() + " + " + (problemStatus[problemIndex].pendingNumber).toString() + " tries";
  1153. tableHTML += `<td class="score_cell"><a><div style="background:#6666FF">&nbsp;<span>${tryString}</span></div></a></td>`;
  1154. }
  1155. else{
  1156. const tryTime = problemStatus[problemIndex].rejected+1;
  1157. const tryString = tryTime.toString() + (tryTime > 1 ? " tries" : " try");
  1158. tableHTML += `<td class="score_cell"><a><div style="background:#60e760">${problemStatus[problemIndex].passtime}<span>${tryString}</span></div></a></td>`;
  1159. }
  1160. }
  1161. else if(problemStatus[problemIndex].pendingNumber != 0){
  1162. const tryTime = problemStatus[problemIndex].rejected;
  1163. const tryString = tryTime.toString() + " + " + (problemStatus[problemIndex].pendingNumber).toString() + " tries";
  1164. tableHTML += `<td class="score_cell"><a><div style="background:#6666FF">&nbsp;<span>${tryString}</span></div></a></td>`;
  1165. }
  1166. else{
  1167. const tryTime = problemStatus[problemIndex].rejected;
  1168. const tryString = tryTime.toString() + (tryTime > 1 ? " tries" : " try");
  1169. tableHTML += `<td class="score_cell"><a><div style="background:#e87272">&nbsp;<span>${tryString}</span></div></a></td>`;
  1170. }
  1171.  
  1172. });
  1173. tableHTML += '</tr>';
  1174.  
  1175. tableHTML += '</tbody></table>';
  1176.  
  1177. submitForm = document.getElementById('pageContent').getElementsByTagName('form')[0];
  1178.  
  1179. document.getElementById('pageContent').innerHTML = tableHTML;
  1180.  
  1181. }
  1182. function drawSubmission(){
  1183. let tableHTML = '<div class="row><div class="col">';
  1184.  
  1185. tableHTML += '<h1 class="teamoverview">Submissions</h1>';
  1186. tableHTML += '<table class="data-table table table-hover table-striped table-sm submissions-table">'
  1187.  
  1188. tableHTML += '<thead class="thead-light"><tr><th scope="col">time</th><th scope="col">problem</th><th scope="col">lang</th><th scope="col">result</th></tr></thead>';
  1189.  
  1190. tableHTML += '<tbody>';
  1191.  
  1192. submissionResult.forEach(Submission =>{
  1193. tableHTML += '<tr class>';
  1194. tableHTML += `<td>${Submission.time}</td>`;
  1195. tableHTML += `<td class="probid"><a><span class="badge problem-badge" style="min-width: 28px;border: 1px solid #7293a8";><span>${Submission.index}</span></span><a></td>`;
  1196. tableHTML += `<td class="langid"><a>${Submission.language}</a></td>`;
  1197. if(Submission.verdict == "CORRECT")
  1198. tableHTML += `<td class="sol sol_correct"><a>${Submission.verdict}</a></td>`;
  1199. else if(Submission.verdict == "PENDING")
  1200. tableHTML += `<td class="sol sol_queued"><a>${Submission.verdict}</a></td>`;
  1201. else
  1202. tableHTML += `<td class="sol sol_incorrect"><a>${Submission.verdict}</a></td>`;
  1203. tableHTML += '</tr>';
  1204. });
  1205.  
  1206. tableHTML += '</tbody></table>';
  1207. tableHTML += '</div></div>';
  1208.  
  1209. document.getElementById('pageContent').innerHTML += tableHTML;
  1210. document.getElementById('sidebar').innerHTML = "";
  1211. }
  1212.  
  1213. addFontAwesome();
  1214. getApiData();
  1215.  
  1216. function domjudgeView() {
  1217. // 遍歷所有的文本節點
  1218. let walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
  1219. let node, nextNode;
  1220.  
  1221. while (node = walker.nextNode()) {
  1222. // 檢查節點是否包含 'on test'
  1223. let textContent = node.nodeValue;
  1224. let index = textContent.indexOf(' ON TEST');
  1225.  
  1226. if (index !== -1) {
  1227. // 刪除 'on test' 及其後面的所有內容
  1228. node.nodeValue = textContent.substring(0, index);
  1229. nextNode = walker.nextNode();
  1230. nextNode.nodeValue = "";
  1231. }
  1232. else{
  1233. let pretestIndex = textContent.indexOf(' ON PRETEST');
  1234. if (pretestIndex !== -1) {
  1235. // 刪除 'on pretest' 及其後面的所有內容
  1236. node.nodeValue = textContent.substring(0, pretestIndex);
  1237. nextNode = walker.nextNode();
  1238. nextNode.nodeValue = "";
  1239. }
  1240. }
  1241. }
  1242. }
  1243.  
  1244. domjudgeView();
  1245.  
  1246. // 監聽 DOM 的變化以處理動態更新的內容
  1247. const observer = new MutationObserver((mutations) => {
  1248. mutations.forEach((mutation) => {
  1249. // 針對新增的節點,重新執行移除操作
  1250. if (mutation.addedNodes.length) {
  1251. // chrome.storage.sync.get(['featureEnabled'], function (result) {
  1252. // if (result.featureEnabled) {
  1253. // domjudgeView();
  1254. // updateTimeLine();
  1255. // }
  1256. // });
  1257. domjudgeView();
  1258. updateTimeLine();
  1259. }
  1260. });
  1261. });
  1262.  
  1263. // 配置監聽器參數
  1264. const observerConfig = {
  1265. childList: true, // 監聽子節點變動
  1266. subtree: true, // 監聽整個子樹
  1267. characterData: true // 監聽文字內容變動
  1268. };
  1269.  
  1270. // 啟動監聽器
  1271. observer.observe(document.body, observerConfig);
  1272.  
  1273. function humanReadableTimeDiff(seconds) {
  1274. var intervals = [
  1275. ['years', 365 * 24 * 60 * 60],
  1276. ['months', 30 * 24 * 60 * 60],
  1277. ['days', 24 * 60 * 60],
  1278. ['hours', 60 * 60],
  1279. ['minutes', 60],
  1280. ];
  1281. for (let [name, length] of intervals) {
  1282. if (seconds / length >= 2) {
  1283. return Math.floor(seconds/length) + ' ' + name;
  1284. }
  1285. }
  1286. return Math.floor(seconds) + ' seconds';
  1287. }
  1288.  
  1289. function humanReadableBytes(bytes) {
  1290. var sizes = [
  1291. ['GB', 1024*1024*1024],
  1292. ['MB', 1024*1024],
  1293. ['KB', 1024],
  1294. ];
  1295. for (let [name, length] of sizes) {
  1296. if (bytes / length >= 2) {
  1297. return Math.floor(bytes/length) + name;
  1298. }
  1299. }
  1300. return Math.floor(bytes) + 'B';
  1301. }
  1302.  
  1303. function addSubmitPage(){
  1304. // 創建模態框的 HTML
  1305.  
  1306. let submitTable = submitForm.querySelector('tbody');
  1307. let rows = submitTable.querySelectorAll('tr');
  1308.  
  1309. submitTable.insertBefore(rows[4], rows[0]);
  1310. submitTable.removeChild(rows[3]);
  1311.  
  1312. submitForm.querySelector('.field-name').innerHTML = "Source files";
  1313. submitForm.querySelector('.programTypeNotice').remove();
  1314. submitForm.querySelector('.outputOnlyProgramTypeIdNotice').remove();
  1315. submitForm.querySelector(".error__submittedProblemIndex").remove();
  1316.  
  1317. let submitButInput = submitTable.querySelector(".submit");
  1318. let buttonElement = document.createElement("button");
  1319. buttonElement.id = submitButInput.id;
  1320. buttonElement.type = submitButInput.type;
  1321. buttonElement.className = submitButInput.className;
  1322. buttonElement.innerHTML = `<i class="fas fa-cloud-upload-alt"></i> Submit `;
  1323. // submitTable.replaceChild(buttonElement, submitButInput);
  1324.  
  1325. buttonElement.classList.add('btn');
  1326. buttonElement.classList.add('btn-success');
  1327.  
  1328.  
  1329. const allowedLanguage = ["43", "89", "87", "31"];
  1330. const languageName = ["C", "CPP", "JAVA", "PYTHON3"];
  1331.  
  1332. const selectElement = submitForm.querySelector('select[name="programTypeId"]');
  1333. Array.from(selectElement.options).forEach(option => {
  1334. if (!allowedLanguage.includes(option.value)) {
  1335. option.remove();
  1336. }
  1337. else{
  1338. for(let i = 0; i < allowedLanguage.length; i++){
  1339. if(allowedLanguage[i] == option.value){
  1340. option.innerHTML = languageName[i];
  1341. option.removeAttribute('selected');
  1342. break;
  1343. }
  1344. }
  1345. }
  1346. });
  1347.  
  1348. const noLanguageOption = document.createElement('option');
  1349. noLanguageOption.value = "0";
  1350. noLanguageOption.text = "Select a language";
  1351. noLanguageOption
  1352. selectElement.insertBefore(noLanguageOption, selectElement.firstChild);
  1353.  
  1354. // console.log(submitForm.outerHTML);
  1355.  
  1356. // <span class="close">&times;</span>
  1357.  
  1358. submitForm.querySelector('select[name="submittedProblemIndex"]').querySelector('option[value=""]').remove();
  1359. let submit_problem_option = submitForm.querySelector('select[name="submittedProblemIndex"]').innerHTML;
  1360. let csrf_token_input = submitForm.querySelector('input[name="csrf_token"]').outerHTML;
  1361. // console.log(submit_problem_option);
  1362.  
  1363. const modalHTML = `<div id="myModal" class="modal fade show" tabindex="-1" role="dialog" aria-modal="true" style="display: none;">
  1364. <div class="modal-dialog modal-lg" role="document"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Submit</h5><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button></div>
  1365. <form class="submit-form" name="csrf_token" method="post" action="/team/submit" enctype="multipart/form-data">`
  1366. + csrf_token_input +
  1367. `<input type="hidden" name="ftaa" value="">
  1368. <input type="hidden" name="bfaa" value="">
  1369. <input type="hidden" name="action" value="submitSolutionFormSubmitted">
  1370. <div class="modal-body">
  1371. <div class="form-group"><label for="submit_problem_code" class="required">Source files</label><div class="custom-file"><input type="file" id="submit_problem_code" name="sourceFile" required="required" class="custom-file-input custom-file-input"><label class="custom-file-label text-truncate text-muted" for="submit_problem_code">No file selected</label></div></div>
  1372. <div class="alert alert-warning" id="files_not_modified" style="display:none;"></div>
  1373. <div class="form-group"><label class="required" for="submit_problem_problem">Problem</label><select id="submit_problem_problem" name="submittedProblemIndex" required="required" class="form-control custom-select form-control"><option value="" selected="selected">Select a problem</option>` + submit_problem_option + `</select></div>
  1374. <div class="form-group"><label class="required" for="submit_problem_language">Language</label><select id="submit_problem_language" name="programTypeId" required="required" class="form-control custom-select form-control"><option value="" selected="selected">Select a language</option><option value="43">C</option><option value="89">C++</option><option value="87">Java</option><option value="31">Python 3</option></select></div></div>
  1375. <div class="modal-footer"><button id="cancelBtn" type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button><button type="submit" class="btn-success btn"><i class="fas fa-cloud-upload-alt"></i> Submit </button></div><input type="hidden" name="_tta" value="396"></form></div></div>
  1376. </div>`;
  1377.  
  1378. // 插入模態框到頁面中
  1379. document.body.insertAdjacentHTML('beforeend', modalHTML);
  1380.  
  1381. $(function () {
  1382. $('body').on('change', '.custom-file-input', function () {
  1383. var files = this.files;
  1384. var fileNames = [];
  1385. for (var i = 0; i < files.length; i++) {
  1386. fileNames.push(files.item(i).name);
  1387. }
  1388. $(this).next('.custom-file-label').html(fileNames.join(", "));
  1389. $(this).next('.custom-file-label').removeClass('text-muted');
  1390. });
  1391. });
  1392.  
  1393. const fileInput = document.getElementById('submit_problem_code');
  1394. fileInput.addEventListener('change', (event) => {
  1395.  
  1396. const five_minutes_in_ms = 5 * 60 * 1000;
  1397. const now = Date.now();
  1398. const filesNotModified = document.getElementById('files_not_modified');
  1399. filesNotModified.style.display = 'none';
  1400.  
  1401. var atLeastOneFileRecent = false;
  1402. var fileInfoHtml = '';
  1403. const files = event.target.files;
  1404. for (let file of files) {
  1405. const date = new Date(file.lastModified);
  1406. const ago = humanReadableTimeDiff((now - date)/1000) + ' ago';
  1407. if (date > now - five_minutes_in_ms) {
  1408. atLeastOneFileRecent = true;
  1409. }
  1410. let size = humanReadableBytes(file.size);
  1411. fileInfoHtml += `<li><span class="filename">${file.name}</span>, ${size}, last modified ${ago}</li>`;
  1412. }
  1413. if (!atLeastOneFileRecent) {
  1414. filesNotModified.style.display = 'block';
  1415. filesNotModified.innerHTML =
  1416. 'None of the selected files has been recently modified:' +
  1417. '<ul>' + fileInfoHtml + '</ul>';
  1418. }
  1419. });
  1420.  
  1421. const modal_backdrop_html = `<div class="modal-backdrop fade show" style="display:none;"></div>`;
  1422. document.body.insertAdjacentHTML('beforeend', modal_backdrop_html);
  1423.  
  1424. // 把 input 按鈕換成 button
  1425. // submitButInput = document.getElementById("singlePageSubmitButton");
  1426. // submitButInput.parentNode.insertBefore(buttonElement, submitButInput);
  1427. // submitButInput.remove();
  1428.  
  1429. // 獲取模態框和觸發連結
  1430. const modal = document.getElementById('myModal');
  1431. const openModal = document.getElementById('submitbut');
  1432. const closeModal = document.querySelector('.close');
  1433. const cancelModal = document.getElementById('cancelBtn');
  1434. const modal_backdrop = document.querySelector('.modal-backdrop');
  1435. const filesNotModified = document.getElementById('files_not_modified');
  1436.  
  1437. // 當用戶點擊連結時,顯示模態框
  1438. openModal.addEventListener('click', function(event) {
  1439. event.preventDefault(); // 防止連結跳轉
  1440. modal.style.display = 'block';
  1441. modal_backdrop.style.display = 'block';
  1442. });
  1443.  
  1444. // 當用戶點擊關閉按鈕時,隱藏模態框
  1445. closeModal.addEventListener('click', function() {
  1446. modal.style.display = 'none';
  1447. modal_backdrop.style.display = 'none';
  1448. filesNotModified.style.display = 'none';
  1449. });
  1450.  
  1451. // 當用戶點擊模態框外部時,隱藏模態框
  1452. window.addEventListener('click', function(event) {
  1453. if (event.target === modal) {
  1454. modal.style.display = 'none';
  1455. modal_backdrop.style.display = 'none';
  1456. filesNotModified.style.display = 'none';
  1457. }
  1458. });
  1459.  
  1460. cancelModal.addEventListener('click', function() {
  1461. modal.style.display = 'none';
  1462. modal_backdrop.style.display = 'none';
  1463. filesNotModified.style.display = 'none';
  1464. });
  1465. }
  1466.  
  1467.  
  1468. function getMainExtension(ext) {
  1469. switch (ext) {
  1470. case 'c':
  1471. return '43';
  1472. case 'cpp':
  1473. return '89';
  1474. case 'cc':
  1475. return '89';
  1476. case 'cxx':
  1477. return '89';
  1478. case 'c++':
  1479. return '89';
  1480. case 'java':
  1481. return '87';
  1482. case 'py':
  1483. return '31';
  1484. default:
  1485. return '';
  1486. }
  1487. }
  1488.  
  1489.  
  1490. function submitButtomJquery(){
  1491.  
  1492. $(document).ready(function () {
  1493. {
  1494. }
  1495. var processFile = function () {
  1496. var filename = $('#submit_problem_code').val();
  1497. if (filename !== '' && filename !== undefined) {
  1498. filename = filename.replace(/^.*[\\\/]/, '');
  1499. var parts = filename.split('.').reverse();
  1500. if (parts.length < 2) return;
  1501. var lcParts = [parts[0].toLowerCase(), parts[1].toLowerCase()];
  1502.  
  1503. // language ID
  1504.  
  1505. var language = document.getElementById('submit_problem_language');
  1506. // the "autodetect" option has empty value
  1507. if (language.value !== '') return;
  1508.  
  1509. var langid = getMainExtension(lcParts[0]);
  1510. for (i = 0; i < language.length; i++) {
  1511. if (language.options[i].value === langid) {
  1512. language.selectedIndex = i;
  1513. }
  1514. }
  1515.  
  1516. // Problem ID
  1517.  
  1518. var problem = document.getElementById('submit_problem_problem');
  1519. // the "autodetect" option has empty value
  1520. if (problem.value !== '') {
  1521. return;
  1522. }
  1523.  
  1524. for (var i = 0; i < problem.length; i++) {
  1525. if (problem.options[i].text.split(/ - /)[0].toLowerCase() === lcParts[1]) {
  1526. problem.selectedIndex = i;
  1527. }
  1528. }
  1529. }
  1530. };
  1531. var $body = $('body');
  1532. $body.on('change', '#submit_problem_code', processFile);
  1533. });
  1534.  
  1535. const form = document.querySelector('.submit-form');
  1536.  
  1537. form.addEventListener('submit', function(event) {
  1538. event.preventDefault();
  1539.  
  1540. const formData = new FormData(document.querySelector('.submit-form'));
  1541.  
  1542. // for (const [key, value] of formData.entries()) {
  1543. // console.log(key, value);
  1544. // }
  1545.  
  1546. var langelt = document.getElementById("submit_problem_language");
  1547. var language = langelt.options[langelt.selectedIndex].value;
  1548. var languagetxt = langelt.options[langelt.selectedIndex].text;
  1549. var fileelt = document.getElementById("submit_problem_code");
  1550. var filenames = fileelt.files;
  1551. var filename = filenames[0].name;
  1552. var probelt = document.getElementById("submit_problem_problem");
  1553. var problem = probelt.options[probelt.selectedIndex].value;
  1554. var problemtxt = probelt.options[probelt.selectedIndex].text;
  1555.  
  1556. var error = false;
  1557. if (language === "") {
  1558. langelt.focus();
  1559. langelt.className = langelt.className + " errorfield";
  1560. error = true;
  1561. }
  1562. if (problem === "") {
  1563. probelt.focus();
  1564. probelt.className = probelt.className + " errorfield";
  1565. error = true;
  1566. }
  1567. if (filename === "") {
  1568. error = true;
  1569. }
  1570. if (error) return false;
  1571.  
  1572. var auxfileno = 0;
  1573. // start at one; skip maincode file field
  1574. for (var i = 1; i < filenames.length; i++) {
  1575. if (filenames[i].value !== "") {
  1576. auxfileno++;
  1577. }
  1578. }
  1579. var extrafiles = '';
  1580. if (auxfileno > 0) {
  1581. extrafiles = "Additional source files: " + auxfileno + '\n';
  1582. }
  1583. var question =
  1584. 'Main source file: ' + filename + '\n' +
  1585. extrafiles + '\n' +
  1586. 'Problem: ' + problemtxt + '\n' +
  1587. 'Language: ' + languagetxt + '\n' +
  1588. '\nMake submission?';
  1589. if(confirm(question)){
  1590. fetch(getCurrentURL().split('/').slice(0, 5).join('/')+'/submit?csrf_token='+formData.get('csrf_token'), {
  1591. method: form.method,
  1592. body: formData,
  1593. })
  1594. .then(response => {
  1595. if (response.ok) {
  1596. location.reload();
  1597.  
  1598. } else {
  1599. console.error('submit fail');
  1600. }
  1601. });
  1602. }
  1603. // .catch(error => {
  1604. // console.error('error: ', error);
  1605. // });
  1606. });
  1607. }

QingJ © 2025

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