xmoj-script 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/.github/.config.yml +21 -0
  2. package/.github/ISSUE_TEMPLATE/bug.yml +30 -0
  3. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. package/.github/ISSUE_TEMPLATE/docs.yml +25 -0
  5. package/.github/ISSUE_TEMPLATE/feature.yml +25 -0
  6. package/.github/dependabot.yml +12 -0
  7. package/.github/labeler.yml +12 -0
  8. package/.github/pull_request_template.md +10 -0
  9. package/.github/workflows/AutoLabelIssue.yml +24 -0
  10. package/.github/workflows/AutoLablePR.yml +23 -0
  11. package/.github/workflows/CodeQL.yml +29 -0
  12. package/.github/workflows/Daily.yml +23 -0
  13. package/.github/workflows/DependencyScan.yml +13 -0
  14. package/.github/workflows/Prerelease.yml +43 -0
  15. package/.github/workflows/Release.yml +45 -0
  16. package/.github/workflows/UpdateToRelease.yml +30 -0
  17. package/.github/workflows/UpdateVersion.yml +26 -0
  18. package/.gitmodules +3 -0
  19. package/.vscode/settings.json +148 -0
  20. package/404.html +362 -0
  21. package/AddonScript.js +10 -0
  22. package/CNAME +1 -0
  23. package/CODE_OF_CONDUCT.md +218 -0
  24. package/Compare.md +21 -0
  25. package/Images/1.png +0 -0
  26. package/Images/10.png +0 -0
  27. package/Images/11.png +0 -0
  28. package/Images/12.png +0 -0
  29. package/Images/13.png +0 -0
  30. package/Images/14.png +0 -0
  31. package/Images/15.png +0 -0
  32. package/Images/16.png +0 -0
  33. package/Images/17.png +0 -0
  34. package/Images/2.png +0 -0
  35. package/Images/3.png +0 -0
  36. package/Images/4.png +0 -0
  37. package/Images/5.png +0 -0
  38. package/Images/6.png +0 -0
  39. package/Images/7.png +0 -0
  40. package/Images/8.png +0 -0
  41. package/Images/9.png +0 -0
  42. package/LICENSE +674 -0
  43. package/README.md +86 -0
  44. package/SECURITY.md +12 -0
  45. package/Update/AutoLabel.js +179 -0
  46. package/Update/GetVersion.js +20 -0
  47. package/Update/UpdateToRelease.js +73 -0
  48. package/Update/UpdateVersion.js +80 -0
  49. package/Update/package.json +7 -0
  50. package/Update.json +702 -0
  51. package/XMOJ.png +0 -0
  52. package/XMOJ.user.js +4490 -0
  53. package/backend/.github/.config.yml +21 -0
  54. package/backend/.github/ISSUE_TEMPLATE/bug.yml +30 -0
  55. package/backend/.github/ISSUE_TEMPLATE/config.yml +5 -0
  56. package/backend/.github/ISSUE_TEMPLATE/feature.yml +25 -0
  57. package/backend/.github/dependabot.yml +12 -0
  58. package/backend/.github/labeler.yml +14 -0
  59. package/backend/LICENSE +661 -0
  60. package/backend/README.md +3 -0
  61. package/backend/Source/BBSSpider.js +50 -0
  62. package/backend/Source/Database.ts +188 -0
  63. package/backend/Source/Initial.sql +95 -0
  64. package/backend/Source/Output.ts +14 -0
  65. package/backend/Source/Process.ts +1227 -0
  66. package/backend/Source/Result.ts +24 -0
  67. package/backend/Source/XMOJ-bbs.code-workspace +11 -0
  68. package/backend/Source/index.ts +31 -0
  69. package/backend/bun.lockb +0 -0
  70. package/backend/package.json +19 -0
  71. package/backend/wrangler.toml +17 -0
  72. package/eula.md +121 -0
  73. package/favicon.ico +0 -0
  74. package/index.html +947 -0
  75. package/package.json +22 -0
  76. package/robots.txt +2 -0
  77. package/sitemap-live/0.xml +26 -0
  78. package/sitemap.xml +6 -0
package/XMOJ.user.js ADDED
@@ -0,0 +1,4490 @@
1
+ // ==UserScript==
2
+ // @name XMOJ
3
+ // @version 1.1.1
4
+ // @description XMOJ增强脚本
5
+ // @author @XMOJ-Script-dev, @langningchen and the community
6
+ // @namespace https://github/langningchen
7
+ // @match http://*.xmoj.tech/*
8
+ // @match https://*.xmoj.tech/*
9
+ // @match http://116.62.212.172/*
10
+ // @require https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
11
+ // @require https://cdn.bootcdn.net/ajax/libs/codemirror/6.65.7/codemirror.min.js
12
+ // @require https://cdn.bootcdn.net/ajax/libs/codemirror/6.65.7/mode/clike/clike.min.js
13
+ // @require https://cdn.bootcdn.net/ajax/libs/codemirror/6.65.7/addon/merge/merge.js
14
+ // @require https://cdn.bootcdn.net/ajax/libs/diff_match_patch/20121119/diff_match_patch_uncompressed.js
15
+ // @require https://cdn.bootcdn.net/ajax/libs/dompurify/3.0.2/purify.min.js
16
+ // @require https://cdn.bootcdn.net/ajax/libs/marked/4.3.0/marked.min.js
17
+ // @grant GM_registerMenuCommand
18
+ // @grant GM_xmlhttpRequest
19
+ // @grant GM_setClipboard
20
+ // @grant unsafeWindow
21
+ // @connect api.xmoj-bbs.tech
22
+ // @connect challenges.cloudflare.com
23
+ // @connect cppinsights.io
24
+ // @connect 127.0.0.1
25
+ // @license GPL
26
+ // @icon data:image/x-icon;base64,AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQDmOhEA5gwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQDlGhEA5acSAObREQDl5xIA5WgRAOYEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEgDoAhIA5moSAOW9EgDlNBEA5WYSAOb/EgDm/xEA5tcRAOY8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEA5TISAOa5EgDmaiELxR4jDcNSEQDlZhIA5v8SAOb/EgDm/xEA5pEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARAOUUEQDmnxYD3R4iDcN4IgzC8yMNwpsRAOVmEgDm/xIA5v8SAOb/EQDmkQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiDcNMIg3D2yMNw/8jDcP/Iw3CmxEA5WYSAOb/EgDm/xIA5v8RAOaREwDmCAAA/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiDcMkIwzCtSMNw/8jDcP/Iw3D/yMNw/8jDcKbEQDlZhIA5v8SAOb/EgDm/xEA5ZMRAOU+EQDmrxEA5hgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiDcMMIwzChyMMw/kjDcP/Iw3D/yMNw/8jDcP/Iw3D/yMNwpsRAOVmEgDm/xIA5v8SAOb/EQDlkxEA5j4SAOb/EQDl7RIA5VoAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlDb8AIg3DWiMMwuMjDcP/Iw3D/yMNw/8jDcP/Iw3D/yMNw/8jDcP/Iw3CmxEA5WYSAOb/EgDm/xIA5v8RAOWTEQDmPhIA5v8SAOb/EgDm/xIA5a8RAOYWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgzDMCMMwsEjDcP/Iw3D/yMNw/8jDcP/Iw3D/yMNw/8jDcP/Iw3D/yMNw/8iDcOZEQDlZhIA5v8SAOb/EgDm/xEA5ZMRAOY+EgDm/xIA5v8SAOb/EgDm/xEA5usSAOVYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjDMP5Iw3D/yMNw/8jDcP/Iw3D/yMNw/8jDMLrIwzCtSMNw/8jDcP/Iw3D/yINw5kRAOVmEgDm/xIA5v8SAOb/EQDlkxEA5iwSAOb3EgDm/xIA5v8SAOb/EgDm/xIA5v8SAOUsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMNw/sjDcP/Iw3D/yMNw/8iDcL7IgzDkyIMwxIjDcJiIw3D/yMNw/8jDcP/Ig3DmREA5WYSAOb/EgDm/xIA5v8SAOWTAAAAABIA5ioRAObLEgDm/xIA5v8SAOb/EgDm/xIA5jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIw3D+yMNw/8jDcP/IwzC+SINwyoAAAAAAAAAACMNwmIjDcP/Iw3D/yMNw/8iDcOZEQDlZhIA5v8SAOb/EgDm/xIA5ZMAAAAAAAAAABIA5QQRAObREgDm/xIA5v8SAOb/EgDmMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjDcP7Iw3D/yMNw/8jDMP1AAD/AAAAAAAAAAAAIw3CYiMNw/8jDcP/Iw3D/yINw5kRAOVmEgDm/xIA5v8SAOb/EgDlkwAAAAAAAAAAAAAAABEA5sUSAOb/EgDm/xIA5v8SAOYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMNw/sjDcP/Iw3D/yMMw/UVAOkAAAAAAAAAAAAiDcNgIw3D/yMNw/8jDcP/Ig3DmREA5WYSAOb/EgDm/xIA5v8SAOWTAAAAAAAAAAAAAAAAEQDmxRIA5v8SAOb/EgDm/xIA5jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIw3D+yMNw/8jDcP/Iw3D90AAvwAAAAAAAAAAACINw2AjDcP/Iw3D/yMNw/8iDcOZEQDlZhIA5v8SAOb/EgDm/xIA5ZMAAAAAAAAAAAAAAAARAObDEgDm/xIA5v8SAOb/EgDmMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjDcP7Iw3D/yMNw/8jDcP3QAC/AAAAAAAAAAAAIg3DYCMNw/8jDcP/Iw3D/yINw5kRAOVmEgDm/xIA5v8SAOb/EgDmlQAAAAAAAAAAAAAAABEA5sMSAOb/EgDm/xIA5v8SAOYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMNw/sjDcP/Iw3D/yMNw/dAAL8AAAAAAAAAAAAiDcNgIw3D/yMNw/8jDcP/Ig3DmREA5WYSAOb/EgDm/xIA5v8SAOaVAAAAAAAAAAAAAAAAEQDmwxIA5v8SAOb/EgDm/xIA5jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIw3D+yMNw/8jDcP/IwzD+SMMwxgAAAAAAAAAACINw2AjDcP/Iw3D/yMNw/8iDcOZEQDlZhIA5v8SAOb/EgDm/xIA5pUAAAAAAAAAABIA5goRAObTEgDm/xIA5v8SAOb/EgDmMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjDcP7Iw3D/yMNw/8jDcP/IwzD6yINwlYAAAAAIg3DYCMNw/8jDcP/Iw3D/yINw5kRAOVmEgDm/xIA5v8SAOb/EgDmlRYA6AARAOZYEQDl4RIA5v8SAOb/EgDm/xIA5v8SAOYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMNw/sjDcP/Iw3D/yMNw/8jDcP/Iw3D/yINw2AjDMNeIw3D/yMNw/8jDcP/Ig3DmREA5WYSAOb/EgDm/xIA5v8SAOW7EQDmwxIA5v8SAOb/EgDm/xIA5v8SAOb/EgDm/xIA5jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIg3CUiINw+kjDcP/Iw3D/yMNw/8jDcP/Ig3DciMMw14jDcP/Iw3D/yMNw/8iDcOZEQDlZhIA5v8SAOb/EgDm/xIA5v8SAOb/EgDm/xIA5v8SAOb/EgDm/xIA5usRAOVmEgDoAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIg3DFCMMw6kjDcP/Iw3D/yMNw/8iDcNyIwzDXiMNw/8jDcP/Iw3D/yINw5kRAOVmEgDm/xIA5v8SAOb/EgDm/xIA5v8SAOb/EgDm/xIA5fsSAOaVEQDlEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIMw1QiDMPpIw3D/yINw3IjDMNeIw3D/yMNw/8jDcP/Ig3DmREA5WYSAOb/EgDm/xIA5v8SAOb/EgDm/xIA5v8RAObBEgDlLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMMwhYiDcKrIg3DciMMw14jDcP/Iw3D/yMNw/8iDcOZEQDmZhIA5v8SAOb/EgDm/xIA5v8SAOXjEQDmWA4A4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiDMISIg3CXCMNw/8jDcP/Iw3D/yINw5kRAOZmEgDm/xIA5v8RAOb3EQDlhxEA5gwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiDcJcIw3D/yMNw/8jDcP/Ig3DmREA5mYSAOb/EQDmsxIA5SQiDMJOIg3CNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACINwlwjDcP/Iw3D/yMNw/8iDcOZEQDlSBIA5koiDMIiIwzCrSINw4EiDcIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIg3DNCMNwuUjDcP/Iw3D/yINw5kjDMMGIwzDfCIMw7UiDMImAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIwzCDCMNwn4iDMPzIgzCxyINw8MjDcNcHA7GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIMwhgiDcJ0Ig3CEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////+P////Y////eH///sh///8If//8CF//8AhP/+AIQ/+ACEH/AAhA/wMIYP8PCHD/Dwhw/w8IcP8PCHD/Dwhw/w8IcP8PCHD/Bwhg/wMIAP+DCAH/wwgD//MID//7CD///wh///8J////Dn///w3////H////////////8=
27
+ // ==/UserScript==
28
+
29
+ /**
30
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
31
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
32
+ * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
33
+ */
34
+
35
+ const CaptchaSiteKey = "0x4AAAAAAALBT58IhyDViNmv";
36
+ const AdminUserList = ["zhuchenrui2", "shanwenxiao", "admin", "shihongxi"];
37
+
38
+ let PurifyHTML = (Input) => {
39
+ return DOMPurify.sanitize(Input, {
40
+ "ALLOWED_TAGS": ["a", "b", "blockquote", "br", "code", "dd", "del", "div", "dl", "dt", "em", "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "hr", "i", "img", "ins", "kbd", "li", "ol", "p", "pre", "q", "rp", "rt", "ruby", "s", "samp", "strike", "strong", "sub", "sup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "tt", "ul", "var"],
41
+ "ALLOWED_ATTR": ["abbr", "accept", "accept-charset", "accesskey", "action", "align", "alt", "axis", "border", "cellpadding", "cellspacing", "char", "charoff", "charset", "checked", "cite", "clear", "color", "cols", "colspan", "compact", "coords", "datetime", "dir", "disabled", "enctype", "for", "frame", "headers", "height", "href", "hreflang", "hspace", "ismap", "itemprop", "label", "lang", "longdesc", "maxlength", "media", "method", "multiple", "name", "nohref", "noshade", "nowrap", "prompt", "readonly", "rel", "rev", "rows", "rowspan", "rules", "scope", "selected", "shape", "size", "span", "src", "start", "summary", "tabindex", "target", "title", "type", "usemap", "valign", "value", "vspace", "width"]
42
+ });
43
+ }
44
+ let GetRelativeTime = (Input) => {
45
+ Input = new Date(Input);
46
+ let Now = new Date().getTime();
47
+ let Delta = Now - Input.getTime();
48
+ let RelativeName = "";
49
+ if (Delta < 0) { RelativeName = "未来"; }
50
+ else if (Delta <= 1000 * 60) { RelativeName = "刚刚"; }
51
+ else if (Delta <= 1000 * 60 * 60) { RelativeName = Math.floor((Now - Input) / 1000 / 60) + "分钟前"; }
52
+ else if (Delta <= 1000 * 60 * 60 * 24) { RelativeName = Math.floor((Now - Input) / 1000 / 60 / 60) + "小时前"; }
53
+ else if (Delta <= 1000 * 60 * 60 * 24 * 31) { RelativeName = Math.floor((Now - Input) / 1000 / 60 / 60 / 24) + "天前"; }
54
+ else if (Delta <= 1000 * 60 * 60 * 24 * 365) { RelativeName = Math.floor((Now - Input) / 1000 / 60 / 60 / 24 / 31) + "个月前"; }
55
+ else { RelativeName = Math.floor((Now - Input) / 1000 / 60 / 60 / 24 / 365) + "年前"; }
56
+ return "<span title=\"" + Input.toLocaleString() + "\">" + RelativeName + "</span>";
57
+ };
58
+ let RenderMathJax = async () => {
59
+ if (document.getElementById("MathJax-script") === null) {
60
+ var ScriptElement = document.createElement("script");
61
+ ScriptElement.id = "MathJax-script";
62
+ ScriptElement.type = "text/javascript";
63
+ ScriptElement.src = "https://cdn.bootcdn.net/ajax/libs/mathjax/3.0.5/es5/tex-chtml.js";
64
+ document.body.appendChild(ScriptElement);
65
+ await new Promise((Resolve) => {
66
+ ScriptElement.onload = () => {
67
+ Resolve();
68
+ };
69
+ });
70
+ }
71
+ MathJax.startup.input[0].findTeX.options.inlineMath.push(["$", "$"]);
72
+ MathJax.startup.input[0].findTeX.getPatterns();
73
+ MathJax.typeset();
74
+ };
75
+ let GetUserInfo = async (Username) => {
76
+ if (localStorage.getItem("UserScript-User-" + Username + "-UserRating") != null &&
77
+ new Date().getTime() - parseInt(localStorage.getItem("UserScript-User-" + Username + "-LastUpdateTime")) < 1000 * 60 * 60 * 24) {
78
+ return {
79
+ "Rating": localStorage.getItem("UserScript-User-" + Username + "-UserRating"),
80
+ "EmailHash": localStorage.getItem("UserScript-User-" + Username + "-EmailHash")
81
+ }
82
+ }
83
+ return await fetch("https://www.xmoj.tech/userinfo.php?user=" + Username).then((Response) => {
84
+ return Response.text();
85
+ }).then((Response) => {
86
+ if (Response.indexOf("No such User!") !== -1) {
87
+ return null;
88
+ }
89
+ const ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
90
+ let Rating = (parseInt(ParsedDocument.querySelector("#statics > tbody > tr:nth-child(4) > td:nth-child(2)").innerText.trim()) /
91
+ parseInt(ParsedDocument.querySelector("#statics > tbody > tr:nth-child(3) > td:nth-child(2)").innerText.trim())).toFixed(3) * 1000;
92
+ let Temp = ParsedDocument.querySelector("#statics > tbody").children;
93
+ let Email = Temp[Temp.length - 1].children[1].innerText.trim();
94
+ let EmailHash = CryptoJS.MD5(Email).toString();
95
+ localStorage.setItem("UserScript-User-" + Username + "-UserRating", Rating);
96
+ if (Email == "") {
97
+ EmailHash = undefined;
98
+ } else {
99
+ localStorage.setItem("UserScript-User-" + Username + "-EmailHash", EmailHash);
100
+ }
101
+ localStorage.setItem("UserScript-User-" + Username + "-LastUpdateTime", new Date().getTime());
102
+ return {
103
+ "Rating": Rating,
104
+ "EmailHash": EmailHash
105
+ }
106
+ });
107
+ };
108
+ /**
109
+ * Retrieves the badge information for a given user.
110
+ *
111
+ * @param {string} Username - The username of the user.
112
+ * @returns {Promise<Object>} - A promise that resolves to an object containing the badge information.
113
+ * @property {string} BackgroundColor - The background color of the badge.
114
+ * @property {string} Color - The color of the badge.
115
+ * @property {string} Content - The content of the badge.
116
+ */
117
+ let GetUserBadge = async (Username) => {
118
+ if (localStorage.getItem("UserScript-User-" + Username + "-Badge-LastUpdateTime") != null &&
119
+ new Date().getTime() - parseInt(localStorage.getItem("UserScript-User-" + Username + "-Badge-LastUpdateTime")) < 1000 * 60 * 60 * 24) {
120
+ return {
121
+ "BackgroundColor": localStorage.getItem("UserScript-User-" + Username + "-Badge-BackgroundColor"),
122
+ "Color": localStorage.getItem("UserScript-User-" + Username + "-Badge-Color"),
123
+ "Content": localStorage.getItem("UserScript-User-" + Username + "-Badge-Content")
124
+ }
125
+ } else {
126
+ let BackgroundColor = "";
127
+ let Color = "";
128
+ let Content = "";
129
+ await new Promise((Resolve) => {
130
+ RequestAPI("GetBadge", {
131
+ "UserID": String(Username)
132
+ }, (Response) => {
133
+ if (Response.Success) {
134
+ BackgroundColor = Response.Data.BackgroundColor;
135
+ Color = Response.Data.Color;
136
+ Content = Response.Data.Content;
137
+ }
138
+ Resolve();
139
+ });
140
+ });
141
+ localStorage.setItem("UserScript-User-" + Username + "-Badge-BackgroundColor", BackgroundColor);
142
+ localStorage.setItem("UserScript-User-" + Username + "-Badge-Color", Color);
143
+ localStorage.setItem("UserScript-User-" + Username + "-Badge-Content", Content);
144
+ localStorage.setItem("UserScript-User-" + Username + "-Badge-LastUpdateTime", String(new Date().getTime()));
145
+ return {
146
+ "BackgroundColor": BackgroundColor,
147
+ "Color": Color,
148
+ "Content": Content
149
+ }
150
+ }
151
+ };
152
+ /**
153
+ * Sets the HTML content of an element to display a username with optional additional information.
154
+ * @param {HTMLElement} Element - The element to set the HTML content.
155
+ * @param {string} Username - The username to display.
156
+ * @param {boolean} [Simple=false] - Indicates whether to display additional information or not.
157
+ * @param {string} [Href="https://www.xmoj.tech/userinfo.php?user="] - The URL to link the username to.
158
+ * @returns {Promise<void>} - A promise that resolves when the HTML content is set.
159
+ */
160
+ let GetUsernameHTML = async (Element, Username, Simple = false, Href = "https://www.xmoj.tech/userinfo.php?user=") => {
161
+ Username = Username.replaceAll(/[^a-zA-Z0-9]/g, "");
162
+ let ID = "Username-" + Username + "-" + Math.random();
163
+ Element.id = ID;
164
+ Element.innerHTML = `<div class="spinner-border spinner-border-sm me-2" role="status"></div>`;
165
+ Element.appendChild(document.createTextNode(Username));
166
+ let UserInfo = await GetUserInfo(Username);
167
+ if (UserInfo === null) {
168
+ document.getElementById(ID).innerHTML = "";
169
+ document.getElementById(ID).appendChild(document.createTextNode(Username));
170
+ return;
171
+ }
172
+ let HTMLData = "";
173
+ if (!Simple) {
174
+ HTMLData += `<img src="`;
175
+ if (UserInfo.EmailHash == undefined) {
176
+ HTMLData += `https://cravatar.cn/avatar/00000000000000000000000000000000?d=mp&f=y`;
177
+ }
178
+ else {
179
+ HTMLData += `https://cravatar.cn/avatar/${UserInfo.EmailHash}?d=retro`;
180
+ }
181
+ HTMLData += `" class="rounded me-2" style="width: 20px; height: 20px; ">`;
182
+ }
183
+ HTMLData += `<a href="${Href}${Username}" class="link-offset-2 link-underline-opacity-50 `
184
+ if (UtilityEnabled("Rating")) {
185
+ let Rating = UserInfo.Rating;
186
+ // if(AdminUserList.includes(Username)){
187
+ // HTMLData += "link-fuchsia"
188
+ // }
189
+ // else
190
+ if (Rating > 500) {
191
+ HTMLData += "link-danger";
192
+ } else if (Rating >= 400) {
193
+ HTMLData += "link-warning";
194
+ } else if (Rating >= 300) {
195
+ HTMLData += "link-success";
196
+ } else {
197
+ HTMLData += "link-info";
198
+ }
199
+ }
200
+ else {
201
+ HTMLData += "link-info";
202
+ }
203
+ HTMLData += `\";"></a>`;
204
+ if (!Simple) {
205
+ if (AdminUserList.includes(Username)) {
206
+ HTMLData += `<span class="badge text-bg-danger ms-2">管理员</span>`;
207
+ }
208
+ if (Username == "chenlangning") {
209
+ HTMLData += `<span class="badge ms-2" style="background-color: #6633cc; color: #ffffff">吉祥物</span>`;
210
+ }
211
+ let BadgeInfo = await GetUserBadge(Username);
212
+ if (BadgeInfo.Content != "") {
213
+ HTMLData += `<span class="badge ms-2" style="background-color: ${BadgeInfo.BackgroundColor}; color: ${BadgeInfo.Color}">${BadgeInfo.Content}</span>`;
214
+ }
215
+ }
216
+ document.getElementById(ID).innerHTML = HTMLData;
217
+ document.getElementById(ID).getElementsByTagName("a")[0].appendChild(document.createTextNode(Username));
218
+ };
219
+ /**
220
+ * Converts the given number of seconds to a formatted string representation of hours, minutes, and seconds.
221
+ * @param {number} InputSeconds - The number of seconds to convert.
222
+ * @returns {string} The formatted string representation of the input seconds.
223
+ */
224
+ let SecondsToString = (InputSeconds) => {
225
+ let Hours = Math.floor(InputSeconds / 3600);
226
+ let Minutes = Math.floor((InputSeconds % 3600) / 60);
227
+ let Seconds = InputSeconds % 60;
228
+ return (Hours < 10 ? "0" : "") + Hours + ":" +
229
+ (Minutes < 10 ? "0" : "") + Minutes + ":" +
230
+ (Seconds < 10 ? "0" : "") + Seconds;
231
+ }
232
+ /**
233
+ * Converts a string in the format "hh:mm:ss" to the equivalent number of seconds.
234
+ * @param {string} InputString - The input string to convert.
235
+ * @returns {number} The number of seconds equivalent to the input string.
236
+ */
237
+ let StringToSeconds = (InputString) => {
238
+ let SplittedString = InputString.split(":");
239
+ return parseInt(SplittedString[0]) * 60 * 60 +
240
+ parseInt(SplittedString[1]) * 60 +
241
+ parseInt(SplittedString[2]);
242
+ }
243
+ /**
244
+ * Converts a memory size in bytes to a human-readable string representation.
245
+ * @param {number} Memory - The memory size in bytes.
246
+ * @returns {string} The human-readable string representation of the memory size.
247
+ */
248
+ let SizeToStringSize = (Memory) => {
249
+ if (UtilityEnabled("AddUnits")) {
250
+ if (Memory < 1024) {
251
+ return Memory + "B";
252
+ } else if (Memory < 1024 * 1024) {
253
+ return (Memory / 1024).toFixed(2) + "KB";
254
+ } else if (Memory < 1024 * 1024 * 1024) {
255
+ return (Memory / 1024 / 1024).toFixed(2) + "MB";
256
+ } else {
257
+ return (Memory / 1024 / 1024 / 1024).toFixed(2) + "GB";
258
+ }
259
+ }
260
+ else {
261
+ return Memory;
262
+ }
263
+ };
264
+ /**
265
+ * Converts a time value to a string representation.
266
+ * @param {number} Time - The time value to convert.
267
+ * @returns {string|number} - The converted time value as a string, or the original value if UtilityEnabled("AddUnits") is false.
268
+ */
269
+ let TimeToStringTime = (Time) => {
270
+ if (UtilityEnabled("AddUnits")) {
271
+ if (Time < 1000) {
272
+ return Time + "ms";
273
+ } else if (Time < 1000 * 60) {
274
+ return (Time / 1000).toFixed(2) + "s";
275
+ }
276
+ }
277
+ else {
278
+ return Time;
279
+ }
280
+ };
281
+ /**
282
+ * Tidies up the given table by applying Bootstrap styling and removing unnecessary attributes.
283
+ *
284
+ * @param {HTMLElement} Table - The table element to be tidied up.
285
+ */
286
+ let TidyTable = (Table) => {
287
+ if (UtilityEnabled("NewBootstrap") && Table != null) {
288
+ Table.className = "table table-hover";
289
+ Table.querySelector("thead > tr").removeAttribute("class");
290
+ Table.querySelector("thead > tr").removeAttribute("align");
291
+ Table.querySelector("thead > tr").innerHTML = Table.querySelector("thead > tr").innerHTML.replaceAll("td", "th");
292
+ let Temp = Table.querySelector("thead > tr").children;
293
+ for (let j = 0; j < Temp.length; j++) {
294
+ let Width = Temp[j].style.width;
295
+ Temp[j].removeAttribute("style");
296
+ Temp[j].style.width = Width;
297
+ Temp[j].removeAttribute("onclick");
298
+ Temp[j].removeAttribute("align");
299
+ }
300
+ Table.querySelector("tbody").className = "table-group-divider";
301
+ Temp = Table.querySelector("tbody").children;
302
+ for (let j = 0; j < Temp.length; j++) {
303
+ Temp[j].removeAttribute("align");
304
+ let Temp2 = Temp[j].querySelectorAll("*");
305
+ for (let k = 0; k < Temp2.length; k++) {
306
+ Temp2[k].classList.remove("left");
307
+ Temp2[k].classList.remove("center");
308
+ if (Temp2[k].className == "") {
309
+ Temp2[k].removeAttribute("class");
310
+ }
311
+ }
312
+ }
313
+ }
314
+ };
315
+ let UtilityEnabled = (Name) => {
316
+ if (localStorage.getItem("UserScript-Setting-" + Name) == null) {
317
+ //DebugMode is off by default
318
+ localStorage.setItem("UserScript-Setting-" + Name, (Name == "DebugMode" ? "false" : "true"));
319
+ }
320
+ return localStorage.getItem("UserScript-Setting-" + Name) == "true";
321
+ };
322
+ let RequestAPI = (Action, Data, CallBack) => {
323
+ let Session = "";
324
+ let Temp = document.cookie.split(";");
325
+ for (let i = 0; i < Temp.length; i++) {
326
+ if (Temp[i].includes("PHPSESSID")) {
327
+ Session = Temp[i].split("=")[1];
328
+ }
329
+ }
330
+ let PostData = {
331
+ "Authentication": {
332
+ "SessionID": Session,
333
+ "Username": CurrentUsername,
334
+ },
335
+ "Data": Data,
336
+ "Version": GM_info.script.version,
337
+ "DebugMode": UtilityEnabled("DebugMode")
338
+ };
339
+ let DataString = JSON.stringify(PostData);
340
+ GM_xmlhttpRequest({
341
+ method: "POST",
342
+ url: "https://api.xmoj-bbs.tech/" + Action,
343
+ // url: "http://127.0.0.1:8787/" + Action,
344
+ headers: {
345
+ "Content-Type": "application/json"
346
+ },
347
+ data: DataString,
348
+ onload: (Response) => {
349
+ try {
350
+ CallBack(JSON.parse(Response.responseText));
351
+ } catch (Error) {
352
+ console.log(Response.responseText);
353
+ CallBack({
354
+ "Success": false,
355
+ "Message": "JSON解析错误:" + Error,
356
+ "Data": null
357
+ });
358
+ }
359
+ }
360
+ });
361
+ };
362
+
363
+ GM_registerMenuCommand("清除缓存", () => {
364
+ let Temp = [];
365
+ for (let i = 0; i < localStorage.length; i++) {
366
+ if (localStorage.key(i).startsWith("UserScript-User-")) {
367
+ Temp.push(localStorage.key(i));
368
+ }
369
+ }
370
+ for (let i = 0; i < Temp.length; i++) {
371
+ localStorage.removeItem(Temp[i]);
372
+ }
373
+ location.reload();
374
+ });
375
+ GM_registerMenuCommand("重置数据", () => {
376
+ if (confirm("确定要重置数据吗?")) {
377
+ localStorage.clear();
378
+ location.reload();
379
+ }
380
+ });
381
+
382
+ let SearchParams = new URLSearchParams(location.search);
383
+ let ServerURL = (UtilityEnabled("DebugMode") ? "https://ghpages.xmoj-bbs.tech/" : "https://web.xmoj-bbs.tech")
384
+ let CurrentUsername = document.querySelector("#profile").innerText;
385
+ CurrentUsername = CurrentUsername.replaceAll(/[^a-zA-Z0-9]/g, "");
386
+ let IsAdmin = AdminUserList.indexOf(CurrentUsername) !== -1;
387
+ if (location.href.startsWith('http://')){
388
+ //use https
389
+ location.href = location.href.replace('http://', 'https://');
390
+ }
391
+ if (location.host != "www.xmoj.tech") {
392
+ location.host = "www.xmoj.tech";
393
+ }
394
+ else {
395
+ document.body.classList.add("placeholder-glow");
396
+ if (document.querySelector("#navbar") != null) {
397
+ if (document.querySelector("body > div > div.jumbotron") != null) {
398
+ document.querySelector("body > div > div.jumbotron").className = "mt-3";
399
+ }
400
+
401
+ if (UtilityEnabled("AutoLogin") &&
402
+ document.querySelector("#profile") != null &&
403
+ document.querySelector("#profile").innerHTML == "登录" &&
404
+ location.pathname != "/login.php" &&
405
+ location.pathname != "/loginpage.php" &&
406
+ location.pathname != "/lostpassword.php") {
407
+ localStorage.setItem("UserScript-LastPage", location.pathname + location.search);
408
+ location.href = "https://www.xmoj.tech/loginpage.php";
409
+ }
410
+
411
+ let Discussion = null;
412
+ if (UtilityEnabled("Discussion")) {
413
+ Discussion = document.createElement("li");
414
+ document.querySelector("#navbar > ul:nth-child(1)").appendChild(Discussion);
415
+ Discussion.innerHTML = "<a href=\"https://www.xmoj.tech/discuss3/discuss.php\">讨论</a>";
416
+ }
417
+
418
+ if (document.querySelector("#navbar > ul:nth-child(1)").childElementCount > 8 && UtilityEnabled("ACMRank")) {
419
+ let ACMRank = document.createElement("li");
420
+ document.querySelector("#navbar > ul:nth-child(1)").insertBefore(ACMRank, document.querySelector("#navbar > ul:nth-child(1) > li:nth-child(9)"));
421
+ ACMRank.innerHTML = "<a href=\"https://www.xmoj.tech/contestrank-oi.php?cid=" + Number(SearchParams.get("cid")) + "&ByUserScript=1\">ACM 排名</a>";
422
+ ACMRank.classList.add("active");
423
+ }
424
+ if (UtilityEnabled("Translate")) {
425
+ document.querySelector("#navbar > ul:nth-child(1) > li:nth-child(2) > a").innerText = "题库";
426
+ }
427
+ //send analytics
428
+ RequestAPI("SendData", {}, (result) => {
429
+ if (UtilityEnabled("DebugMode")) {
430
+ console.log(result);
431
+ }
432
+ });
433
+ if (UtilityEnabled("ReplaceLinks")) {
434
+ document.body.innerHTML =
435
+ String(document.body.innerHTML).replaceAll(
436
+ /\[<a href="([^"]*)">([^<]*)<\/a>\]/g,
437
+ "<button onclick=\"location.href='$1'\" class=\"btn btn-outline-secondary\">$2</button>");
438
+ }
439
+ if (UtilityEnabled("ReplaceXM")) {
440
+ document.body.innerHTML = String(document.body.innerHTML).replaceAll("我", "高老师");
441
+ document.body.innerHTML = String(document.body.innerHTML).replaceAll("小明", "高老师");
442
+ document.body.innerHTML = String(document.body.innerHTML).replaceAll("下海", "上海");
443
+ document.body.innerHTML = String(document.body.innerHTML).replaceAll("海上", "上海");
444
+ document.body.innerHTML = String(document.body.innerHTML).replaceAll("小红", "徐师娘");
445
+ document.body.innerHTML = String(document.body.innerHTML).replaceAll("小粉", "彩虹");
446
+ document.body.innerHTML = String(document.body.innerHTML).replaceAll("高老师们", "我们");
447
+ document.body.innerHTML = String(document.body.innerHTML).replaceAll("自高老师", "自我");
448
+ document.title = String(document.title).replaceAll("小明", "高老师");
449
+ }
450
+
451
+ if (UtilityEnabled("NewBootstrap")) {
452
+ let Temp = document.querySelectorAll("link");
453
+ for (var i = 0; i < Temp.length; i++) {
454
+ if (Temp[i].href.indexOf("bootstrap.min.css") != -1) {
455
+ Temp[i].remove();
456
+ }
457
+ else if (Temp[i].href.indexOf("white.css") != -1) {
458
+ Temp[i].remove();
459
+ }
460
+ else if (Temp[i].href.indexOf("semantic.min.css") != -1) {
461
+ Temp[i].remove();
462
+ }
463
+ else if (Temp[i].href.indexOf("bootstrap-theme.min.css") != -1) {
464
+ Temp[i].remove();
465
+ }
466
+ else if (Temp[i].href.indexOf("problem.css") != -1) {
467
+ Temp[i].remove();
468
+ }
469
+ }
470
+ if (UtilityEnabled("DarkMode")) {
471
+ document.querySelector("html").setAttribute("data-bs-theme", "dark");
472
+ }
473
+ else {
474
+ document.querySelector("html").setAttribute("data-bs-theme", "light");
475
+ }
476
+
477
+ let PopperScriptElement = document.createElement("script"); document.head.appendChild(PopperScriptElement);
478
+ PopperScriptElement.type = "module";
479
+ PopperScriptElement.src = "https://cdn.bootcdn.net/ajax/libs/popper.js/2.11.7/umd/popper.min.js";
480
+ let CodeMirrorStyleElement = document.createElement("link"); document.head.appendChild(CodeMirrorStyleElement);
481
+ CodeMirrorStyleElement.rel = "stylesheet";
482
+ CodeMirrorStyleElement.href = "https://cdn.bootcdn.net/ajax/libs/codemirror/6.65.7/codemirror.min.css";
483
+ let CodeMirrorThemeStyleElement = document.createElement("link"); document.head.appendChild(CodeMirrorThemeStyleElement);
484
+ CodeMirrorThemeStyleElement.rel = "stylesheet";
485
+ CodeMirrorThemeStyleElement.href = "https://cdn.bootcdn.net/ajax/libs/codemirror/6.65.7/theme/darcula.min.css";
486
+ let CodeMirrorMergeStyleElement = document.createElement("link"); document.head.appendChild(CodeMirrorMergeStyleElement);
487
+ CodeMirrorMergeStyleElement.rel = "stylesheet";
488
+ CodeMirrorMergeStyleElement.href = "https://cdn.bootcdn.net/ajax/libs/codemirror/6.65.7/addon/merge/merge.min.css";
489
+ let BootstrapStyleElement = document.createElement("link"); document.head.appendChild(BootstrapStyleElement);
490
+ BootstrapStyleElement.rel = "stylesheet";
491
+ BootstrapStyleElement.href = "https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0-alpha3/css/bootstrap.min.css";
492
+ await new Promise((Resolve) => {
493
+ PopperScriptElement.onload = () => {
494
+ Resolve();
495
+ };
496
+ });
497
+ Temp = document.querySelectorAll("script");
498
+ for (var i = 0; i < Temp.length; i++) {
499
+ if (Temp[i].src.indexOf("bootstrap.min.js") != -1) {
500
+ Temp[i].remove();
501
+ let BootstrapScriptElement = document.createElement("script"); document.head.appendChild(BootstrapScriptElement);
502
+ BootstrapScriptElement.type = "module";
503
+ BootstrapScriptElement.src = "https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0-alpha3/js/bootstrap.min.js";
504
+ await new Promise((Resolve) => {
505
+ BootstrapScriptElement.onload = () => {
506
+ Resolve();
507
+ };
508
+ });
509
+ }
510
+ }
511
+ document.querySelector("nav").className = "navbar navbar-expand-lg bg-body-tertiary";
512
+ document.querySelector("#navbar > ul:nth-child(1)").classList = "navbar-nav me-auto mb-2 mb-lg-0";
513
+ document.querySelector("body > div > nav > div > div.navbar-header").outerHTML = `<a class="navbar-brand" href="https://www.xmoj.tech/">${UtilityEnabled("ReplaceXM") ? "高老师" : "小明"}的OJ</a><button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbar"><span class="navbar-toggler-icon"></span></button>`;
514
+ document.querySelector("#navbar > ul.nav.navbar-nav.navbar-right > li").classList = "nav-item dropdown";
515
+ document.querySelector("#navbar > ul.nav.navbar-nav.navbar-right > li > a").className = "nav-link dropdown-toggle";
516
+ document.querySelector("#navbar > ul.nav.navbar-nav.navbar-right > li > a > span.caret").remove();
517
+ Temp = document.querySelector("#navbar > ul:nth-child(1)").children;
518
+ for (var i = 0; i < Temp.length; i++) {
519
+ if (Temp[i].classList.contains("active")) {
520
+ Temp[i].classList.remove("active");
521
+ Temp[i].children[0].classList.add("active");
522
+ }
523
+ Temp[i].classList.add("nav-item");
524
+ Temp[i].children[0].classList.add("nav-link");
525
+ }
526
+ document.querySelector("#navbar > ul.nav.navbar-nav.navbar-right > li > a").setAttribute("data-bs-toggle", "dropdown");
527
+ document.querySelector("#navbar > ul.nav.navbar-nav.navbar-right > li > a").removeAttribute("data-toggle");
528
+ }
529
+ if (UtilityEnabled("RemoveUseless") && document.getElementsByTagName("marquee")[0] != undefined) {
530
+ document.getElementsByTagName("marquee")[0].remove();
531
+ }
532
+
533
+ let Style = document.createElement("style");
534
+ document.body.appendChild(Style);
535
+ Style.innerHTML = `
536
+ nav {
537
+ border-bottom-left-radius: 5px;
538
+ border-bottom-right-radius: 5px;
539
+ }
540
+ blockquote {
541
+ border-left: 5px solid var(--bs-secondary-bg);
542
+ padding: 0.5em 1em;
543
+ }
544
+ .status_y:hover {
545
+ box-shadow: #52c41a 1px 1px 10px 0px !important;
546
+ }
547
+ .status_n:hover {
548
+ box-shadow: #fe4c61 1px 1px 10px 0px !important;
549
+ }
550
+ .test-case {
551
+ border-radius: 5px !important;
552
+ }
553
+ .test-case:hover {
554
+ box-shadow: rgba(0, 0, 0, 0.3) 0px 10px 20px 3px !important;
555
+ }
556
+ .data[result-item] {
557
+ border-bottom-left-radius: 5px;
558
+ border-bottom-right-radius: 5px;
559
+ }
560
+ .software_list {
561
+ width: unset !important;
562
+ }
563
+ .software_item {
564
+ margin: 5px 10px !important;
565
+ background-color: var(--bs-secondary-bg) !important;
566
+ }
567
+ .item-txt {
568
+ color: var(--bs-emphasis-color) !important;
569
+ }
570
+ .cnt-row {
571
+ justify-content: inherit;
572
+ align-items: stretch;
573
+ width: 100% !important;
574
+ padding: 1rem 0;
575
+ }
576
+ .cnt-row-head {
577
+ padding: 0.8em 1em;
578
+ background-color: var(--bs-secondary-bg);
579
+ border-radius: 0.3rem 0.3rem 0 0;
580
+ width: 100%;
581
+ }
582
+ .cnt-row-body {
583
+ padding: 1em;
584
+ border: 1px solid var(--bs-secondary-bg);
585
+ border-top: none;
586
+ border-radius: 0 0 0.3rem 0.3rem;
587
+ }`;
588
+ if (UtilityEnabled("AddAnimation")) {
589
+ Style.innerHTML += `.status, .test-case {
590
+ transition: 0.5s !important;
591
+ }`;
592
+ }
593
+ if (UtilityEnabled("AddColorText")) {
594
+ Style.innerHTML += `.red {
595
+ color: red !important;
596
+ }
597
+ .green {
598
+ color: green !important;
599
+ }
600
+ .blue {
601
+ color: blue !important;
602
+ }`;
603
+ }
604
+
605
+ if (UtilityEnabled("RemoveUseless")) {
606
+ if (document.getElementsByClassName("footer")[0] != null) {
607
+ document.getElementsByClassName("footer")[0].remove();
608
+ }
609
+ }
610
+
611
+ if (UtilityEnabled("ReplaceYN")) {
612
+ Temp = document.getElementsByClassName("status_y");
613
+ for (let i = 0; i < Temp.length; i++) {
614
+ Temp[i].innerText = "✓";
615
+ }
616
+ Temp = document.getElementsByClassName("status_n");
617
+ for (let i = 0; i < Temp.length; i++) {
618
+ Temp[i].innerText = "✗";
619
+ }
620
+ }
621
+
622
+ Temp = document.getElementsByClassName("page-item");
623
+ for (let i = 0; i < Temp.length; i++) {
624
+ Temp[i].children[0].className = "page-link";
625
+ }
626
+ if (document.getElementsByClassName("pagination")[0] != null) {
627
+ document.getElementsByClassName("pagination")[0].classList.add("justify-content-center");
628
+ }
629
+
630
+ Temp = document.getElementsByTagName("table");
631
+ for (let i = 0; i < Temp.length; i++) {
632
+ if (Temp[i].querySelector("thead") != null) {
633
+ TidyTable(Temp[i]);
634
+ }
635
+ }
636
+
637
+ setInterval(() => {
638
+ try {
639
+ let CurrentDate = new Date(new Date().getTime() + diff);
640
+ let Year = CurrentDate.getFullYear();
641
+ if (Year > 3000) {
642
+ Year -= 1900;
643
+ }
644
+ let Month = CurrentDate.getMonth() + 1;
645
+ let _Date = CurrentDate.getDate();
646
+ let Hours = CurrentDate.getHours();
647
+ let Minutes = CurrentDate.getMinutes();
648
+ let Seconds = CurrentDate.getSeconds();
649
+ document.getElementById("nowdate").innerHTML =
650
+ Year + "-" +
651
+ (Month < 10 ? "0" : "") + Month + "-" +
652
+ (_Date < 10 ? "0" : "") + _Date + " " +
653
+ (Hours < 10 ? "0" : "") + Hours + ":" +
654
+ (Minutes < 10 ? "0" : "") + Minutes + ":" +
655
+ (Seconds < 10 ? "0" : "") + Seconds;
656
+ } catch (Error) { }
657
+
658
+ if (UtilityEnabled("ResetType")) {
659
+ if (document.querySelector("#profile") != undefined &&
660
+ document.querySelector("#profile").innerHTML == "登录") {
661
+ if (document.querySelector("#navbar > ul.nav.navbar-nav.navbar-right > li > ul").childNodes.length == 3) {
662
+ document.querySelector("#navbar > ul.nav.navbar-nav.navbar-right > li > ul").childNodes[3].remove();
663
+ }
664
+ }
665
+ else if (document.querySelector("#navbar > ul.nav.navbar-nav.navbar-right > li > ul > li:nth-child(3) > a > span") != undefined &&
666
+ document.querySelector("#navbar > ul.nav.navbar-nav.navbar-right > li > ul > li:nth-child(3) > a > span").innerText != "个人中心") {
667
+ let PopupUL = document.querySelector("#navbar > ul.nav.navbar-nav.navbar-right > li > ul");
668
+ PopupUL.innerHTML = `<li class="dropdown-item">修改帐号</li>
669
+ <li class="dropdown-item">个人中心</li>
670
+ <li class="dropdown-item">短消息</li>
671
+ <li class="dropdown-item">插件设置</li>
672
+ <li class="dropdown-item">注销</li>`
673
+ PopupUL.children[0].addEventListener("click", () => {
674
+ location.href = "https://www.xmoj.tech/modifypage.php";
675
+ });
676
+ PopupUL.children[1].addEventListener("click", () => {
677
+ location.href = "https://www.xmoj.tech/userinfo.php?user=" + CurrentUsername;
678
+ });
679
+ PopupUL.children[2].addEventListener("click", () => {
680
+ location.href = "https://www.xmoj.tech/mail.php";
681
+ });
682
+ PopupUL.children[3].addEventListener("click", () => {
683
+ location.href = "https://www.xmoj.tech/index.php?ByUserScript=1";
684
+ });
685
+ PopupUL.children[4].addEventListener("click", () => {
686
+ localStorage.removeItem("UserScript-Username");
687
+ localStorage.removeItem("UserScript-Password");
688
+ location.href = "https://www.xmoj.tech/logout.php";
689
+ });
690
+ Style.innerHTML += ".dropdown-item {";
691
+ Style.innerHTML += " cursor: pointer;";
692
+ Style.innerHTML += "}";
693
+ }
694
+ }
695
+ if (UtilityEnabled("AutoCountdown")) {
696
+ let Temp = document.getElementsByClassName("UpdateByJS");
697
+ for (let i = 0; i < Temp.length; i++) {
698
+ let EndTime = Temp[i].getAttribute("EndTime");
699
+ if (EndTime === null) {
700
+ Temp[i].classList.remove("UpdateByJS");
701
+ continue;
702
+ }
703
+ let TimeStamp = parseInt(EndTime) - new Date().getTime();
704
+ if (TimeStamp < 3000) {
705
+ Temp[i].classList.remove("UpdateByJS");
706
+ location.reload();
707
+ }
708
+ let CurrentDate = new Date(TimeStamp);
709
+ let Day = parseInt((TimeStamp / 1000 / 60 / 60 / 24).toFixed(0));
710
+ let Hour = CurrentDate.getUTCHours();
711
+ let Minute = CurrentDate.getUTCMinutes();
712
+ let Second = CurrentDate.getUTCSeconds();
713
+ Temp[i].innerHTML = (Day !== 0 ? Day + "天" : "") +
714
+ (Hour !== 0 ? (Hour < 10 ? "0" : "") + Hour + "小时" : "") +
715
+ (Minute !== 0 ? (Minute < 10 ? "0" : "") + Minute + "分" : "") +
716
+ (Second !== 0 ? (Second < 10 ? "0" : "") + Second + "秒" : "");
717
+ }
718
+ }
719
+ }, 100);
720
+
721
+ fetch(ServerURL + "/Update.json", { cache: "no-cache" })
722
+ .then((Response) => {
723
+ return Response.json();
724
+ })
725
+ .then((Response) => {
726
+ let CurrentVersion = GM_info.script.version;
727
+ let LatestVersion;
728
+ for (let i = Object.keys(Response.UpdateHistory).length - 1; i >= 0; i--) {
729
+ let VersionInfo = Object.keys(Response.UpdateHistory)[i];
730
+ if (UtilityEnabled("DebugMode") || Response.UpdateHistory[VersionInfo].Prerelease == false) {
731
+ LatestVersion = VersionInfo;
732
+ break;
733
+ }
734
+ }
735
+ if (CurrentVersion < LatestVersion) {
736
+ let UpdateDiv = document.createElement("div");
737
+ UpdateDiv.innerHTML = `<div class="alert alert-warning alert-dismissible fade show mt-2" role="alert">
738
+ <div>
739
+ XMOJ用户脚本发现新版本${LatestVersion},当前版本${CurrentVersion},点击
740
+ <a href="${ServerURL}/XMOJ.user.js" target="_blank" class="alert-link">此处</a>
741
+ 更新
742
+ </div>
743
+ <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
744
+ </div>`;
745
+ document.querySelector("body > div").insertBefore(UpdateDiv, document.querySelector("body > div > div.mt-3"));
746
+ }
747
+ if (localStorage.getItem("UserScript-Update-LastVersion") != GM_info.script.version) {
748
+ localStorage.setItem("UserScript-Update-LastVersion", GM_info.script.version);
749
+ let UpdateDiv = document.createElement("div"); document.querySelector("body").appendChild(UpdateDiv);
750
+ UpdateDiv.className = "modal fade";
751
+ UpdateDiv.id = "UpdateModal";
752
+ UpdateDiv.tabIndex = -1;
753
+ let UpdateDialog = document.createElement("div"); UpdateDiv.appendChild(UpdateDialog);
754
+ UpdateDialog.className = "modal-dialog";
755
+ let UpdateContent = document.createElement("div"); UpdateDialog.appendChild(UpdateContent);
756
+ UpdateContent.className = "modal-content";
757
+ let UpdateHeader = document.createElement("div"); UpdateContent.appendChild(UpdateHeader);
758
+ UpdateHeader.className = "modal-header";
759
+ let UpdateTitle = document.createElement("h5"); UpdateHeader.appendChild(UpdateTitle);
760
+ UpdateTitle.className = "modal-title";
761
+ UpdateTitle.innerText = "更新日志";
762
+ let UpdateCloseButton = document.createElement("button"); UpdateHeader.appendChild(UpdateCloseButton);
763
+ UpdateCloseButton.type = "button";
764
+ UpdateCloseButton.className = "btn-close";
765
+ UpdateCloseButton.setAttribute("data-bs-dismiss", "modal");
766
+ let UpdateBody = document.createElement("div"); UpdateContent.appendChild(UpdateBody);
767
+ UpdateBody.className = "modal-body";
768
+ let UpdateFooter = document.createElement("div"); UpdateContent.appendChild(UpdateFooter);
769
+ UpdateFooter.className = "modal-footer";
770
+ let UpdateButton = document.createElement("button"); UpdateFooter.appendChild(UpdateButton);
771
+ UpdateButton.type = "button";
772
+ UpdateButton.className = "btn btn-secondary";
773
+ UpdateButton.setAttribute("data-bs-dismiss", "modal");
774
+ UpdateButton.innerText = "关闭";
775
+ let Version = Object.keys(Response.UpdateHistory)[Object.keys(Response.UpdateHistory).length - 1]
776
+ let Data = Response.UpdateHistory[Version];
777
+ let UpdateDataCard = document.createElement("div"); UpdateBody.appendChild(UpdateDataCard);
778
+ UpdateDataCard.className = "card mb-3";
779
+ let UpdateDataCardBody = document.createElement("div"); UpdateDataCard.appendChild(UpdateDataCardBody);
780
+ UpdateDataCardBody.className = "card-body";
781
+ let UpdateDataCardTitle = document.createElement("h5"); UpdateDataCardBody.appendChild(UpdateDataCardTitle);
782
+ UpdateDataCardTitle.className = "card-title";
783
+ UpdateDataCardTitle.innerText = Version;
784
+ let UpdateDataCardSubtitle = document.createElement("h6"); UpdateDataCardBody.appendChild(UpdateDataCardSubtitle);
785
+ UpdateDataCardSubtitle.className = "card-subtitle mb-2 text-muted";
786
+ UpdateDataCardSubtitle.innerHTML = GetRelativeTime(Data.UpdateDate);
787
+ let UpdateDataCardText = document.createElement("p"); UpdateDataCardBody.appendChild(UpdateDataCardText);
788
+ UpdateDataCardText.className = "card-text";
789
+ let UpdateDataCardList = document.createElement("ul"); UpdateDataCardText.appendChild(UpdateDataCardList);
790
+ UpdateDataCardList.className = "list-group list-group-flush";
791
+ for (let j = 0; j < Data.UpdateContents.length; j++) {
792
+ let UpdateDataCardListItem = document.createElement("li"); UpdateDataCardList.appendChild(UpdateDataCardListItem);
793
+ UpdateDataCardListItem.className = "list-group-item";
794
+ UpdateDataCardListItem.innerHTML =
795
+ "(<a href=\"https://github.com/XMOJ-Script-dev/XMOJ-Script/pull/" + Data.UpdateContents[j].PR + "\" target=\"_blank\">" +
796
+ "#" + Data.UpdateContents[j].PR + "</a>) " +
797
+ Data.UpdateContents[j].Description;
798
+ }
799
+ let UpdateDataCardLink = document.createElement("a"); UpdateDataCardBody.appendChild(UpdateDataCardLink);
800
+ UpdateDataCardLink.className = "card-link";
801
+ UpdateDataCardLink.href = "https://github.com/XMOJ-Script-dev/XMOJ-Script/releases/tag/" + Version;
802
+ UpdateDataCardLink.target = "_blank";
803
+ UpdateDataCardLink.innerText = "查看该版本";
804
+ new bootstrap.Modal(document.getElementById("UpdateModal")).show();
805
+ }
806
+ });
807
+ fetch(ServerURL + "/AddonScript.js", { cache: "no-cache" })
808
+ .then((Response) => {
809
+ return Response.text();
810
+ })
811
+ .then((Response) => {
812
+ eval(Response);
813
+ });
814
+
815
+ let ToastContainer = document.createElement("div");
816
+ ToastContainer.classList.add("toast-container", "position-fixed", "bottom-0", "end-0", "p-3");
817
+ document.body.appendChild(ToastContainer);
818
+ addEventListener("focus", () => {
819
+ if (UtilityEnabled("BBSPopup")) {
820
+ RequestAPI("GetBBSMentionList", {}, (Response) => {
821
+ if (Response.Success) {
822
+ ToastContainer.innerHTML = "";
823
+ let MentionList = Response.Data.MentionList;
824
+ for (let i = 0; i < MentionList.length; i++) {
825
+ let Toast = document.createElement("div");
826
+ Toast.classList.add("toast");
827
+ Toast.setAttribute("role", "alert");
828
+ let ToastHeader = document.createElement("div");
829
+ ToastHeader.classList.add("toast-header");
830
+ let ToastTitle = document.createElement("strong");
831
+ ToastTitle.classList.add("me-auto");
832
+ ToastTitle.innerHTML = "提醒:有人@你";
833
+ ToastHeader.appendChild(ToastTitle);
834
+ let ToastTime = document.createElement("small");
835
+ ToastTime.classList.add("text-body-secondary");
836
+ ToastTime.innerHTML = GetRelativeTime(MentionList[i].MentionTime);
837
+ ToastHeader.appendChild(ToastTime);
838
+ let ToastCloseButton = document.createElement("button");
839
+ ToastCloseButton.type = "button";
840
+ ToastCloseButton.classList.add("btn-close");
841
+ ToastCloseButton.setAttribute("data-bs-dismiss", "toast");
842
+ ToastHeader.appendChild(ToastCloseButton);
843
+ Toast.appendChild(ToastHeader);
844
+ let ToastBody = document.createElement("div");
845
+ ToastBody.classList.add("toast-body");
846
+ ToastBody.innerHTML = "讨论" + MentionList[i].PostTitle + "有新回复";
847
+ let ToastFooter = document.createElement("div");
848
+ ToastFooter.classList.add("mt-2", "pt-2", "border-top");
849
+ let ToastDismissButton = document.createElement("button");
850
+ ToastDismissButton.type = "button";
851
+ ToastDismissButton.classList.add("btn", "btn-secondary", "btn-sm", "me-2");
852
+ ToastDismissButton.innerText = "忽略";
853
+ ToastDismissButton.addEventListener("click", () => {
854
+ RequestAPI("ReadBBSMention", {
855
+ "MentionID": Number(MentionList[i].MentionID)
856
+ }, () => { });
857
+ Toast.remove();
858
+ });
859
+ ToastFooter.appendChild(ToastDismissButton);
860
+ let ToastViewButton = document.createElement("button");
861
+ ToastViewButton.type = "button";
862
+ ToastViewButton.classList.add("btn", "btn-primary", "btn-sm");
863
+ ToastViewButton.innerText = "查看";
864
+ ToastViewButton.addEventListener("click", () => {
865
+ open("https://www.xmoj.tech/discuss3/thread.php?tid=" + MentionList[i].PostID, "_blank");
866
+ RequestAPI("ReadBBSMention", {
867
+ "MentionID": Number(MentionList[i].MentionID)
868
+ }, () => { });
869
+ });
870
+ ToastFooter.appendChild(ToastViewButton);
871
+ ToastBody.appendChild(ToastFooter);
872
+ Toast.appendChild(ToastBody);
873
+ ToastContainer.appendChild(Toast);
874
+ new bootstrap.Toast(Toast).show();
875
+ }
876
+ }
877
+ });
878
+ }
879
+ if (UtilityEnabled("MessagePopup")) {
880
+ RequestAPI("GetMailMentionList", {}, async (Response) => {
881
+ if (Response.Success) {
882
+ if (!UtilityEnabled("BBSPopup")) {
883
+ ToastContainer.innerHTML = "";
884
+ }
885
+ let MentionList = Response.Data.MentionList;
886
+ for (let i = 0; i < MentionList.length; i++) {
887
+ let Toast = document.createElement("div");
888
+ Toast.classList.add("toast");
889
+ Toast.setAttribute("role", "alert");
890
+ let ToastHeader = document.createElement("div");
891
+ ToastHeader.classList.add("toast-header");
892
+ let ToastTitle = document.createElement("strong");
893
+ ToastTitle.classList.add("me-auto");
894
+ ToastTitle.innerHTML = "提醒:有新消息";
895
+ ToastHeader.appendChild(ToastTitle);
896
+ let ToastTime = document.createElement("small");
897
+ ToastTime.classList.add("text-body-secondary");
898
+ ToastTime.innerHTML = GetRelativeTime(MentionList[i].MentionTime);
899
+ ToastHeader.appendChild(ToastTime);
900
+ let ToastCloseButton = document.createElement("button");
901
+ ToastCloseButton.type = "button";
902
+ ToastCloseButton.classList.add("btn-close");
903
+ ToastCloseButton.setAttribute("data-bs-dismiss", "toast");
904
+ ToastHeader.appendChild(ToastCloseButton);
905
+ Toast.appendChild(ToastHeader);
906
+ let ToastBody = document.createElement("div");
907
+ ToastBody.classList.add("toast-body");
908
+ let ToastUser = document.createElement("span");
909
+ GetUsernameHTML(ToastUser, MentionList[i].FromUserID);
910
+ ToastBody.appendChild(ToastUser);
911
+ ToastBody.innerHTML += " 给你发了一封短消息";
912
+ let ToastFooter = document.createElement("div");
913
+ ToastFooter.classList.add("mt-2", "pt-2", "border-top");
914
+ let ToastDismissButton = document.createElement("button");
915
+ ToastDismissButton.type = "button";
916
+ ToastDismissButton.classList.add("btn", "btn-secondary", "btn-sm", "me-2");
917
+ ToastDismissButton.innerText = "忽略";
918
+ ToastDismissButton.addEventListener("click", () => {
919
+ RequestAPI("ReadMailMention", {
920
+ "MentionID": Number(MentionList[i].MentionID)
921
+ }, () => { });
922
+ });
923
+ ToastFooter.appendChild(ToastDismissButton);
924
+ let ToastViewButton = document.createElement("button");
925
+ ToastViewButton.type = "button";
926
+ ToastViewButton.classList.add("btn", "btn-primary", "btn-sm");
927
+ ToastViewButton.innerText = "查看";
928
+ ToastViewButton.addEventListener("click", () => {
929
+ open("https://www.xmoj.tech/mail.php?other=" + MentionList[i].FromUserID, "_blank");
930
+ RequestAPI("ReadMailMention", {
931
+ "MentionID": Number(MentionList[i].MentionID)
932
+ }, () => { });
933
+ });
934
+ ToastFooter.appendChild(ToastViewButton);
935
+ ToastBody.appendChild(ToastFooter);
936
+ Toast.appendChild(ToastBody);
937
+ ToastContainer.appendChild(Toast);
938
+ new bootstrap.Toast(Toast).show();
939
+ }
940
+ }
941
+ });
942
+ }
943
+ });
944
+ dispatchEvent(new Event("focus"));
945
+
946
+
947
+ if (location.pathname == "/index.php" || location.pathname == "/") {
948
+ if (new URL(location.href).searchParams.get("ByUserScript") != null) {
949
+ localStorage.setItem("UserScript-Opened", "true");
950
+ let Container = document.getElementsByClassName("mt-3")[0];
951
+ Container.innerHTML = "";
952
+ let Alert = document.createElement("div");
953
+ Alert.classList.add("alert");
954
+ Alert.classList.add("alert-primary");
955
+ Alert.role = "alert";
956
+ Alert.innerHTML = `欢迎您使用XMOJ增强脚本!点击
957
+ <a class="alert-link" href="https://www.xmoj.tech/modifypage.php?ByUserScript=1" target="_blank">此处</a>
958
+ 查看更新日志。`;
959
+ Container.appendChild(Alert);
960
+ let UtilitiesCard = document.createElement("div");
961
+ UtilitiesCard.classList.add("card");
962
+ UtilitiesCard.classList.add("mb-3");
963
+ let UtilitiesCardHeader = document.createElement("div");
964
+ UtilitiesCardHeader.classList.add("card-header");
965
+ UtilitiesCardHeader.innerText = "XMOJ增强脚本功能列表";
966
+ UtilitiesCard.appendChild(UtilitiesCardHeader);
967
+ let UtilitiesCardBody = document.createElement("div");
968
+ UtilitiesCardBody.classList.add("card-body");
969
+ let CreateList = (Data) => {
970
+ let List = document.createElement("ul");
971
+ List.classList.add("list-group");
972
+ for (let i = 0; i < Data.length; i++) {
973
+ let Row = document.createElement("li");
974
+ Row.classList.add("list-group-item");
975
+ if (Data[i].Type == "A") {
976
+ Row.classList.add("list-group-item-success");
977
+ }
978
+ else if (Data[i].Type == "F") {
979
+ Row.classList.add("list-group-item-warning");
980
+ }
981
+ else if (Data[i].Type == "D") {
982
+ Row.classList.add("list-group-item-danger");
983
+ }
984
+ if (Data[i].Children == undefined) {
985
+ let CheckBox = document.createElement("input");
986
+ CheckBox.classList.add("form-check-input");
987
+ CheckBox.classList.add("me-1");
988
+ CheckBox.type = "checkbox";
989
+ CheckBox.id = Data[i].ID;
990
+ if (localStorage.getItem("UserScript-Setting-" + Data[i].ID) == null) {
991
+ localStorage.setItem("UserScript-Setting-" + Data[i].ID, "true");
992
+ }
993
+ if (localStorage.getItem("UserScript-Setting-" + Data[i].ID) == "false") {
994
+ CheckBox.checked = false;
995
+ }
996
+ else {
997
+ CheckBox.checked = true;
998
+ }
999
+ CheckBox.addEventListener("change", () => {
1000
+ return localStorage.setItem("UserScript-Setting-" + Data[i].ID, CheckBox.checked);
1001
+ });
1002
+
1003
+ Row.appendChild(CheckBox);
1004
+ let Label = document.createElement("label");
1005
+ Label.classList.add("form-check-label");
1006
+ Label.htmlFor = Data[i].ID;
1007
+ Label.innerText = Data[i].Name;
1008
+ Row.appendChild(Label);
1009
+ }
1010
+ else {
1011
+ let Label = document.createElement("label");
1012
+ Label.innerText = Data[i].Name;
1013
+ Row.appendChild(Label);
1014
+ }
1015
+ if (Data[i].Children != undefined) {
1016
+ Row.appendChild(CreateList(Data[i].Children));
1017
+ }
1018
+ List.appendChild(Row);
1019
+ }
1020
+ return List;
1021
+ };
1022
+ UtilitiesCardBody.appendChild(CreateList([
1023
+ { "ID": "ACMRank", "Type": "A", "Name": "比赛ACM排名,并且能下载ACM排名" },
1024
+ { "ID": "Discussion", "Type": "F", "Name": "恢复讨论与短消息功能" },
1025
+ { "ID": "MoreSTD", "Type": "F", "Name": "查看到更多标程" },
1026
+ {
1027
+ "ID": "StudyMode", "Type": "A", "Name": "学术模式", "Children": [
1028
+ { "ID": "ApplyData", "Type": "A", "Name": "获取数据功能" },
1029
+ { "ID": "AutoCheat", "Type": "A", "Name": "自动提交当年代码" }
1030
+ ]
1031
+ },
1032
+ { "ID": "Rating", "Type": "A", "Name": "添加用户评分和用户名颜色" },
1033
+ { "ID": "AutoRefresh", "Type": "A", "Name": "比赛列表、比赛排名界面自动刷新" },
1034
+ { "ID": "AutoCountdown", "Type": "A", "Name": "比赛列表等界面的时间自动倒计时" },
1035
+ { "ID": "DownloadPlayback", "Type": "A", "Name": "回放视频增加下载功能" },
1036
+ { "ID": "ImproveACRate", "Type": "A", "Name": "自动提交已AC题目以提高AC率" },
1037
+ { "ID": "AutoO2", "Type": "F", "Name": "代码提交界面自动选择O2优化" },
1038
+ {
1039
+ "ID": "Beautify", "Type": "F", "Name": "美化界面", "Children": [
1040
+ { "ID": "NewBootstrap", "Type": "F", "Name": "使用新版的Bootstrap样式库*" },
1041
+ { "ID": "ResetType", "Type": "F", "Name": "重新排版*" },
1042
+ { "ID": "AddColorText", "Type": "A", "Name": "增加彩色文字" },
1043
+ { "ID": "AddUnits", "Type": "A", "Name": "状态界面内存与耗时添加单位" },
1044
+ { "ID": "DarkMode", "Type": "A", "Name": "使用暗色模式" },
1045
+ { "ID": "AddAnimation", "Type": "A", "Name": "增加动画" },
1046
+ { "ID": "ReplaceYN", "Type": "F", "Name": "题目前对错的Y和N替换为勾和叉" },
1047
+ { "ID": "RemoveAlerts", "Type": "D", "Name": "去除多余反复的提示" },
1048
+ { "ID": "Translate", "Type": "F", "Name": "统一使用中文,翻译了部分英文*" },
1049
+ { "ID": "ReplaceLinks", "Type": "F", "Name": "将网站中所有以方括号包装的链接替换为按钮" },
1050
+ { "ID": "RemoveUseless", "Type": "D", "Name": "删去无法使用的功能*" },
1051
+ { "ID": "ReplaceXM", "Type": "F", "Name": "将网站中所有“小明”和“我”关键字替换为“高老师”,所有“小红”替换为“徐师娘”,所有“小粉”替换为“彩虹”,所有“下海”、“海上”替换为“上海”" }
1052
+ ]
1053
+ },
1054
+ { "ID": "AutoLogin", "Type": "A", "Name": "在需要登录的界面自动跳转到登陆界面" },
1055
+ { "ID": "SavePassword", "Type": "A", "Name": "自动保存用户名与密码,免去每次手动输入密码的繁琐" },
1056
+ { "ID": "CopySamples", "Type": "F", "Name": "题目界面测试样例有时复制无效" },
1057
+ { "ID": "RefreshSolution", "Type": "F", "Name": "状态页面结果自动刷新每次只能刷新一个" },
1058
+ { "ID": "CopyMD", "Type": "A", "Name": "复制题目或题解内容" },
1059
+ { "ID": "OpenAllProblem", "Type": "A", "Name": "比赛题目界面一键打开所有题目" },
1060
+ {
1061
+ "ID": "CheckCode", "Type": "A", "Name": "提交代码前对代码进行检查", "Children": [
1062
+ { "ID": "IOFile", "Type": "A", "Name": "是否使用了文件输入输出(如果需要使用)" },
1063
+ { "ID": "CompileError", "Type": "A", "Name": "是否有编译错误" }
1064
+ ]
1065
+ },
1066
+ { "ID": "ExportACCode", "Type": "F", "Name": "导出AC代码每一道题目一个文件" },
1067
+ { "ID": "LoginFailed", "Type": "F", "Name": "修复登录后跳转失败*" },
1068
+ { "ID": "NewDownload", "Type": "A", "Name": "下载页面增加下载内容" },
1069
+ { "ID": "CompareSource", "Type": "A", "Name": "比较代码" },
1070
+ { "ID": "BBSPopup", "Type": "A", "Name": "讨论提醒" },
1071
+ { "ID": "MessagePopup", "Type": "A", "Name": "短消息提醒" },
1072
+ { "ID": "DebugMode", "Type": "A", "Name": "调试模式(仅供开发者使用)" }
1073
+ ]));
1074
+ let UtilitiesCardFooter = document.createElement("div");
1075
+ UtilitiesCardFooter.className = "card-footer text-muted";
1076
+ UtilitiesCardFooter.innerText = "* 不建议关闭,可能会导致系统不稳定、界面错乱、功能缺失等问题\n绿色:增加功能 黄色:修改功能 红色:删除功能";
1077
+ UtilitiesCardBody.appendChild(UtilitiesCardFooter);
1078
+ UtilitiesCard.appendChild(UtilitiesCardBody);
1079
+ Container.appendChild(UtilitiesCard);
1080
+ let FeedbackCard = document.createElement("div");
1081
+ FeedbackCard.className = "card mb-3";
1082
+ let FeedbackCardHeader = document.createElement("div");
1083
+ FeedbackCardHeader.className = "card-header";
1084
+ FeedbackCardHeader.innerText = "反馈、源代码、联系作者";
1085
+ FeedbackCard.appendChild(FeedbackCardHeader);
1086
+ let FeedbackCardBody = document.createElement("div");
1087
+ FeedbackCardBody.className = "card-body";
1088
+ let FeedbackCardText = document.createElement("p");
1089
+ FeedbackCardText.className = "card-text";
1090
+ FeedbackCardText.innerText = "如果您有任何建议或者发现了bug,请前往本项目的GitHub页面并提交issue。提交issue前请先搜索是否有相同的issue,如果有请在该issue下留言。请在issue中尽可能详细地描述您的问题,并且附上您的浏览器版本、操作系统版本、脚本版本、复现步骤等信息。谢谢您支持本项目。";
1091
+ FeedbackCardBody.appendChild(FeedbackCardText);
1092
+ let FeedbackCardLink = document.createElement("a");
1093
+ FeedbackCardLink.className = "card-link";
1094
+ FeedbackCardLink.innerText = "GitHub";
1095
+ FeedbackCardLink.href = "https://github.com/XMOJ-Script-dev/XMOJ-Script";
1096
+ FeedbackCardBody.appendChild(FeedbackCardLink);
1097
+ FeedbackCard.appendChild(FeedbackCardBody);
1098
+ Container.appendChild(FeedbackCard);
1099
+ }
1100
+ else {
1101
+ let Temp = document.querySelector("body > div > div.mt-3 > div > div.col-md-8").children;
1102
+ let NewsData = [];
1103
+ for (let i = 0; i < Temp.length; i += 2) {
1104
+ let Title = Temp[i].children[0].innerText;
1105
+ let Time = 0;
1106
+ if (Temp[i].children[1] != null) {
1107
+ Time = Temp[i].children[1].innerText;
1108
+ }
1109
+ let Body = Temp[i + 1].innerHTML;
1110
+ NewsData.push({ "Title": Title, "Time": new Date(Time), "Body": Body });
1111
+ }
1112
+ document.querySelector("body > div > div.mt-3 > div > div.col-md-8").innerHTML = "";
1113
+ for (let i = 0; i < NewsData.length; i++) {
1114
+ let NewsRow = document.createElement("div");
1115
+ NewsRow.className = "cnt-row";
1116
+ let NewsRowHead = document.createElement("div");
1117
+ NewsRowHead.className = "cnt-row-head title";
1118
+ NewsRowHead.innerText = NewsData[i].Title;
1119
+ if (NewsData[i].Time != 0) {
1120
+ NewsRowHead.innerHTML += "<small class=\"ms-3\">" + NewsData[i].Time.toLocaleDateString() + "</small>";
1121
+ }
1122
+ NewsRow.appendChild(NewsRowHead);
1123
+ let NewsRowBody = document.createElement("div");
1124
+ NewsRowBody.className = "cnt-row-body";
1125
+ NewsRowBody.innerHTML = NewsData[i].Body;
1126
+ NewsRow.appendChild(NewsRowBody);
1127
+ document.querySelector("body > div > div.mt-3 > div > div.col-md-8").appendChild(NewsRow);
1128
+ }
1129
+ let CountDownData = document.querySelector("#countdown_list").innerHTML;
1130
+ document.querySelector("body > div > div.mt-3 > div > div.col-md-4").innerHTML = `<div class="cnt-row">
1131
+ <div class="cnt-row-head title">倒计时</div>
1132
+ <div class="cnt-row-body">${CountDownData}</div>
1133
+ </div>`;
1134
+ }
1135
+ } else if (location.pathname == "/problemset.php") {
1136
+ if (UtilityEnabled("Translate")) {
1137
+ document.querySelector("body > div > div.mt-3 > center > table:nth-child(2) > tbody > tr > td:nth-child(2) > form > input").placeholder = "题目编号";
1138
+ document.querySelector("body > div > div.mt-3 > center > table:nth-child(2) > tbody > tr > td:nth-child(2) > form > button").innerText = "确认";
1139
+ document.querySelector("body > div > div.mt-3 > center > table:nth-child(2) > tbody > tr > td:nth-child(3) > form > input").placeholder = "标题或内容";
1140
+ document.querySelector("#problemset > thead > tr > th:nth-child(1)").innerText = "状态";
1141
+ }
1142
+ if (UtilityEnabled("ResetType")) {
1143
+ document.querySelector("#problemset > thead > tr > th:nth-child(1)").style.width = "5%";
1144
+ document.querySelector("#problemset > thead > tr > th:nth-child(2)").style.width = "10%";
1145
+ document.querySelector("#problemset > thead > tr > th:nth-child(3)").style.width = "75%";
1146
+ document.querySelector("#problemset > thead > tr > th:nth-child(4)").style.width = "5%";
1147
+ document.querySelector("#problemset > thead > tr > th:nth-child(5)").style.width = "5%";
1148
+ }
1149
+ document.querySelector("body > div > div.mt-3 > center > table:nth-child(2)").outerHTML = `
1150
+ <div class="row">
1151
+ <div class="center col-md-3"></div>
1152
+ <div class="col-md-2">
1153
+ <form action="problem.php" class="input-group">
1154
+ <input class="form-control" type="number" name="id" placeholder="题目编号" min="0">
1155
+ <button class="btn btn-outline-secondary" type="submit">跳转</button>
1156
+ </form>
1157
+ </div>
1158
+ <div class="col-md-4">
1159
+ <form action="problemset.php" class="input-group">
1160
+ <input class="form-control" type="text" name="search" placeholder="标题或内容">
1161
+ <button class="btn btn-outline-secondary" type="submit">查找</button>
1162
+ </form>
1163
+ </div>
1164
+ </div>`;
1165
+ if (SearchParams.get("search") != null) {
1166
+ document.querySelector("body > div > div.mt-3 > center > div > div:nth-child(3) > form > input").value = SearchParams.get("search");
1167
+ }
1168
+
1169
+ let Temp = document.querySelector("#problemset").rows;
1170
+ for (let i = 1; i < Temp.length; i++) {
1171
+ localStorage.setItem("UserScript-Problem-" + Temp[i].children[1].innerText + "-Name",
1172
+ Temp[i].children[2].innerText);
1173
+ }
1174
+ } else if (location.pathname == "/problem.php") {
1175
+ if (SearchParams.get("cid") != null) {
1176
+ document.getElementsByTagName("h2")[0].innerHTML += " (" +
1177
+ localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") +
1178
+ "-Problem-" + SearchParams.get("pid") + "-PID") +
1179
+ ")";
1180
+ }
1181
+ if (document.querySelector("body > div > div.mt-3 > h2") != null) {
1182
+ document.querySelector("body > div > div.mt-3").innerHTML = "没有此题目或题目对你不可见";
1183
+ setTimeout(() => {
1184
+ location.href = "https://www.xmoj.tech/problemset.php";
1185
+ }, 1000);
1186
+ }
1187
+ else {
1188
+ let PID = localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") +
1189
+ "-Problem-" + SearchParams.get("pid") + "-PID");
1190
+
1191
+ document.querySelector("body > div > div.mt-3 > center").lastChild.style.marginLeft = "10px";
1192
+ //修复提交按钮
1193
+ let SubmitLink = document.querySelector('.mt-3 > center:nth-child(1) > a:nth-child(12)');
1194
+ if (SubmitLink == null) { //如果是比赛题目
1195
+ SubmitLink = document.querySelector('.mt-3 > center:nth-child(1) > a:nth-child(10)');
1196
+ }
1197
+ if (SubmitLink == null) {
1198
+ SubmitLink = document.querySelector('.mt-3 > center:nth-child(1) > a:nth-child(11)');
1199
+ }
1200
+ if (SubmitLink == null) {
1201
+ SubmitLink = document.querySelector('.mt-3 > center:nth-child(1) > a:nth-child(13)');
1202
+ }
1203
+ if (SubmitLink == null) {
1204
+ SubmitLink = document.querySelector('.mt-3 > center:nth-child(1) > a:nth-child(9)');
1205
+ }
1206
+ let SubmitButton = document.createElement('button');
1207
+ SubmitButton.id = 'SubmitButton';
1208
+ SubmitButton.className = 'btn btn-outline-secondary';
1209
+ SubmitButton.textContent = '提交';
1210
+ SubmitButton.href = SubmitLink.href;
1211
+ SubmitButton.onclick = function () {
1212
+ window.location.href = SubmitLink.href;
1213
+ console.log(SubmitLink.href);
1214
+ };
1215
+
1216
+ // Replace the <a> element with the button
1217
+ SubmitLink.parentNode.replaceChild(SubmitButton, SubmitLink);
1218
+ // Remove the button's outer []
1219
+ let str = document.querySelector('.mt-3 > center:nth-child(1)').innerHTML;
1220
+ let target = SubmitButton.outerHTML;
1221
+ let result = str.replace(new RegExp(`(.?)${target}(.?)`, 'g'), target);
1222
+ document.querySelector('.mt-3 > center:nth-child(1)').innerHTML = result;
1223
+ document.querySelector('html body.placeholder-glow div.container div.mt-3 center button#SubmitButton.btn.btn-outline-secondary').onclick = function () {
1224
+ window.location.href = SubmitLink.href;
1225
+ console.log(SubmitLink.href);
1226
+ };
1227
+ Temp = document.querySelectorAll(".sampledata");
1228
+ for (var i = 0; i < Temp.length; i++) {
1229
+ Temp[i].parentElement.className = "card";
1230
+ }
1231
+ if (UtilityEnabled("RemoveUseless")) {
1232
+ document.querySelector("h2.lang_en").remove();
1233
+ document.getElementsByTagName("center")[1].remove();
1234
+ }
1235
+ if (UtilityEnabled("CopySamples")) {
1236
+ $(".copy-btn").click((Event) => {
1237
+ let CurrentButton = $(Event.currentTarget);
1238
+ let span = CurrentButton.parent().last().find(".sampledata");
1239
+ if (!span.length) {
1240
+ CurrentButton.text("未找到代码块").addClass("done");
1241
+ setTimeout(() => {
1242
+ $(".copy-btn").text("复制").removeClass("done");
1243
+ }, 1000);
1244
+ return;
1245
+ }
1246
+ GM_setClipboard(span.text());
1247
+ CurrentButton.text("复制成功").addClass("done");
1248
+ setTimeout(() => {
1249
+ $(".copy-btn").text("复制").removeClass("done");
1250
+ }, 1000);
1251
+ //document.body.removeChild(textarea[0]);
1252
+ });
1253
+ }
1254
+ let IOFileElement = document.querySelector("body > div > div.mt-3 > center > h3");
1255
+ if (IOFileElement != null) {
1256
+ while (IOFileElement.childNodes.length >= 1) {
1257
+ IOFileElement.parentNode.insertBefore(IOFileElement.childNodes[0], IOFileElement);
1258
+ }
1259
+ IOFileElement.parentNode.insertBefore(document.createElement("br"), IOFileElement);
1260
+ IOFileElement.remove();
1261
+ let Temp = document.querySelector("body > div > div.mt-3 > center").childNodes[2].data.trim();
1262
+ let IOFilename = Temp.substring(0, Temp.length - 3);
1263
+ localStorage.setItem("UserScript-Problem-" + PID + "-IOFilename", IOFilename);
1264
+ }
1265
+
1266
+ if (UtilityEnabled("CopyMD")) {
1267
+ await fetch(location.href).then((Response) => {
1268
+ return Response.text();
1269
+ }).then((Response) => {
1270
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
1271
+ let Temp = ParsedDocument.querySelectorAll(".cnt-row");
1272
+ for (let i = 0; i < Temp.length; i++) {
1273
+ if (Temp[i].children[1].children[0].className == "content") {
1274
+ let CopyMDButton = document.createElement("button");
1275
+ CopyMDButton.className = "btn btn-sm btn-outline-secondary copy-btn";
1276
+ CopyMDButton.innerText = "复制";
1277
+ CopyMDButton.style.marginLeft = "10px";
1278
+ CopyMDButton.type = "button";
1279
+ document.querySelectorAll(".cnt-row")[i].children[0].appendChild(CopyMDButton);
1280
+ CopyMDButton.addEventListener("click", () => {
1281
+ GM_setClipboard(Temp[i].children[1].children[0].innerText.trim().replaceAll("\n\t", "\n").replaceAll("\n\n", "\n").replaceAll("\n\n", "\n"));
1282
+ CopyMDButton.innerText = "复制成功";
1283
+ setTimeout(() => {
1284
+ CopyMDButton.innerText = "复制";
1285
+ }, 1000);
1286
+ });
1287
+ }
1288
+ }
1289
+ });
1290
+ }
1291
+
1292
+ if (UtilityEnabled("Discussion")) {
1293
+ let DiscussButton = document.createElement("button");
1294
+ DiscussButton.className = "btn btn-outline-secondary position-relative";
1295
+ DiscussButton.innerHTML = `讨论`;
1296
+ DiscussButton.style.marginLeft = "10px";
1297
+ DiscussButton.type = "button";
1298
+ DiscussButton.addEventListener("click", () => {
1299
+ if (SearchParams.get("cid") != null) {
1300
+ open("https://www.xmoj.tech/discuss3/discuss.php?pid=" + PID, "_blank");
1301
+ }
1302
+ else {
1303
+ open("https://www.xmoj.tech/discuss3/discuss.php?pid=" + SearchParams.get("id"), "_blank");
1304
+ }
1305
+ });
1306
+ document.querySelector("body > div > div.mt-3 > center").appendChild(DiscussButton);
1307
+ let UnreadBadge = document.createElement("span");
1308
+ UnreadBadge.className = "position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger";
1309
+ UnreadBadge.style.display = "none";
1310
+ DiscussButton.appendChild(UnreadBadge);
1311
+
1312
+ let RefreshCount = () => {
1313
+ RequestAPI("GetPostCount", {
1314
+ "ProblemID": Number(PID)
1315
+ }, (Response) => {
1316
+ if (Response.Success) {
1317
+ if (Response.Data.DiscussCount != 0) {
1318
+ UnreadBadge.innerText = Response.Data.DiscussCount;
1319
+ UnreadBadge.style.display = "";
1320
+ }
1321
+ }
1322
+ });
1323
+ };
1324
+ RefreshCount();
1325
+ addEventListener("focus", RefreshCount);
1326
+ }
1327
+
1328
+ let Tables = document.getElementsByTagName("table");
1329
+ for (let i = 0; i < Tables.length; i++) {
1330
+ TidyTable(Tables[i]);
1331
+ }
1332
+ }
1333
+ Style.innerHTML += "code, kbd, pre, samp {";
1334
+ Style.innerHTML += " font-family: monospace, Consolas, 'Courier New';";
1335
+ Style.innerHTML += " font-size: 1rem;";
1336
+ Style.innerHTML += "}";
1337
+ Style.innerHTML += "pre {";
1338
+ Style.innerHTML += " padding: 0.3em 0.5em;";
1339
+ Style.innerHTML += " margin: 0.5em 0;";
1340
+ Style.innerHTML += "}";
1341
+ Style.innerHTML += ".in-out {";
1342
+ Style.innerHTML += " overflow: hidden;";
1343
+ Style.innerHTML += " display: flex;";
1344
+ Style.innerHTML += " padding: 0.5em 0;";
1345
+ Style.innerHTML += "}";
1346
+ Style.innerHTML += ".in-out .in-out-item {";
1347
+ Style.innerHTML += " flex: 1;";
1348
+ Style.innerHTML += " overflow: hidden;";
1349
+ Style.innerHTML += "}";
1350
+ Style.innerHTML += ".cnt-row .title {";
1351
+ Style.innerHTML += " font-weight: bolder;";
1352
+ Style.innerHTML += " font-size: 1.1rem;";
1353
+ Style.innerHTML += "}";
1354
+ Style.innerHTML += ".cnt-row .content {";
1355
+ Style.innerHTML += " overflow: hidden;";
1356
+ Style.innerHTML += "}";
1357
+ Style.innerHTML += "a.copy-btn {";
1358
+ Style.innerHTML += " float: right;";
1359
+ Style.innerHTML += " padding: 0 0.4em;";
1360
+ Style.innerHTML += " border: 1px solid var(--bs-primary);";
1361
+ Style.innerHTML += " border-radius: 3px;";
1362
+ Style.innerHTML += " color: var(--bs-primary);";
1363
+ Style.innerHTML += " cursor: pointer;";
1364
+ Style.innerHTML += "}";
1365
+ Style.innerHTML += "a.copy-btn:hover {";
1366
+ Style.innerHTML += " background-color: var(--bs-secondary-bg);";
1367
+ Style.innerHTML += "}";
1368
+ Style.innerHTML += "a.done, a.done:hover {";
1369
+ Style.innerHTML += " background-color: var(--bs-primary);";
1370
+ Style.innerHTML += " color: white;";
1371
+ Style.innerHTML += "}";
1372
+ } else if (location.pathname == "/status.php") {
1373
+ if (SearchParams.get("ByUserScript") == null) {
1374
+ document.querySelector("body > script:nth-child(5)").remove();
1375
+ if (UtilityEnabled("NewBootstrap")) {
1376
+ document.querySelector("#simform").outerHTML = `<form id="simform" class="justify-content-center form-inline row g-2" action="status.php" method="get" style="padding-bottom: 7px;">
1377
+ <input class="form-control" type="text" size="4" name="user_id" value="${CurrentUsername} "style="display: none;">
1378
+ <div class="col-md-1">
1379
+ <label for="problem_id" class="form-label">题目编号</label>
1380
+ <input type="text" class="form-control" id="problem_id" name="problem_id" size="4">
1381
+ </div>
1382
+ <div class="col-md-1">
1383
+ <label for="language" class="form-label">语言</label>
1384
+ <select id="language" name="language" class="form-select">
1385
+ <option value="-1" selected="">全部</option>
1386
+ <option value="0">C</option>
1387
+ <option value="1">C++</option>
1388
+ <option value="2">Pascal</option>
1389
+ </select>
1390
+ </div><div class="col-md-1">
1391
+ <label for="jresult" class="form-label">结果</label>
1392
+ <select id="jresult" name="jresult" class="form-select">
1393
+ <option value="-1" selected="">全部</option>
1394
+ <option value="4">正确</option>
1395
+ <option value="5">格式错误</option>
1396
+ <option value="6">答案错误</option>
1397
+ <option value="7">时间超限</option>
1398
+ <option value="8">内存超限</option>
1399
+ <option value="9">输出超限</option>
1400
+ <option value="10">运行错误</option>
1401
+ <option value="11">编译错误</option>
1402
+ <option value="0">等待</option>
1403
+ <option value="1">等待重判</option>
1404
+ <option value="2">编译中</option>
1405
+ <option value="3">运行并评判</option>
1406
+ </select>
1407
+ </div>
1408
+ <div class="col-md-1">
1409
+ <button type="submit" class="btn btn-primary">查找</button>
1410
+ </div><div id="csrf"></div></form>`;
1411
+ }
1412
+
1413
+ if (UtilityEnabled("ImproveACRate")) {
1414
+ let ImproveACRateButton = document.createElement("button");
1415
+ document.querySelector("body > div.container > div > div.input-append").appendChild(ImproveACRateButton);
1416
+ ImproveACRateButton.className = "btn btn-outline-secondary";
1417
+ ImproveACRateButton.innerText = "提高正确率";
1418
+ ImproveACRateButton.disabled = true;
1419
+ let ACProblems = [];
1420
+ await fetch("https://www.xmoj.tech/userinfo.php?user=" + CurrentUsername)
1421
+ .then((Response) => {
1422
+ return Response.text();
1423
+ }).then((Response) => {
1424
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
1425
+ ImproveACRateButton.innerText += "(" + (parseInt(ParsedDocument.querySelector("#statics > tbody > tr:nth-child(4) > td:nth-child(2)").innerText) / parseInt(ParsedDocument.querySelector("#statics > tbody > tr:nth-child(3) > td:nth-child(2)").innerText) * 100).toFixed(2) + "%)";
1426
+ let Temp = ParsedDocument.querySelector("#statics > tbody > tr:nth-child(2) > td:nth-child(3) > script").innerText.split("\n")[5].split(";");
1427
+ for (let i = 0; i < Temp.length; i++) {
1428
+ ACProblems.push(Number(Temp[i].substring(2, Temp[i].indexOf(","))));
1429
+ }
1430
+ ImproveACRateButton.disabled = false;
1431
+ });
1432
+ ImproveACRateButton.addEventListener("click", async () => {
1433
+ ImproveACRateButton.disabled = true;
1434
+ let SubmitTimes = 3;
1435
+ let Count = 0;
1436
+ let SubmitInterval = setInterval(async () => {
1437
+ if (Count >= SubmitTimes) {
1438
+ clearInterval(SubmitInterval);
1439
+ location.reload();
1440
+ return;
1441
+ }
1442
+ ImproveACRateButton.innerText = "正在提交 (" + (Count + 1) + "/" + SubmitTimes + ")";
1443
+ let PID = ACProblems[Math.floor(Math.random() * ACProblems.length)];
1444
+ let SID = 0;
1445
+ await fetch("https://www.xmoj.tech/status.php?problem_id=" + PID + "&jresult=4")
1446
+ .then((Result) => {
1447
+ return Result.text();
1448
+ }).then((Result) => {
1449
+ let ParsedDocument = new DOMParser().parseFromString(Result, "text/html");
1450
+ SID = ParsedDocument.querySelector("#result-tab > tbody > tr:nth-child(1) > td:nth-child(2)").innerText;
1451
+ });
1452
+ let Code = "";
1453
+ await fetch("https://www.xmoj.tech/getsource.php?id=" + SID)
1454
+ .then((Response) => {
1455
+ return Response.text();
1456
+ }).then((Response) => {
1457
+ Code = Response.substring(0, Response.indexOf("/**************************************************************")).trim();
1458
+ });
1459
+ await fetch("https://www.xmoj.tech/submit.php", {
1460
+ "headers": {
1461
+ "content-type": "application/x-www-form-urlencoded"
1462
+ },
1463
+ "referrer": "https://www.xmoj.tech/submitpage.php?id=" + PID,
1464
+ "method": "POST",
1465
+ "body": "id=" + PID + "&" +
1466
+ "language=1&" +
1467
+ "source=" + encodeURIComponent(Code) + "&" +
1468
+ "enable_O2=on"
1469
+ });
1470
+ Count++;
1471
+ }, 1000);
1472
+ });
1473
+ ImproveACRateButton.style.marginBottom = ImproveACRateButton.style.marginRight = "7px";
1474
+ ImproveACRateButton.style.marginRight = "7px";
1475
+ }
1476
+ if (UtilityEnabled("CompareSource")) {
1477
+ let CompareButton = document.createElement("button");
1478
+ document.querySelector("body > div.container > div > div.input-append").appendChild(CompareButton);
1479
+ CompareButton.className = "btn btn-outline-secondary";
1480
+ CompareButton.innerText = "比较提交记录";
1481
+ CompareButton.addEventListener("click", () => {
1482
+ location.href = "https://www.xmoj.tech/comparesource.php";
1483
+ });
1484
+ CompareButton.style.marginBottom = "7px";
1485
+ }
1486
+ if (UtilityEnabled("ResetType")) {
1487
+ document.querySelector("#result-tab > thead > tr > th:nth-child(1)").remove();
1488
+ document.querySelector("#result-tab > thead > tr > th:nth-child(2)").remove();
1489
+ document.querySelector("#result-tab > thead > tr > th:nth-child(10)").innerHTML = "开启O2";
1490
+ }
1491
+ let Temp = document.querySelector("#result-tab > tbody").childNodes;
1492
+ let SolutionIDs = [];
1493
+ for (let i = 1; i < Temp.length; i += 2) {
1494
+ let SID = Number(Temp[i].childNodes[1].innerText);
1495
+ SolutionIDs.push(SID);
1496
+ if (UtilityEnabled("ResetType")) {
1497
+ Temp[i].childNodes[0].remove();
1498
+ Temp[i].childNodes[0].innerHTML = "<a href=\"https://www.xmoj.tech/showsource.php?id=" + SID + "\">" + SID + "</a> " +
1499
+ "<a href=\"" + Temp[i].childNodes[6].children[1].href + "\">重交</a>";
1500
+ Temp[i].childNodes[1].remove();
1501
+ Temp[i].childNodes[1].children[0].removeAttribute("class");
1502
+ Temp[i].childNodes[3].childNodes[0].innerText = SizeToStringSize(Temp[i].childNodes[3].childNodes[0].innerText);
1503
+ Temp[i].childNodes[4].childNodes[0].innerText = TimeToStringTime(Temp[i].childNodes[4].childNodes[0].innerText);
1504
+ Temp[i].childNodes[5].innerText = Temp[i].childNodes[5].childNodes[0].innerText;
1505
+ Temp[i].childNodes[6].innerText = SizeToStringSize(Temp[i].childNodes[6].innerText.substring(0, Temp[i].childNodes[6].innerText.length - 1));
1506
+ Temp[i].childNodes[9].innerText = (Temp[i].childNodes[9].innerText == "" ? "否" : "是");
1507
+ }
1508
+ if (SearchParams.get("cid") === null) {
1509
+ localStorage.setItem("UserScript-Solution-" + SID + "-Problem",
1510
+ Temp[i].childNodes[1].innerText);
1511
+ }
1512
+ else {
1513
+ localStorage.setItem("UserScript-Solution-" + SID + "-Contest",
1514
+ SearchParams.get("cid"));
1515
+ localStorage.setItem("UserScript-Solution-" + SID + "-PID-Contest",
1516
+ Temp[i].childNodes[1].innerText.charAt(0));
1517
+ }
1518
+ }
1519
+
1520
+ if (UtilityEnabled("RefreshSolution")) {
1521
+ let StdList;
1522
+ await new Promise((Resolve) => {
1523
+ RequestAPI("GetStdList", {}, async (Result) => {
1524
+ if (Result.Success) {
1525
+ StdList = Result.Data.StdList;
1526
+ Resolve();
1527
+ }
1528
+ })
1529
+ });
1530
+
1531
+ let Rows = document.getElementById("result-tab").rows;
1532
+ let Points = Array();
1533
+ for (let i = 1; i <= SolutionIDs.length; i++) {
1534
+ Rows[i].cells[2].className = "td_result";
1535
+ let SolutionID = SolutionIDs[i - 1];
1536
+ if (Rows[i].cells[2].children.length == 2) {
1537
+ Points[SolutionID] = Rows[i].cells[2].children[1].innerText;
1538
+ Rows[i].cells[2].children[1].remove();
1539
+ }
1540
+ Rows[i].cells[2].innerHTML += "<img style=\"margin-left: 10px\" height=\"18\" width=\"18\" src=\"image/loader.gif\">";
1541
+ setTimeout(() => {
1542
+ RefreshResult(SolutionID);
1543
+ }, 0);
1544
+ }
1545
+
1546
+ let RefreshResult = async (SolutionID) => {
1547
+ let CurrentRow = null;
1548
+ let Rows = document.getElementById("result-tab").rows;
1549
+ for (let i = 0; i < SolutionIDs.length; i++) {
1550
+ if (SolutionIDs[i] == SolutionID) {
1551
+ CurrentRow = Rows[i + 1];
1552
+ break;
1553
+ }
1554
+ }
1555
+ await fetch("status-ajax.php?solution_id=" + SolutionID)
1556
+ .then((Response) => {
1557
+ return Response.text();
1558
+ })
1559
+ .then((Response) => {
1560
+ let PID = 0;
1561
+ if (SearchParams.get("cid") === null) {
1562
+ PID = localStorage.getItem("UserScript-Solution-" + SolutionID + "-Problem");
1563
+ } else {
1564
+ PID = localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") + "-Problem-" + (CurrentRow.cells[1].innerText.charCodeAt(0) - 65) + "-PID");
1565
+ }
1566
+ let ResponseData = Response.split(",");
1567
+ CurrentRow.cells[3].innerHTML = "<div id=\"center\" class=\"red\">" + SizeToStringSize(ResponseData[1]) + "</div>";
1568
+ CurrentRow.cells[4].innerHTML = "<div id=\"center\" class=\"red\">" + TimeToStringTime(ResponseData[2]) + "</div>";
1569
+ let TempHTML = "<a href=\"" + (ResponseData[0] == 11 ? "ce" : "re") + "info.php?sid=" + SolutionID + "\" class=\"" + judge_color[ResponseData[0]] + "\">";
1570
+ TempHTML += judge_result[ResponseData[0]];
1571
+ TempHTML += "</a>";
1572
+ if (Points[SolutionID] != undefined) {
1573
+ TempHTML += "<span style=\"margin-left: 5px\" class=\"badge text-bg-info\">" + Points[SolutionID] + "</span>";
1574
+ if (Points[SolutionID].substring(0, Points[SolutionID].length - 1) >= 50) {
1575
+ TempHTML += `<a href="https://www.xmoj.tech/showsource.php?pid=${PID}&ByUserScript=1" class="ms-1 link-secondary">查看标程</a>`;
1576
+ }
1577
+ }
1578
+ if (ResponseData[0] < 4) {
1579
+ setTimeout(() => {
1580
+ RefreshResult(SolutionID)
1581
+ }, 500);
1582
+ TempHTML += "<img style=\"margin-left: 5px\" height=\"18\" width=\"18\" src=\"image/loader.gif\">";
1583
+ }
1584
+ else if (ResponseData[0] == 4 && UtilityEnabled("UploadStd")) {
1585
+ if (SearchParams.get("cid") == null)
1586
+ CurrentRow.cells[1].innerText;
1587
+ let Std = StdList.find((Element) => {
1588
+ return Element == Number(PID);
1589
+ });
1590
+ if (Std != undefined) {
1591
+ TempHTML += "✅";
1592
+ }
1593
+ else {
1594
+ RequestAPI("UploadStd", {
1595
+ "ProblemID": Number(PID),
1596
+ }, (Result) => {
1597
+ if (Result.Success) {
1598
+ CurrentRow.cells[2].innerHTML += "🆗";
1599
+ }
1600
+ else {
1601
+ CurrentRow.cells[2].innerHTML += "⚠️";
1602
+ }
1603
+ });
1604
+ }
1605
+ }
1606
+ CurrentRow.cells[2].innerHTML = TempHTML;
1607
+ });
1608
+ };
1609
+ }
1610
+ }
1611
+ } else if (location.pathname == "/contest.php") {
1612
+ if (UtilityEnabled("AutoCountdown")) {
1613
+ clock = () => { }
1614
+ }
1615
+ if (location.href.indexOf("?cid=") == -1) {
1616
+ if (UtilityEnabled("ResetType")) {
1617
+ document.querySelector("body > div > div.mt-3 > center").innerHTML =
1618
+ String(document.querySelector("body > div > div.mt-3 > center").innerHTML).replaceAll("ServerTime:", "服务器时间:");
1619
+ document.querySelector("body > div > div.mt-3 > center > table").style.marginTop = "10px";
1620
+
1621
+ document.querySelector("body > div > div.mt-3 > center > form").outerHTML = `<div class="row">
1622
+ <div class="col-md-4"></div>
1623
+ <form method="post" action="contest.php" class="col-md-4">
1624
+ <div class="input-group">
1625
+ <input name="keyword" type="text" class="form-control" spellcheck="false" data-ms-editor="true">
1626
+ <input type="submit" value="搜索" class="btn btn-outline-secondary">
1627
+ </div>
1628
+ </form>
1629
+ </div>`;
1630
+ }
1631
+ if (UtilityEnabled("Translate")) {
1632
+ document.querySelector("body > div > div.mt-3 > center > table > thead > tr").childNodes[0].innerText = "编号";
1633
+ document.querySelector("body > div > div.mt-3 > center > table > thead > tr").childNodes[1].innerText = "标题";
1634
+ document.querySelector("body > div > div.mt-3 > center > table > thead > tr").childNodes[2].innerText = "状态";
1635
+ document.querySelector("body > div > div.mt-3 > center > table > thead > tr").childNodes[3].remove();
1636
+ document.querySelector("body > div > div.mt-3 > center > table > thead > tr").childNodes[3].innerText = "创建者";
1637
+ }
1638
+ let Temp = document.querySelector("body > div > div.mt-3 > center > table > tbody").childNodes;
1639
+ for (let i = 1; i < Temp.length; i++) {
1640
+ let CurrentElement = Temp[i].childNodes[2].childNodes;
1641
+ if (CurrentElement[1].childNodes[0].data.indexOf("运行中") != -1) {
1642
+ let Time = String(CurrentElement[1].childNodes[1].innerText).substring(4);
1643
+ let Day = parseInt(Time.substring(0, Time.indexOf("天"))) || 0;
1644
+ let Hour = parseInt(Time.substring((Time.indexOf("天") == -1 ? 0 : Time.indexOf("天") + 1), Time.indexOf("小时"))) || 0;
1645
+ let Minute = parseInt(Time.substring((Time.indexOf("小时") == -1 ? 0 : Time.indexOf("小时") + 2), Time.indexOf("分"))) || 0;
1646
+ let Second = parseInt(Time.substring((Time.indexOf("分") == -1 ? 0 : Time.indexOf("分") + 1), Time.indexOf("秒"))) || 0;
1647
+ let TimeStamp = new Date().getTime() + diff + ((((isNaN(Day) ? 0 : Day) * 24 + Hour) * 60 + Minute) * 60 + Second) * 1000;
1648
+ CurrentElement[1].childNodes[1].setAttribute("EndTime", TimeStamp);
1649
+ CurrentElement[1].childNodes[1].classList.add("UpdateByJS");
1650
+ } else if (CurrentElement[1].childNodes[0].data.indexOf("开始于") != -1) {
1651
+ let TimeStamp = Date.parse(String(CurrentElement[1].childNodes[0].data).substring(4)) + diff;
1652
+ CurrentElement[1].setAttribute("EndTime", TimeStamp);
1653
+ CurrentElement[1].classList.add("UpdateByJS");
1654
+ } else if (CurrentElement[1].childNodes[0].data.indexOf("已结束") != -1) {
1655
+ let TimeStamp = String(CurrentElement[1].childNodes[0].data).substring(4);
1656
+ CurrentElement[1].childNodes[0].data = " 已结束 ";
1657
+ CurrentElement[1].className = "red";
1658
+ let Temp = document.createElement("span");
1659
+ CurrentElement[1].appendChild(Temp);
1660
+ Temp.className = "green";
1661
+ Temp.innerHTML = TimeStamp;
1662
+ }
1663
+ Temp[i].childNodes[3].style.display = "none";
1664
+ Temp[i].childNodes[4].innerHTML = "<a href=\"https://www.xmoj.tech/userinfo.php?user=" + Temp[i].childNodes[4].innerHTML + "\">" + Temp[i].childNodes[4].innerHTML + "</a>";
1665
+ localStorage.setItem("UserScript-Contest-" + Temp[i].childNodes[0].innerText + "-Name", Temp[i].childNodes[1].innerText);
1666
+ }
1667
+ } else {
1668
+ document.getElementsByTagName("h3")[0].innerHTML =
1669
+ "比赛" + document.getElementsByTagName("h3")[0].innerHTML.substring(7);
1670
+ if (document.querySelector("#time_left") != null) {
1671
+ let EndTime = document.querySelector("body > div > div.mt-3 > center").childNodes[3].data;
1672
+ EndTime = EndTime.substring(EndTime.indexOf("结束时间是:") + 6, EndTime.lastIndexOf("。"));
1673
+ EndTime = new Date(EndTime).getTime();
1674
+ if (new Date().getTime() < EndTime) {
1675
+ document.querySelector("#time_left").classList.add("UpdateByJS");
1676
+ document.querySelector("#time_left").setAttribute("EndTime", EndTime);
1677
+ }
1678
+ }
1679
+ let HTMLData = document.querySelector("body > div > div.mt-3 > center > div").innerHTML;
1680
+ HTMLData = HTMLData.replaceAll("&nbsp;&nbsp;\n&nbsp;&nbsp;", "&nbsp;")
1681
+ HTMLData = HTMLData.replaceAll("<br>开始于: ", "开始时间:")
1682
+ HTMLData = HTMLData.replaceAll("\n结束于: ", "<br>结束时间:")
1683
+ HTMLData = HTMLData.replaceAll("\n订正截止日期: ", "<br>订正截止日期:")
1684
+ HTMLData = HTMLData.replaceAll("\n现在时间: ", "当前时间:")
1685
+ HTMLData = HTMLData.replaceAll("\n状态:", "<br>状态:")
1686
+ document.querySelector("body > div > div.mt-3 > center > div").innerHTML = HTMLData;
1687
+ if (UtilityEnabled("RemoveAlerts") && document.querySelector("body > div > div.mt-3 > center").innerHTML.indexOf("尚未开始比赛") != -1) {
1688
+ document.querySelector("body > div > div.mt-3 > center > a").setAttribute("href",
1689
+ "start_contest.php?cid=" + SearchParams.get("cid"));
1690
+ }
1691
+ else if (UtilityEnabled("AutoRefresh")) {
1692
+ addEventListener("focus", async () => {
1693
+ await fetch(location.href)
1694
+ .then((Response) => {
1695
+ return Response.text();
1696
+ })
1697
+ .then((Response) => {
1698
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
1699
+ let Temp = ParsedDocument.querySelector("#problemset > tbody").children;
1700
+ if (UtilityEnabled("ReplaceYN")) {
1701
+ for (let i = 0; i < Temp.length; i++) {
1702
+ let Status = Temp[i].children[0].innerText;
1703
+ if (Status.indexOf("Y") != -1) {
1704
+ document.querySelector("#problemset > tbody").children[i].children[0].children[0].className = "status status_y";
1705
+ document.querySelector("#problemset > tbody").children[i].children[0].children[0].innerText = "✓";
1706
+ }
1707
+ else if (Status.indexOf("N") != -1) {
1708
+ document.querySelector("#problemset > tbody").children[i].children[0].children[0].className = "status status_n";
1709
+ document.querySelector("#problemset > tbody").children[i].children[0].children[0].innerText = "✗";
1710
+ }
1711
+ }
1712
+ }
1713
+ });
1714
+ });
1715
+ document.querySelector("body > div > div.mt-3 > center > br:nth-child(2)").remove();
1716
+ document.querySelector("body > div > div.mt-3 > center > br:nth-child(2)").remove();
1717
+ document.querySelector("body > div > div.mt-3 > center > div > .red").innerHTML =
1718
+ String(document.querySelector("body > div > div.mt-3 > center > div > .red").innerHTML).replaceAll("<br>", "<br><br>");
1719
+ let StaticButton = document.createElement("button");
1720
+ document.querySelectorAll("body > div > div.mt-3 > center > div > .red")[1].appendChild(StaticButton);
1721
+ StaticButton.className = "btn btn-outline-secondary";
1722
+ StaticButton.innerText = "统计";
1723
+ StaticButton.addEventListener("click", () => {
1724
+ location.href = "https://www.xmoj.tech/conteststatistics.php?cid=" + SearchParams.get("cid");
1725
+ });
1726
+
1727
+ document.querySelector("#problemset > tbody").innerHTML =
1728
+ String(document.querySelector("#problemset > tbody").innerHTML).replaceAll(
1729
+ /\t&nbsp;([0-9]*) &nbsp;&nbsp;&nbsp;&nbsp; 问题 &nbsp;([^<]*)/g,
1730
+ "$2. $1");
1731
+
1732
+ document.querySelector("#problemset > tbody").innerHTML =
1733
+ String(document.querySelector("#problemset > tbody").innerHTML).replaceAll(
1734
+ /\t\*([0-9]*) &nbsp;&nbsp;&nbsp;&nbsp; 问题 &nbsp;([^<]*)/g,
1735
+ "拓展$2. $1");
1736
+
1737
+ if (UtilityEnabled("MoreSTD") && document.querySelector("#problemset > thead > tr").innerHTML.indexOf("标程") != -1) {
1738
+ let Temp = document.querySelector("#problemset > thead > tr").children;
1739
+ for (let i = 0; i < Temp.length; i++) {
1740
+ if (Temp[i].innerText == "标程") {
1741
+ Temp[i].remove();
1742
+ let Temp2 = document.querySelector("#problemset > tbody").children;
1743
+ for (let j = 0; j < Temp2.length; j++) {
1744
+ if (Temp2[j].children[i] != undefined) {
1745
+ Temp2[j].children[i].remove();
1746
+ }
1747
+ }
1748
+ }
1749
+ }
1750
+ document.querySelector("#problemset > thead > tr").innerHTML += "<td width=\"5%\">标程</td>";
1751
+ Temp = document.querySelector("#problemset > tbody").children;
1752
+ for (let i = 0; i < Temp.length; i++) {
1753
+ Temp[i].innerHTML += "<td><a href=\"https://www.xmoj.tech/problem_std.php?cid=" + Number(SearchParams.get("cid")) + "&pid=" + i + "\" target=\"_blank\">打开</a></td>";
1754
+ }
1755
+ }
1756
+
1757
+ Temp = document.querySelector("#problemset > tbody").rows;
1758
+ for (let i = 0; i < Temp.length; i++) {
1759
+ if (Temp[i].childNodes[0].children.length == 0) {
1760
+ Temp[i].childNodes[0].innerHTML = "<div class=\"status\"></div>";
1761
+ }
1762
+ let PID = Temp[i].childNodes[1].innerHTML;
1763
+ if (PID.substring(0, 2) == "拓展") {
1764
+ PID = PID.substring(2);
1765
+ }
1766
+ Temp[i].children[2].children[0].target = "_blank";
1767
+ localStorage.setItem("UserScript-Contest-" + SearchParams.get("cid") + "-Problem-" + i + "-PID",
1768
+ PID.substring(3));
1769
+ localStorage.setItem("UserScript-Problem-" + PID.substring(3) + "-Name",
1770
+ Temp[i].childNodes[2].innerText);
1771
+ }
1772
+ let CheatDiv = document.createElement("div");
1773
+ CheatDiv.style.marginTop = "20px";
1774
+ CheatDiv.style.textAlign = "left";
1775
+ document.querySelector("body > div > div.mt-3 > center").insertBefore(CheatDiv, document.querySelector("#problemset"));
1776
+ if (UtilityEnabled("AutoCheat")) {
1777
+ let AutoCheatButton = document.createElement("button");
1778
+ CheatDiv.appendChild(AutoCheatButton);
1779
+ AutoCheatButton.className = "btn btn-outline-secondary";
1780
+ AutoCheatButton.innerText = "自动提交当年代码";
1781
+ AutoCheatButton.style.marginRight = "5px";
1782
+ AutoCheatButton.disabled = true;
1783
+ let ACProblems = [], ContestProblems = [];
1784
+ const UrlParams = new URLSearchParams(window.location.search);
1785
+ const CID = UrlParams.get("cid");
1786
+ await fetch("https://www.xmoj.tech/userinfo.php?user=" + CurrentUsername)
1787
+ .then((Response) => {
1788
+ return Response.text();
1789
+ }).then((Response) => {
1790
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
1791
+ let Temp = ParsedDocument.querySelector("#statics > tbody > tr:nth-child(2) > td:nth-child(3) > script").innerText.split("\n")[5].split(";");
1792
+ for (let i = 0; i < Temp.length; i++) {
1793
+ ACProblems.push(Number(Temp[i].substring(2, Temp[i].indexOf(","))));
1794
+ }
1795
+ AutoCheatButton.disabled = false;
1796
+ });
1797
+ let Rows = document.querySelector("#problemset > tbody").rows;
1798
+ for (let i = 0; i < Rows.length; i++) {
1799
+ ContestProblems.push(Rows[i].children[1].innerText.substring(Rows[i].children[1].innerText.indexOf('.') + 2)).toFixed;
1800
+ }
1801
+ AutoCheatButton.addEventListener("click", async () => {
1802
+ AutoCheatButton.disabled = true;
1803
+ let Submitted = false;
1804
+ for (let i = 0; i < ContestProblems.length; i++) {
1805
+ let PID = ContestProblems[i];
1806
+ if (ACProblems.indexOf(Number(PID)) == -1) {
1807
+ console.log("Ignoring problem " + PID + " as it has not been solved yet.");
1808
+ continue;
1809
+ }
1810
+ if (Rows[i].children[0].children[0].classList.contains("status_y")) {
1811
+ console.log("Ignoring problem " + PID + " as it has already been solved in this contest.");
1812
+ continue;
1813
+ }
1814
+ console.log("Submitting problem " + PID);
1815
+ Submitted = true;
1816
+ AutoCheatButton.innerHTML = "正在提交 " + PID;
1817
+ let SID = 0;
1818
+ await fetch("https://www.xmoj.tech/status.php?problem_id=" + PID + "&jresult=4")
1819
+ .then((Result) => {
1820
+ return Result.text();
1821
+ }).then((Result) => {
1822
+ let ParsedDocument = new DOMParser().parseFromString(Result, "text/html");
1823
+ SID = ParsedDocument.querySelector("#result-tab > tbody > tr:nth-child(1) > td:nth-child(2)").innerText;
1824
+ });
1825
+ let Code = "";
1826
+ await fetch("https://www.xmoj.tech/getsource.php?id=" + SID)
1827
+ .then((Response) => {
1828
+ return Response.text();
1829
+ }).then((Response) => {
1830
+ Code = Response.substring(0, Response.indexOf("/**************************************************************")).trim();
1831
+ });
1832
+ await fetch("https://www.xmoj.tech/submit.php", {
1833
+ "headers": {
1834
+ "content-type": "application/x-www-form-urlencoded"
1835
+ },
1836
+ "referrer": "https://www.xmoj.tech/submitpage.php?id=" + PID,
1837
+ "method": "POST",
1838
+ "body": "cid=" + CID + "&pid=" + i + "&" +
1839
+ "language=1&" +
1840
+ "source=" + encodeURIComponent(Code) + "&" +
1841
+ "enable_O2=on"
1842
+ });
1843
+ }
1844
+ if (!Submitted) {
1845
+ AutoCheatButton.innerHTML = "没有可以提交的题目!";
1846
+ await new Promise(r => setTimeout(r, 1000));
1847
+ }
1848
+ AutoCheatButton.disabled = false;
1849
+ if (Submitted) location.reload();
1850
+ else AutoCheatButton.innerHTML = "自动提交当年代码";
1851
+ });
1852
+ }
1853
+
1854
+ if (UtilityEnabled("OpenAllProblem")) {
1855
+ let OpenAllButton = document.createElement("button");
1856
+ OpenAllButton.className = "btn btn-outline-secondary";
1857
+ OpenAllButton.innerText = "打开全部题目";
1858
+ OpenAllButton.style.marginRight = "5px";
1859
+ CheatDiv.appendChild(OpenAllButton);
1860
+ OpenAllButton.addEventListener("click", () => {
1861
+ let Rows = document.querySelector("#problemset > tbody").rows;
1862
+ for (let i = 0; i < Rows.length; i++) {
1863
+ open(Rows[i].children[2].children[0].href, "_blank");
1864
+ }
1865
+ });
1866
+ let OpenUnsolvedButton = document.createElement("button");
1867
+ OpenUnsolvedButton.className = "btn btn-outline-secondary";
1868
+ OpenUnsolvedButton.innerText = "打开未解决题目";
1869
+ CheatDiv.appendChild(OpenUnsolvedButton);
1870
+ OpenUnsolvedButton.addEventListener("click", () => {
1871
+ let Rows = document.querySelector("#problemset > tbody").rows;
1872
+ for (let i = 0; i < Rows.length; i++) {
1873
+ if (!Rows[i].children[0].children[0].classList.contains("status_y")) {
1874
+ open(Rows[i].children[2].children[0].href, "_blank");
1875
+ }
1876
+ }
1877
+ });
1878
+ }
1879
+
1880
+ if (UtilityEnabled("ResetType")) {
1881
+ document.querySelector("#problemset > thead > tr > th:nth-child(1)").style.width = "5%";
1882
+ }
1883
+ localStorage.setItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemCount",
1884
+ document.querySelector("#problemset > tbody").rows.length);
1885
+ }
1886
+ }
1887
+ } else if (location.pathname == "/contestrank-oi.php") {
1888
+ if (document.querySelector("#rank") == null) {
1889
+ document.querySelector("body > div > div.mt-3").innerHTML = "<center><h3>比赛排名</h3><a></a><table id=\"rank\"></table>";
1890
+ }
1891
+ if (SearchParams.get("ByUserScript") == null) {
1892
+ if (document.querySelector("body > div > div.mt-3 > center > h3").innerText == "比赛排名") {
1893
+ document.querySelector("#rank").innerText = "比赛暂时还没有排名";
1894
+ }
1895
+ else {
1896
+ document.querySelector("body > div > div.mt-3 > center > h3").innerText =
1897
+ document.querySelector("body > div > div.mt-3 > center > h3").innerText.substring(
1898
+ document.querySelector("body > div > div.mt-3 > center > h3").innerText.indexOf(" -- ") + 4)
1899
+ + "(OI排名)";
1900
+ document.querySelector("#rank > thead > tr > :nth-child(1)").innerText = "排名";
1901
+ document.querySelector("#rank > thead > tr > :nth-child(2)").innerText = "用户";
1902
+ document.querySelector("#rank > thead > tr > :nth-child(3)").innerText = "昵称";
1903
+ document.querySelector("#rank > thead > tr > :nth-child(4)").innerText = "AC数";
1904
+ document.querySelector("#rank > thead > tr > :nth-child(5)").innerText = "得分";
1905
+ let RefreshOIRank = async () => {
1906
+ await fetch(location.href)
1907
+ .then((Response) => {
1908
+ return Response.text()
1909
+ })
1910
+ .then(async (Response) => {
1911
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
1912
+ TidyTable(ParsedDocument.getElementById("rank"));
1913
+ let Temp = ParsedDocument.getElementById("rank").rows;
1914
+ for (var i = 1; i < Temp.length; i++) {
1915
+ let MetalCell = Temp[i].cells[0];
1916
+ let Metal = document.createElement("span");
1917
+ Metal.innerText = MetalCell.innerText;
1918
+ Metal.className = "badge text-bg-primary";
1919
+ MetalCell.innerText = "";
1920
+ MetalCell.appendChild(Metal);
1921
+ GetUsernameHTML(Temp[i].cells[1], Temp[i].cells[1].innerText);
1922
+ Temp[i].cells[2].innerHTML = Temp[i].cells[2].innerText;
1923
+ Temp[i].cells[3].innerHTML = Temp[i].cells[3].innerText;
1924
+ for (let j = 5; j < Temp[i].cells.length; j++) {
1925
+ let InnerText = Temp[i].cells[j].innerText;
1926
+ let BackgroundColor = Temp[i].cells[j].style.backgroundColor;
1927
+ let Red = BackgroundColor.substring(4, BackgroundColor.indexOf(","));
1928
+ let Green = BackgroundColor.substring(BackgroundColor.indexOf(",") + 2, BackgroundColor.lastIndexOf(","));
1929
+ let Blue = BackgroundColor.substring(BackgroundColor.lastIndexOf(",") + 2, BackgroundColor.lastIndexOf(")"));
1930
+ let NoData = (Red == 238 && Green == 238 && Blue == 238);
1931
+ let FirstBlood = (Red == 170 && Green == 170 && Blue == 255);
1932
+ let Solved = (Green == 255);
1933
+ let ErrorCount = "";
1934
+ if (Solved) {
1935
+ ErrorCount = (Blue == 170 ? 5 : (Blue - 51) / 32);
1936
+ }
1937
+ else {
1938
+ ErrorCount = (Blue == 22 ? 15 : (170 - Blue) / 10);
1939
+ }
1940
+ if (NoData) {
1941
+ BackgroundColor = "";
1942
+ }
1943
+ else if (FirstBlood) {
1944
+ BackgroundColor = "rgb(127, 127, 255)";
1945
+ }
1946
+ else if (Solved) {
1947
+ BackgroundColor = "rgb(0, 255, 0, " + Math.max(1 / 10 * (10 - ErrorCount), 0.2) + ")";
1948
+ if (ErrorCount != 0) {
1949
+ InnerText += " (" + (ErrorCount == 5 ? "4+" : ErrorCount) + ")";
1950
+ }
1951
+ }
1952
+ else {
1953
+ BackgroundColor = "rgba(255, 0, 0, " + Math.min(ErrorCount / 10 + 0.2, 1) + ")";
1954
+ if (ErrorCount != 0) {
1955
+ InnerText += " (" + (ErrorCount == 15 ? "14+" : ErrorCount) + ")";
1956
+ }
1957
+ }
1958
+ Temp[i].cells[j].innerHTML = InnerText;
1959
+ Temp[i].cells[j].style.backgroundColor = BackgroundColor;
1960
+ Temp[i].cells[j].style.color = (UtilityEnabled("DarkMode") ? "white" : "black");
1961
+ }
1962
+ }
1963
+ document.querySelector("#rank > tbody").innerHTML = ParsedDocument.querySelector("#rank > tbody").innerHTML;
1964
+ });
1965
+ };
1966
+ RefreshOIRank();
1967
+ if (UtilityEnabled("AutoRefresh")) {
1968
+ addEventListener("focus", RefreshOIRank);
1969
+ }
1970
+ }
1971
+ }
1972
+ else if (UtilityEnabled("ACMRank")) {
1973
+ if (document.querySelector("body > div > div.mt-3 > center > h3").innerText != "比赛排名") {
1974
+ document.querySelector("body > div > div.mt-3 > center > h3").innerText =
1975
+ document.querySelector("body > div > div.mt-3 > center > h3").innerText.substring(
1976
+ document.querySelector("body > div > div.mt-3 > center > h3").innerText.indexOf(" -- ") + 4)
1977
+ + "(ACM排名)";
1978
+ }
1979
+ let RankData = [];
1980
+ let RefreshACMRank = async (ProblemCount) => {
1981
+ let LastPositionX = scrollX;
1982
+ let LastPositionY = scrollY;
1983
+ let NewURL = new URL(location.href);
1984
+ NewURL.pathname = "/contestrank2.php";
1985
+ await fetch(NewURL.toString())
1986
+ .then((Response) => {
1987
+ return Response.text()
1988
+ })
1989
+ .then(async (Response) => {
1990
+ RankData = [];
1991
+
1992
+ let Table = document.querySelector("#rank"); Table.innerHTML = "";
1993
+ let StartPosition = Response.indexOf("var solutions=") + 14;
1994
+ let EndPosition = Response.indexOf("}];", StartPosition) + 2;
1995
+ if (EndPosition == 1) {
1996
+ Table.innerHTML = "暂时还没有人提交呢";
1997
+ }
1998
+ else {
1999
+ let SubmitRecord = JSON.parse(Response.substring(StartPosition, EndPosition));
2000
+
2001
+ for (let i = 0; i < SubmitRecord.length; i++) {
2002
+ let CurrentSubmission = SubmitRecord[i];
2003
+ let CurrentRow = RankData.find((CurrentRow) => {
2004
+ if (CurrentRow.Username == CurrentSubmission.user_id) {
2005
+ return true;
2006
+ }
2007
+ });
2008
+ if (CurrentRow == null) {
2009
+ CurrentRow = {
2010
+ Username: CurrentSubmission.user_id,
2011
+ Nickname: CurrentSubmission.nick,
2012
+ Solved: 0,
2013
+ Penalty: 0,
2014
+ Problem: [],
2015
+ QuickSubmitCount: 0
2016
+ };
2017
+ RankData.push(CurrentRow);
2018
+ }
2019
+ let CurrentProblem = CurrentRow.Problem.find((CurrentRow) => {
2020
+ if (CurrentRow.Index == CurrentSubmission.num) {
2021
+ return true;
2022
+ }
2023
+ });
2024
+ if (CurrentProblem == null) {
2025
+ CurrentProblem = {
2026
+ Index: CurrentSubmission.num,
2027
+ Attempts: [],
2028
+ SolveTime: 0
2029
+ };
2030
+ CurrentRow.Problem.push(CurrentProblem);
2031
+ }
2032
+ if (CurrentSubmission.result == 4 && CurrentProblem.SolveTime == 0) {
2033
+ CurrentProblem.SolveTime = parseInt(CurrentSubmission.in_date);
2034
+ CurrentRow.Solved++;
2035
+ CurrentRow.Penalty += parseInt(CurrentSubmission.in_date) + CurrentProblem.Attempts.length * 20 * 60;
2036
+ }
2037
+ CurrentProblem.Attempts.push({
2038
+ Time: CurrentSubmission.in_date,
2039
+ Result: CurrentSubmission.result
2040
+ });
2041
+ }
2042
+
2043
+ for (let i = 0; i < RankData.length; i++) {
2044
+ for (let j = 0; j < RankData[i].Problem.length; j++) {
2045
+ for (let k = 0; k < RankData[i].Problem.length; k++) {
2046
+ if (j != k && RankData[i].Problem[j].SolveTime != 0 && RankData[i].Problem[k].SolveTime != 0 &&
2047
+ Math.abs(RankData[i].Problem[j].SolveTime - RankData[i].Problem[k].SolveTime) < 60) {
2048
+ RankData[i].QuickSubmitCount++;
2049
+ }
2050
+ }
2051
+ }
2052
+ }
2053
+
2054
+ RankData.sort((a, b) => {
2055
+ if (a.Solved != b.Solved) {
2056
+ return a.Solved < b.Solved ? 1 : -1;
2057
+ } else if (a.Penalty != b.Penalty) {
2058
+ return a.Penalty > b.Penalty ? 1 : -1;
2059
+ }
2060
+ return 0;
2061
+ });
2062
+
2063
+ let Header = document.createElement("thead"); Table.appendChild(Header);
2064
+ let RowHeader = document.createElement("tr"); Header.appendChild(RowHeader);
2065
+ let MetalHeader = document.createElement("th"); RowHeader.appendChild(MetalHeader); MetalHeader.innerText = "排名"; MetalHeader.style.width = "5%";
2066
+ let UsernameHeader = document.createElement("th"); RowHeader.appendChild(UsernameHeader); UsernameHeader.innerText = "用户"; UsernameHeader.style.width = "10%";
2067
+ let NicknameHeader = document.createElement("th"); RowHeader.appendChild(NicknameHeader); NicknameHeader.innerText = "昵称"; NicknameHeader.style.width = "10%";
2068
+ let NameHeader = document.createElement("th"); RowHeader.appendChild(NameHeader); NameHeader.innerText = "姓名"; NameHeader.style.width = "5%";
2069
+ let SolvedHeader = document.createElement("th"); RowHeader.appendChild(SolvedHeader); SolvedHeader.innerText = "AC数"; SolvedHeader.style.width = "5%";
2070
+ let PenaltyHeader = document.createElement("th"); RowHeader.appendChild(PenaltyHeader); PenaltyHeader.innerText = "罚时"; PenaltyHeader.style.width = "10%";
2071
+
2072
+ for (let i = 0; i < ProblemCount; i++) {
2073
+ let ProblemHeader = document.createElement("th"); RowHeader.appendChild(ProblemHeader);
2074
+ let ProblemLink = document.createElement("a"); ProblemHeader.appendChild(ProblemLink);
2075
+ ProblemLink.href = "problem.php?cid=" + SearchParams.get("cid") + "&pid=" + i; ProblemLink.innerText = String.fromCharCode(65 + i);
2076
+ ProblemHeader.classList.add("header"); ProblemHeader.style.width = (50 / ProblemCount) + "%";
2077
+ }
2078
+
2079
+ let Body = document.createElement("tbody"); Table.appendChild(Body);
2080
+ Body.className = "table-group-divider";
2081
+ for (let i = 0; i < RankData.length; i++) {
2082
+ let RowData = RankData[i];
2083
+ let Row = document.createElement("tr"); Body.appendChild(Row);
2084
+ let MetalCell = document.createElement("td"); Row.appendChild(MetalCell);
2085
+ let UsernameCell = document.createElement("td"); Row.appendChild(UsernameCell);
2086
+ let NicknameCell = document.createElement("td"); Row.appendChild(NicknameCell);
2087
+ let NameCell = document.createElement("td"); Row.appendChild(NameCell);
2088
+ let SolvedCell = document.createElement("td"); Row.appendChild(SolvedCell);
2089
+ let PenaltyCell = document.createElement("td"); Row.appendChild(PenaltyCell);
2090
+
2091
+ let Medal = document.createElement("span"); MetalCell.appendChild(Medal);
2092
+ Medal.innerText = i + 1;
2093
+ Medal.classList.add("badge");
2094
+ if (i <= RankData.length * 0.05) {
2095
+ Medal.classList.add("text-bg-danger");
2096
+ }
2097
+ else if (i <= RankData.length * 0.15) {
2098
+ Medal.classList.add("text-bg-warning");
2099
+ }
2100
+ else if (i <= RankData.length * 0.4) {
2101
+ Medal.classList.add("text-bg-primary");
2102
+ }
2103
+ else {
2104
+ Medal.classList.add("text-bg-secondary");
2105
+ }
2106
+
2107
+ let UsernameSpan = document.createElement("span"); UsernameCell.appendChild(UsernameSpan);
2108
+ GetUsernameHTML(UsernameSpan, RowData.Username);
2109
+ if (RowData.Username == CurrentUsername) {
2110
+ Row.classList.add("table-primary");
2111
+ }
2112
+ if (RowData.QuickSubmitCount >= 2) {
2113
+ let QuickSubmitBadge = document.createElement("span"); UsernameCell.appendChild(QuickSubmitBadge);
2114
+ QuickSubmitBadge.innerText = "作弊者";
2115
+ QuickSubmitBadge.className = "badge text-bg-warning ms-2";
2116
+ }
2117
+
2118
+ NicknameCell.innerText = (RowData.Nickname.length < 16 ? RowData.Nickname : RowData.Nickname.substring(0, 15) + "...");
2119
+
2120
+ let Names = {
2121
+ "huangkai": "黄开", "chenlangning": "陈朗宁", "chensiru": "陈斯如", "chentianle": "陈天乐", "chenxuanhe": "陈宣合", "chenzecong": "陈泽聪", "chenzerui": "陈泽睿", "danwenxiao": "单文骁", "dongminghui": "董明辉", "gaochenming": "高晨茗", "guoqingtong": "郭庆桐", "guoruiqun": "郭睿群", "guyuchen": "顾毓辰",
2122
+ "hanshujian": "韩书简", "heshuhan": "贺书瀚", "hexinyi": "何昕弈", "huangmingxuan": "黄铭宣", "huangruina": "黄睿纳", "huangwei": "黄唯", "huyiyang": "胡以杨", "jiangxingyu": "姜星宇", "jingtaiyu": "荆泰宇", "jinweizhe": "金炜喆", "leijiahan": "雷家涵",
2123
+ "lianzhongzhe": "连中哲", "liaoyanxu": "廖彦旭", "lingzixiang": "凌梓翔", "linziyi": "林子懿", "liujianhao": "刘健豪", "liujiankun": "刘健坤", "liuxianyong": "刘先勇", "liuxixian": "刘希贤", "liyihan": "李亦涵", "luojinyang": "罗金阳", "lutianfeng": "陆天枫",
2124
+ "meitianyi": "梅天一", "panyinliang": "潘胤良", "pengyixuan": "彭议萱", "putong": "蒲通", "qianqingyuan": "钱清源", "qidekai": "戚得凯", "shanwenxiao": "单文骁", "shenxichen": "沈熙晨", "shihongxi": "施泓熙", "shimufan": "施慕梵", "shiyichen": "施奕辰",
2125
+ "shiyunhao": "施云浩", "shuxinmo": "舒馨墨", "suiruochen": "隋若宸", "sunyihan": "孙艺涵", "sunyimiao": "孙义淼", "tangchao": "唐潮", "tangyuhan": "唐钰涵", "tanhaoxuan": "谭皓轩", "taoxianyu": "陶羡榆", "wangkangming": "王康明", "wangminghao": "王明浩",
2126
+ "wangmingshuo": "王茗铄", "wangpengyu": "王芃雨", "wangsiyuan3": "王思源", "wangtianqi": "王天琦", "wangzetong": "王泽通", "wanxinlian": "万馨联", "wensiyi": "闻思奕", "wujinhong": "吴锦鸿", "wurunze": "吴润泽", "wuyukai": "巫昱恺", "xiangjicheng": "项际诚",
2127
+ "xiaoguanxun": "肖贯勋", "xiaojiasheng": "肖嘉盛", "xiaruicheng": "夏瑞成", "xiaweimin": "夏蔚民", "xiaxuran": "夏诩然", "xiebingxiu": "谢秉修", "xiebingxiu": "谢秉修", "xieliren": "谢立仁", "xinyihan": "辛轶涵", "xuconghan": "徐从瀚", "xukan": "徐衎",
2128
+ "xuweiyi": "徐维易", "yanghaochen": "杨皓宸", "yezijiong": "叶梓炅", "youzhouhang": "尤周杭", "yuanruiqing": "袁瑞擎", "yutingjun": "于庭郡", "zhangchenming": "张宸铭", "zhangqiuze": "张秋泽", "zhangshuxuan": "张澍萱", "zhangwenda": "张闻达", "zhangyifu": "张亦夫",
2129
+ "zhangyouheng": "张佑恒", "zhaochenshen": "赵晨神", "zhaochenwei": "赵晨伟", "zhengyinan": "郑逸楠", "zhonghongyi": "钟弘毅", "zhoujunyu": "周峻瑜", "zhouziyi": "周子逸", "zhouziyou": "周子游", "zhuchenrui2": "朱晨瑞", "zhuruichen": "朱睿宸", "zhuxule": "朱徐乐",
2130
+ "zhuyikun": "朱奕坤", "leiwenda": "雷文达", "wangyuancheng": "王源成", "zhuyiyang": "朱奕阳", "hanjialin": "韩佳霖", "zhaozichen": "赵紫辰", "zhuaiwei": "朱艾薇", "linlitong": "林立桐", "xuyan": "徐衍", "fenghaochen": "冯皓宸", "lutianlang": "陆天朗", "tangyuhan": "唐钰涵",
2131
+ "jiangbowen": "姜博文", "shangguanbocheng": "上官伯呈", "wangchengqi": "王呈齐", "yanpeitong": "颜培桐", "gongcheng": "龚橙", "weijiefu": "韦杰夫", "": ""
2132
+ };
2133
+ NameCell.innerText = (Names[RowData.Username] == undefined ? "" : Names[RowData.Username]);
2134
+
2135
+ SolvedCell.innerText = RowData.Solved;
2136
+
2137
+ PenaltyCell.innerText = SecondsToString(RowData.Penalty);
2138
+
2139
+ for (let j = 0; j < ProblemCount; j++) {
2140
+ let Problem = document.createElement("td"); Row.appendChild(Problem);
2141
+ let ProblemData = RowData.Problem.find((CurrentRow) => {
2142
+ if (CurrentRow.Index == j) {
2143
+ return true;
2144
+ }
2145
+ });
2146
+ if (ProblemData == undefined) {
2147
+ Problem.style.backgroundColor = "rgba(0, 0, 0, 0)";
2148
+ }
2149
+ else if (ProblemData.SolveTime != 0) {
2150
+ Problem.innerText = SecondsToString(ProblemData.SolveTime) + "(" + ProblemData.Attempts.length + ")";
2151
+ let Color = Math.max(1 / 10 * (10 - ProblemData.Attempts.length), 0.2);
2152
+ Problem.style.backgroundColor = "rgba(0, 255, 0, " + Color + ")";
2153
+ }
2154
+ else {
2155
+ Problem.innerText = "(" + ProblemData.Attempts.length + ")";
2156
+ let Color = Math.min(ProblemData.Attempts.length / 10 + 0.2, 1);
2157
+ Problem.style.backgroundColor = "rgba(255, 0, 0, " + Color + ")";
2158
+ }
2159
+ Problem.style.color = (UtilityEnabled("DarkMode") ? "white" : "black");
2160
+ }
2161
+ }
2162
+
2163
+ TidyTable(Table);
2164
+
2165
+ scrollTo({
2166
+ left: LastPositionX,
2167
+ top: LastPositionY,
2168
+ behavior: "instant"
2169
+ });
2170
+ }
2171
+ });
2172
+ }
2173
+ document.getElementById("rank").style.width = "100%";
2174
+ let DownloadButton = document.createElement("button");
2175
+ document.querySelector("body > div.container > div > center").insertBefore(DownloadButton, document.querySelector("body > div.container > div > center > a"));
2176
+ DownloadButton.className = "btn btn-outline-secondary";
2177
+ DownloadButton.innerText = "下载ACM排名";
2178
+ DownloadButton.style.marginBottom = "20px";
2179
+ DownloadButton.addEventListener("click", () => {
2180
+ location.href = "https://www.xmoj.tech/contestrank.xls.php?cid=" + SearchParams.get("cid");
2181
+ });
2182
+ let ProblemCount = localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemCount");
2183
+ RefreshACMRank(ProblemCount);
2184
+ if (UtilityEnabled("AutoRefresh")) {
2185
+ addEventListener("focus", () => {
2186
+ RefreshACMRank(ProblemCount);
2187
+ });
2188
+ }
2189
+ }
2190
+ Style.innerHTML += "td {";
2191
+ Style.innerHTML += " white-space: nowrap;";
2192
+ Style.innerHTML += "}";
2193
+ document.querySelector("body > div.container > div > center").style.paddingBottom = "10px";
2194
+ document.querySelector("body > div.container > div > center > a").style.display = "none";
2195
+ } else if (location.pathname == "/contestrank-correct.php") {
2196
+ if (document.querySelector("#rank") == null) {
2197
+ document.querySelector("body > div > div.mt-3").innerHTML = "<center><h3>比赛排名</h3><a></a><table id=\"rank\"></table>";
2198
+ }
2199
+ if (document.querySelector("body > div > div.mt-3 > center > h3").innerText == "比赛排名") {
2200
+ document.querySelector("#rank").innerText = "比赛暂时还没有排名";
2201
+ }
2202
+ else {
2203
+ if (UtilityEnabled("ResetType")) {
2204
+ document.querySelector("body > div > div.mt-3 > center > h3").innerText =
2205
+ document.querySelector("body > div > div.mt-3 > center > h3").innerText.substring(
2206
+ document.querySelector("body > div > div.mt-3 > center > h3").innerText.indexOf(" -- ") + 4)
2207
+ + "(订正排名)";
2208
+ document.querySelector("body > div > div.mt-3 > center > a").remove();
2209
+ }
2210
+ document.querySelector("#rank > thead > tr > :nth-child(1)").innerText = "排名";
2211
+ document.querySelector("#rank > thead > tr > :nth-child(2)").innerText = "用户";
2212
+ document.querySelector("#rank > thead > tr > :nth-child(3)").innerText = "昵称";
2213
+ document.querySelector("#rank > thead > tr > :nth-child(4)").innerText = "AC数";
2214
+ document.querySelector("#rank > thead > tr > :nth-child(5)").innerText = "得分";
2215
+ let RefreshCorrectRank = async () => {
2216
+ await fetch(location.href)
2217
+ .then((Response) => {
2218
+ return Response.text()
2219
+ })
2220
+ .then(async (Response) => {
2221
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
2222
+ TidyTable(ParsedDocument.getElementById("rank"));
2223
+ let Temp = ParsedDocument.getElementById("rank").rows;
2224
+ for (var i = 1; i < Temp.length; i++) {
2225
+ let MetalCell = Temp[i].cells[0];
2226
+ let Metal = document.createElement("span");
2227
+ Metal.innerText = MetalCell.innerText;
2228
+ Metal.className = "badge text-bg-primary";
2229
+ MetalCell.innerText = "";
2230
+ MetalCell.appendChild(Metal);
2231
+ GetUsernameHTML(Temp[i].cells[1], Temp[i].cells[1].innerText);
2232
+ Temp[i].cells[2].innerHTML = Temp[i].cells[2].innerText;
2233
+ Temp[i].cells[3].innerHTML = Temp[i].cells[3].innerText;
2234
+ for (let j = 5; j < Temp[i].cells.length; j++) {
2235
+ let InnerText = Temp[i].cells[j].innerText;
2236
+ let BackgroundColor = Temp[i].cells[j].style.backgroundColor;
2237
+ let Red = BackgroundColor.substring(4, BackgroundColor.indexOf(","));
2238
+ let Green = BackgroundColor.substring(BackgroundColor.indexOf(",") + 2, BackgroundColor.lastIndexOf(","));
2239
+ let Blue = BackgroundColor.substring(BackgroundColor.lastIndexOf(",") + 2, BackgroundColor.lastIndexOf(")"));
2240
+ let NoData = (Red == 238 && Green == 238 && Blue == 238);
2241
+ let FirstBlood = (Red == 170 && Green == 170 && Blue == 255);
2242
+ let Solved = (Green == 255);
2243
+ let ErrorCount = "";
2244
+ if (Solved) {
2245
+ ErrorCount = (Blue == 170 ? "4+" : (Blue - 51) / 32);
2246
+ }
2247
+ else {
2248
+ ErrorCount = (Blue == 22 ? "14+" : (170 - Blue) / 10);
2249
+ }
2250
+ if (NoData) {
2251
+ BackgroundColor = "";
2252
+ }
2253
+ else if (FirstBlood) {
2254
+ BackgroundColor = "rgba(127, 127, 255, 0.5)";
2255
+ }
2256
+ else if (Solved) {
2257
+ BackgroundColor = "rgba(0, 255, 0, 0.5)";
2258
+ if (ErrorCount != 0) {
2259
+ InnerText += " (" + ErrorCount + ")";
2260
+ }
2261
+ }
2262
+ else {
2263
+ BackgroundColor = "rgba(255, 0, 0, 0.5)";
2264
+ if (ErrorCount != 0) {
2265
+ InnerText += " (" + ErrorCount + ")";
2266
+ }
2267
+ }
2268
+ Temp[i].cells[j].innerHTML = InnerText;
2269
+ Temp[i].cells[j].style.backgroundColor = BackgroundColor;
2270
+ }
2271
+ }
2272
+ document.querySelector("#rank > tbody").innerHTML = ParsedDocument.querySelector("#rank > tbody").innerHTML;
2273
+ });
2274
+ };
2275
+ RefreshCorrectRank();
2276
+ if (UtilityEnabled("AutoRefresh")) {
2277
+ addEventListener("focus", RefreshCorrectRank);
2278
+ }
2279
+ }
2280
+ } else if (location.pathname == "/submitpage.php") {
2281
+ document.querySelector("body > div > div.mt-3").innerHTML = `<center class="mb-3">` +
2282
+ `<h3>提交代码</h3>` +
2283
+ (SearchParams.get("id") != null ?
2284
+ `题目<span class="blue">${Number(SearchParams.get("id"))}</span>` :
2285
+ `比赛<span class="blue">${Number(SearchParams.get("cid")) + `</span>&emsp;题目<span class="blue">` + String.fromCharCode(65 + parseInt(SearchParams.get("pid")))}</span>`) +
2286
+ `</center>
2287
+ <textarea id="CodeInput"></textarea>
2288
+ <center class="mt-3">
2289
+ <input id="enable_O2" name="enable_O2" type="checkbox"><label for="enable_O2">打开O2开关</label>
2290
+ <br>
2291
+ <input id="Submit" class="btn btn-info mt-2" type="button" value="提交">
2292
+ <div id="ErrorElement" class="mt-2" style="display: none; text-align: left; padding: 10px;">
2293
+ <div id="ErrorMessage" style="white-space: pre; background-color: rgba(0, 0, 0, 0.1); padding: 10px; border-radius: 5px;"></div>
2294
+ <button id="PassCheck" class="btn btn-outline-secondary mt-2" style="display: none">强制提交</button>
2295
+ </div>
2296
+ </center>`;
2297
+ if (UtilityEnabled("AutoO2")) {
2298
+ document.querySelector("#enable_O2").checked = true;
2299
+ }
2300
+ let CodeMirrorElement;
2301
+ (() => {
2302
+ CodeMirrorElement = CodeMirror.fromTextArea(document.querySelector("#CodeInput"), {
2303
+ lineNumbers: true,
2304
+ matchBrackets: true,
2305
+ mode: "text/x-c++src",
2306
+ indentUnit: 4,
2307
+ indentWithTabs: true,
2308
+ enterMode: "keep",
2309
+ tabMode: "shift",
2310
+ theme: (UtilityEnabled("DarkMode") ? "darcula" : "default"),
2311
+ extraKeys: {
2312
+ "Ctrl-Space": "autocomplete",
2313
+ "Ctrl-Enter": function (instance) {
2314
+ Submit.click();
2315
+ }
2316
+ }
2317
+ })
2318
+ })();
2319
+ CodeMirrorElement.setSize("100%", "auto");
2320
+ CodeMirrorElement.getWrapperElement().style.border = "1px solid #ddd";
2321
+
2322
+ if (SearchParams.get("sid") !== null) {
2323
+ await fetch("https://www.xmoj.tech/getsource.php?id=" + SearchParams.get("sid"))
2324
+ .then((Response) => {
2325
+ return Response.text()
2326
+ })
2327
+ .then((Response) => {
2328
+ CodeMirrorElement.setValue(Response.substring(0, Response.indexOf("/**************************************************************")).trim());
2329
+ });
2330
+ }
2331
+
2332
+ PassCheck.addEventListener("click", async () => {
2333
+ ErrorElement.style.display = "none";
2334
+ document.querySelector("#Submit").disabled = true;
2335
+ document.querySelector("#Submit").value = "正在提交...";
2336
+ await fetch("https://www.xmoj.tech/submit.php", {
2337
+ "headers": {
2338
+ "content-type": "application/x-www-form-urlencoded"
2339
+ },
2340
+ "referrer": location.href,
2341
+ "method": "POST",
2342
+ "body":
2343
+ (SearchParams.get("id") != null ?
2344
+ "id=" + SearchParams.get("id") :
2345
+ "cid=" + SearchParams.get("cid") + "&pid=" + SearchParams.get("pid")) +
2346
+ "&language=1&" +
2347
+ "source=" + encodeURIComponent(CodeMirrorElement.getValue()) + "&" +
2348
+ "enable_O2=on"
2349
+ }).then((Response) => {
2350
+ if (Response.redirected) {
2351
+ location.href = Response.url;
2352
+ }
2353
+ else {
2354
+ ErrorElement.style.display = "block";
2355
+ ErrorMessage.style.color = "red";
2356
+ ErrorMessage.innerText = "提交失败!请关闭脚本后重试!";
2357
+ Submit.disabled = false;
2358
+ Submit.value = "提交";
2359
+ }
2360
+ })
2361
+ });
2362
+
2363
+ Submit.addEventListener("click", async () => {
2364
+ PassCheck.style.display = "none";
2365
+ ErrorElement.style.display = "none";
2366
+ document.querySelector("#Submit").disabled = true;
2367
+ document.querySelector("#Submit").value = "正在检查...";
2368
+ let Source = CodeMirrorElement.getValue();
2369
+ let PID = 0;
2370
+ let IOFilename = "";
2371
+ if (SearchParams.get("cid") != null && SearchParams.get("pid") != null) {
2372
+ PID = localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") + "-Problem-" + SearchParams.get("pid") + "-PID")
2373
+ }
2374
+ else {
2375
+ PID = SearchParams.get("id");
2376
+ }
2377
+ IOFilename = localStorage.getItem("UserScript-Problem-" + PID + "-IOFilename");
2378
+ if (UtilityEnabled("IOFile") && IOFilename != null) {
2379
+ if (Source.indexOf(IOFilename) == -1) {
2380
+ PassCheck.style.display = "";
2381
+ ErrorElement.style.display = "block";
2382
+ ErrorMessage.style.color = "red";
2383
+ ErrorMessage.innerText = "此题输入输出文件名为" + IOFilename + ",请检查是否填错";
2384
+ document.querySelector("#Submit").disabled = false;
2385
+ document.querySelector("#Submit").value = "提交";
2386
+ return false;
2387
+ }
2388
+ else if (RegExp("//.*freopen").test(Source)) {
2389
+ PassCheck.style.display = "";
2390
+ ErrorElement.style.display = "block";
2391
+ ErrorMessage.style.color = "red";
2392
+ ErrorMessage.innerText = "请不要注释freopen语句";
2393
+ document.querySelector("#Submit").disabled = false;
2394
+ document.querySelector("#Submit").value = "提交";
2395
+ return false;
2396
+ }
2397
+ }
2398
+ if (Source == "") {
2399
+ PassCheck.style.display = "";
2400
+ ErrorElement.style.display = "block";
2401
+ ErrorMessage.style.color = "red";
2402
+ ErrorMessage.innerText = "源代码为空";
2403
+ document.querySelector("#Submit").disabled = false;
2404
+ document.querySelector("#Submit").value = "提交";
2405
+ return false;
2406
+ }
2407
+ if (UtilityEnabled("CompileError")) {
2408
+ let ResponseData = await new Promise((Resolve) => {
2409
+ GM_xmlhttpRequest({
2410
+ method: "POST",
2411
+ url: "https://cppinsights.io/api/v1/transform",
2412
+ headers: {
2413
+ "content-type": "application/json;charset=UTF-8"
2414
+ },
2415
+ referrer: "https://cppinsights.io/",
2416
+ data: JSON.stringify({
2417
+ "insightsOptions": [
2418
+ "cpp14"
2419
+ ],
2420
+ "code": Source
2421
+ }),
2422
+ onload: (Response) => {
2423
+ Resolve(Response);
2424
+ }
2425
+ });
2426
+ });
2427
+ let Response = JSON.parse(ResponseData.responseText);
2428
+ if (Response.returncode) {
2429
+ PassCheck.style.display = "";
2430
+ ErrorElement.style.display = "block";
2431
+ ErrorMessage.style.color = "red";
2432
+ ErrorMessage.innerText = "编译错误:\n" + Response.stderr.trim();
2433
+ document.querySelector("#Submit").disabled = false;
2434
+ document.querySelector("#Submit").value = "提交";
2435
+ return false;
2436
+ }
2437
+ else {
2438
+ PassCheck.click();
2439
+ }
2440
+ }
2441
+ else {
2442
+ PassCheck.click();
2443
+ }
2444
+ });
2445
+ } else if (location.pathname == "/modifypage.php") {
2446
+ if (SearchParams.get("ByUserScript") != null) {
2447
+ document.querySelector("body > div > div.mt-3").innerHTML = "";
2448
+ await fetch(ServerURL + "/Update.json", { cache: "no-cache" })
2449
+ .then((Response) => {
2450
+ return Response.json();
2451
+ })
2452
+ .then((Response) => {
2453
+ for (let i = Object.keys(Response.UpdateHistory).length - 1; i >= 0; i--) {
2454
+ let Version = Object.keys(Response.UpdateHistory)[i];
2455
+ let Data = Response.UpdateHistory[Version];
2456
+ let UpdateDataCard = document.createElement("div"); document.querySelector("body > div > div.mt-3").appendChild(UpdateDataCard);
2457
+ UpdateDataCard.className = "card mb-3";
2458
+ if (Data.Prerelease)
2459
+ UpdateDataCard.classList.add("text-secondary");
2460
+ let UpdateDataCardBody = document.createElement("div"); UpdateDataCard.appendChild(UpdateDataCardBody);
2461
+ UpdateDataCardBody.className = "card-body";
2462
+ let UpdateDataCardTitle = document.createElement("h5"); UpdateDataCardBody.appendChild(UpdateDataCardTitle);
2463
+ UpdateDataCardTitle.className = "card-title";
2464
+ UpdateDataCardTitle.innerText = Version;
2465
+ if (Data.Prerelease) {
2466
+ UpdateDataCardTitle.innerHTML += "(预览版)";
2467
+ }
2468
+ let UpdateDataCardSubtitle = document.createElement("h6"); UpdateDataCardBody.appendChild(UpdateDataCardSubtitle);
2469
+ UpdateDataCardSubtitle.className = "card-subtitle mb-2 text-muted";
2470
+ UpdateDataCardSubtitle.innerHTML = GetRelativeTime(Data.UpdateDate);
2471
+ let UpdateDataCardText = document.createElement("p"); UpdateDataCardBody.appendChild(UpdateDataCardText);
2472
+ UpdateDataCardText.className = "card-text";
2473
+ let UpdateDataCardList = document.createElement("ul"); UpdateDataCardText.appendChild(UpdateDataCardList);
2474
+ UpdateDataCardList.className = "list-group list-group-flush";
2475
+ for (let j = 0; j < Data.UpdateContents.length; j++) {
2476
+ let UpdateDataCardListItem = document.createElement("li"); UpdateDataCardList.appendChild(UpdateDataCardListItem);
2477
+ UpdateDataCardListItem.className = "list-group-item";
2478
+ UpdateDataCardListItem.innerHTML =
2479
+ "(<a href=\"https://github.com/XMOJ-Script-dev/XMOJ-Script/pull/" + Data.UpdateContents[j].PR + "\" target=\"_blank\">" +
2480
+ "#" + Data.UpdateContents[j].PR + "</a>) " +
2481
+ Data.UpdateContents[j].Description;
2482
+ }
2483
+ let UpdateDataCardLink = document.createElement("a"); UpdateDataCardBody.appendChild(UpdateDataCardLink);
2484
+ UpdateDataCardLink.className = "card-link";
2485
+ UpdateDataCardLink.href = "https://github.com/XMOJ-Script-dev/XMOJ-Script/releases/tag/" + Version;
2486
+ UpdateDataCardLink.target = "_blank";
2487
+ UpdateDataCardLink.innerText = "查看该版本";
2488
+ }
2489
+ });
2490
+ }
2491
+ else {
2492
+ let Nickname = document.getElementsByName("nick")[0].value;
2493
+ let School = document.getElementsByName("school")[0].value;
2494
+ let EmailAddress = document.getElementsByName("email")[0].value;
2495
+ let CodeforcesAccount = document.getElementsByName("acc_cf")[0].value;
2496
+ let AtcoderAccount = document.getElementsByName("acc_atc")[0].value;
2497
+ let USACOAccount = document.getElementsByName("acc_usaco")[0].value;
2498
+ let LuoguAccount = document.getElementsByName("acc_luogu")[0].value;
2499
+ document.querySelector("body > div > div").innerHTML = `<div class="row g-2 align-items-center col-6 mb-1">
2500
+ <div class="col-3"><label for="UserID" class="col-form-label">用户ID</label></div>
2501
+ <div class="col-9"><input id="UserID" class="form-control" disabled readonly value="${CurrentUsername}"></div>
2502
+ </div>
2503
+ <div class="row g-2 align-items-center col-6 mb-1">
2504
+ <div class="col-3"><label for="Avatar" class="col-form-label">头像</label></div>
2505
+ <div class="col-9">
2506
+ <img width="64" height="64" src="https://cravatar.cn/avatar/` + (await GetUserInfo(CurrentUsername)).EmailHash + `?d=retro">
2507
+ <a href="https://cravatar.cn/avatars" target="_blank">修改头像</a>
2508
+ </div>
2509
+ </div>
2510
+ <div class="row g-2 align-items-center col-6 pb-1 ps-2 pe-2 mt-3 mb-3 border" id="BadgeRow" style="display: none">
2511
+ <div class="col-3">标签</div>
2512
+ <div class="col-9">
2513
+ <div class="row g-2 align-items-center mb-1">
2514
+ <div class="col-3"><label for="BadgeContent" class="col-form-label">内容</label></div>
2515
+ <div class="col-9"><input class="form-control" id="BadgeContent"></div>
2516
+ </div>
2517
+ <div class="row g-2 align-items-center mb-1">
2518
+ <div class="col-3"><label for="BadgeBackgroundColor" class="col-form-label">背景颜色</label></div>
2519
+ <div class="col-9"><input class="form-control form-control-color" type="color" id="BadgeBackgroundColor"></div>
2520
+ </div>
2521
+ <div class="row g-2 align-items-center mb-1">
2522
+ <div class="col-3"><label for="BadgeColor" class="col-form-label">文字颜色</label></div>
2523
+ <div class="col-9"><input class="form-control form-control-color" type="color" id="BadgeColor"></div>
2524
+ </div>
2525
+ </div>
2526
+ </div>
2527
+ <div class="row g-2 align-items-center col-6 mb-1">
2528
+ <div class="col-3"><label for="Nickname" class="col-form-label">昵称</label></div>
2529
+ <div class="col-9"><input id="Nickname" class="form-control"></div>
2530
+ </div>
2531
+ <div class="row g-2 align-items-center col-6 mb-1">
2532
+ <div class="col-3"><label for="OldPassword" class="col-form-label">旧密码</label></div>
2533
+ <div class="col-9"><input type="password" id="OldPassword" class="form-control"></div>
2534
+ </div>
2535
+ <div class="row g-2 align-items-center col-6 mb-1">
2536
+ <div class="col-3"><label for="NewPassword" class="col-form-label">新密码</label></div>
2537
+ <div class="col-9"><input type="password" id="NewPassword" class="form-control"></div>
2538
+ </div>
2539
+ <div class="row g-2 align-items-center col-6 mb-1">
2540
+ <div class="col-3"><label for="NewPasswordAgain" class="col-form-label">请重复密码</label></div>
2541
+ <div class="col-9"><input type="password" id="NewPasswordAgain" class="form-control"></div>
2542
+ </div>
2543
+ <div class="row g-2 align-items-center col-6 mb-1">
2544
+ <div class="col-3"><label for="School" class="col-form-label">学校</label></div>
2545
+ <div class="col-9"><input id="School" class="form-control"></div>
2546
+ </div>
2547
+ <div class="row g-2 align-items-center col-6 mb-1">
2548
+ <div class="col-3"><label for="EmailAddress" class="col-form-label">电子邮箱</label></div>
2549
+ <div class="col-9"><input id="EmailAddress" class="form-control"></div>
2550
+ </div>
2551
+ <div class="row g-2 align-items-center col-6 mb-1">
2552
+ <div class="col-3"><label for="CodeforcesAccount" class="col-form-label">Codeforces账号</label></div>
2553
+ <div class="col-9"><input id="CodeforcesAccount" class="form-control"></div>
2554
+ </div>
2555
+ <div class="row g-2 align-items-center col-6 mb-1">
2556
+ <div class="col-3"><label for="AtcoderAccount" class="col-form-label">Atcoder账号</label></div>
2557
+ <div class="col-9"><input id="AtcoderAccount" class="form-control"></div>
2558
+ </div>
2559
+ <div class="row g-2 align-items-center col-6 mb-1">
2560
+ <div class="col-3"><label for="USACOAccount" class="col-form-label">USACO账号</label></div>
2561
+ <div class="col-9"><input id="USACOAccount" class="form-control"></div>
2562
+ </div>
2563
+ <div class="row g-2 align-items-center col-6 mb-1">
2564
+ <div class="col-3"><label for="LuoguAccount" class="col-form-label">洛谷账号</label></div>
2565
+ <div class="col-9"><input id="LuoguAccount" class="form-control"></div>
2566
+ </div>
2567
+ <button type="submit" class="btn btn-primary mb-2" id="ModifyInfo">
2568
+ 修改
2569
+ <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" style="display: none"></span>
2570
+ </button>
2571
+ <div class="alert alert-danger mb-3" role="alert" id="ErrorElement" style="display: none;"></div>
2572
+ <div class="alert alert-success mb-3" role="alert" id="SuccessElement" style="display: none;">修改成功</div>
2573
+ <br>`;
2574
+ document.getElementById("Nickname").value = Nickname;
2575
+ document.getElementById("School").value = School;
2576
+ document.getElementById("EmailAddress").value = EmailAddress;
2577
+ document.getElementById("CodeforcesAccount").value = CodeforcesAccount;
2578
+ document.getElementById("AtcoderAccount").value = AtcoderAccount;
2579
+ document.getElementById("USACOAccount").value = USACOAccount;
2580
+ document.getElementById("LuoguAccount").value = LuoguAccount;
2581
+ RequestAPI("GetBadge", {
2582
+ "UserID": String(CurrentUsername)
2583
+ }, (Response) => {
2584
+ if (Response.Success) {
2585
+ BadgeRow.style.display = "";
2586
+ BadgeContent.value = Response.Data.Content;
2587
+ BadgeBackgroundColor.value = Response.Data.BackgroundColor;
2588
+ BadgeColor.value = Response.Data.Color;
2589
+ SuccessElement.innerText += ",用户标签会在一天内生效";
2590
+ }
2591
+ });
2592
+ ModifyInfo.addEventListener("click", async () => {
2593
+ ModifyInfo.disabled = true;
2594
+ ModifyInfo.querySelector("span").style.display = "";
2595
+ ErrorElement.style.display = "none";
2596
+ SuccessElement.style.display = "none";
2597
+ let BadgeContent = document.querySelector("#BadgeContent").value;
2598
+ let BadgeBackgroundColor = document.querySelector("#BadgeBackgroundColor").value;
2599
+ let BadgeColor = document.querySelector("#BadgeColor").value;
2600
+ await new Promise((Resolve) => {
2601
+ RequestAPI("EditBadge", {
2602
+ "UserID": String(CurrentUsername),
2603
+ "Content": String(BadgeContent),
2604
+ "BackgroundColor": String(BadgeBackgroundColor),
2605
+ "Color": String(BadgeColor)
2606
+ }, (Response) => {
2607
+ if (Response.Success) {
2608
+ Resolve();
2609
+ }
2610
+ else {
2611
+ ModifyInfo.disabled = false;
2612
+ ModifyInfo.querySelector("span").style.display = "none";
2613
+ ErrorElement.style.display = "block";
2614
+ ErrorElement.innerText = Response.Message;
2615
+ }
2616
+ });
2617
+ });
2618
+ let Nickname = document.querySelector("#Nickname").value;
2619
+ let OldPassword = document.querySelector("#OldPassword").value;
2620
+ let NewPassword = document.querySelector("#NewPassword").value;
2621
+ let NewPasswordAgain = document.querySelector("#NewPasswordAgain").value;
2622
+ let School = document.querySelector("#School").value;
2623
+ let EmailAddress = document.querySelector("#EmailAddress").value;
2624
+ let CodeforcesAccount = document.querySelector("#CodeforcesAccount").value;
2625
+ let AtcoderAccount = document.querySelector("#AtcoderAccount").value;
2626
+ let USACOAccount = document.querySelector("#USACOAccount").value;
2627
+ let LuoguAccount = document.querySelector("#LuoguAccount").value;
2628
+ await fetch("https://www.xmoj.tech/modify.php", {
2629
+ "headers": {
2630
+ "content-type": "application/x-www-form-urlencoded"
2631
+ },
2632
+ "referrer": location.href,
2633
+ "method": "POST",
2634
+ "body":
2635
+ "nick=" + encodeURIComponent(Nickname) + "&" +
2636
+ "opassword=" + encodeURIComponent(OldPassword) + "&" +
2637
+ "npassword=" + encodeURIComponent(NewPassword) + "&" +
2638
+ "rptpassword=" + encodeURIComponent(NewPasswordAgain) + "&" +
2639
+ "school=" + encodeURIComponent(School) + "&" +
2640
+ "email=" + encodeURIComponent(EmailAddress) + "&" +
2641
+ "acc_cf=" + encodeURIComponent(CodeforcesAccount) + "&" +
2642
+ "acc_atc=" + encodeURIComponent(AtcoderAccount) + "&" +
2643
+ "acc_usaco=" + encodeURIComponent(USACOAccount) + "&" +
2644
+ "acc_luogu=" + encodeURIComponent(LuoguAccount)
2645
+ });
2646
+ ModifyInfo.disabled = false;
2647
+ ModifyInfo.querySelector("span").style.display = "none";
2648
+ SuccessElement.style.display = "block";
2649
+ });
2650
+ if (UtilityEnabled("ExportACCode")) {
2651
+ let ExportACCode = document.createElement("button");
2652
+ document.querySelector("body > div.container > div").appendChild(ExportACCode);
2653
+ ExportACCode.innerText = "导出AC代码";
2654
+ ExportACCode.className = "btn btn-outline-secondary";
2655
+ ExportACCode.addEventListener("click", () => {
2656
+ ExportACCode.disabled = true;
2657
+ let ExportProgressBar = document.getElementsByTagName("progress")[0] || document.createElement("progress");
2658
+ ExportProgressBar.removeAttribute("value");
2659
+ ExportProgressBar.removeAttribute("max");
2660
+ document.querySelector("body > div.container > div").appendChild(ExportProgressBar);
2661
+ ExportACCode.innerText = "正在导出...";
2662
+ let Request = new XMLHttpRequest();
2663
+ Request.addEventListener("readystatechange", () => {
2664
+ if (Request.readyState == 4) {
2665
+ if (Request.status == 200) {
2666
+ let Response = Request.responseText;
2667
+ let ACCode = Response.split("------------------------------------------------------\r\n");
2668
+ ExportProgressBar.max = ACCode.length - 1;
2669
+ let DownloadCode = (i) => {
2670
+ if (i >= ACCode.length) {
2671
+ ExportACCode.innerText = "AC代码导出成功";
2672
+ ExportACCode.disabled = false;
2673
+ ExportProgressBar.remove();
2674
+ setTimeout(() => {
2675
+ ExportACCode.innerText = "导出AC代码";
2676
+ }, 1000);
2677
+ return;
2678
+ }
2679
+ let CurrentCode = ACCode[i];
2680
+ if (CurrentCode != "") {
2681
+ let CurrentQuestionID = CurrentCode.substring(7, 11);
2682
+ CurrentCode = CurrentCode.substring(14);
2683
+ ExportProgressBar.value = i + 1;
2684
+ let DownloadLink = document.createElement("a");
2685
+ DownloadLink.href = window.URL.createObjectURL(new Blob([CurrentCode]));
2686
+ DownloadLink.download = CurrentQuestionID + ".cpp";
2687
+ DownloadLink.click();
2688
+ }
2689
+ setTimeout(() => {
2690
+ DownloadCode(i + 1);
2691
+ }, 50);
2692
+ };
2693
+ DownloadCode(0);
2694
+ } else {
2695
+ ExportACCode.disabled = false;
2696
+ ExportACCode.innerText = "AC代码导出失败";
2697
+ setTimeout(() => {
2698
+ ExportACCode.innerText = "导出AC代码";
2699
+ }, 1000);
2700
+ }
2701
+ }
2702
+ });
2703
+ Request.open("GET", "https://www.xmoj.tech/export_ac_code.php", true);
2704
+ Request.send();
2705
+ });
2706
+ }
2707
+ }
2708
+ } else if (location.pathname == "/userinfo.php") {
2709
+ if (SearchParams.get("ByUserScript") === null) {
2710
+ if (UtilityEnabled("RemoveUseless")) {
2711
+ let Temp = document.getElementById("submission").childNodes;
2712
+ for (let i = 0; i < Temp.length; i++) {
2713
+ Temp[i].remove();
2714
+ }
2715
+ }
2716
+ eval(document.querySelector("body > script:nth-child(5)").innerHTML);
2717
+ document.querySelector("#statics > tbody > tr:nth-child(1)").remove();
2718
+
2719
+ let Temp = document.querySelector("#statics > tbody").children;
2720
+ for (let i = 0; i < Temp.length; i++) {
2721
+ if (Temp[i].children[0] != undefined) {
2722
+ if (Temp[i].children[0].innerText == "Statistics") {
2723
+ Temp[i].children[0].innerText = "统计";
2724
+ }
2725
+ else if (Temp[i].children[0].innerText == "Email:") {
2726
+ Temp[i].children[0].innerText = "电子邮箱";
2727
+ }
2728
+ else {
2729
+ Temp[i].children[1].innerText = Temp[i].children[1].innerText;
2730
+ }
2731
+ Temp[i].children[1].removeAttribute("align");
2732
+ }
2733
+ }
2734
+
2735
+ Temp = document.querySelector("#statics > tbody > tr:nth-child(1) > td:nth-child(3)").childNodes;
2736
+ let ACProblems = [];
2737
+ for (let i = 0; i < Temp.length; i++) {
2738
+ if (Temp[i].tagName == "A" && Temp[i].href.indexOf("problem.php?id=") != -1) {
2739
+ ACProblems.push(Number(Temp[i].innerText.trim()));
2740
+ }
2741
+ }
2742
+ document.querySelector("#statics > tbody > tr:nth-child(1) > td:nth-child(3)").remove();
2743
+
2744
+ let UserID, UserNick;
2745
+ [UserID, UserNick] = document.querySelector("#statics > caption").childNodes[0].data.trim().split("--");
2746
+ document.querySelector("#statics > caption").remove();
2747
+
2748
+ let Row = document.createElement("div"); Row.className = "row";
2749
+ let LeftDiv = document.createElement("div"); LeftDiv.className = "col-md-5"; Row.appendChild(LeftDiv);
2750
+
2751
+ let LeftTopDiv = document.createElement("div"); LeftTopDiv.className = "row mb-2"; LeftDiv.appendChild(LeftTopDiv);
2752
+ let AvatarContainer = document.createElement("div");
2753
+ AvatarContainer.classList.add("col-auto");
2754
+ let AvatarElement = document.createElement("img");
2755
+ let UserEmailHash = (await GetUserInfo(UserID)).EmailHash;
2756
+ if (UserEmailHash == undefined) {
2757
+ AvatarElement.src = `https://cravatar.cn/avatar/00000000000000000000000000000000?d=mp&f=y`;
2758
+ }
2759
+ else {
2760
+ AvatarElement.src = `https://cravatar.cn/avatar/${UserEmailHash}?d=retro`;
2761
+ }
2762
+ AvatarElement.classList.add("rounded", "me-2");
2763
+ AvatarElement.style.height = "120px";
2764
+ AvatarContainer.appendChild(AvatarElement);
2765
+ LeftTopDiv.appendChild(AvatarContainer);
2766
+
2767
+ let UserInfoElement = document.createElement("div");
2768
+ UserInfoElement.classList.add("col-auto");
2769
+ UserInfoElement.style.lineHeight = "40px";
2770
+ UserInfoElement.innerHTML += "用户名:" + UserID + "<br>";
2771
+ UserInfoElement.innerHTML += "昵称:" + UserNick + "<br>";
2772
+ if (UtilityEnabled("Rating")) {
2773
+ UserInfoElement.innerHTML += "评分:" + ((await GetUserInfo(UserID)).Rating) + "<br>";
2774
+ }
2775
+ // Create a placeholder for the last online time
2776
+ let lastOnlineElement = document.createElement('div');
2777
+ lastOnlineElement.innerHTML = "最后在线:加载中...<br>";
2778
+ UserInfoElement.appendChild(lastOnlineElement);
2779
+
2780
+ RequestAPI("LastOnline", {"Username": UserID}, (result) => {
2781
+ if (result.Success) {
2782
+ if (UtilityEnabled("DebugMode")) {
2783
+ console.log('lastOnline:' + result.Data.logintime);
2784
+ }
2785
+ lastOnlineElement.innerHTML = "最后在线:" + GetRelativeTime(result.Data.logintime) + "<br>";
2786
+ } else {
2787
+ lastOnlineElement.innerHTML = "最后在线:近三个月内从未<br>";
2788
+ }
2789
+ });
2790
+ LeftTopDiv.appendChild(UserInfoElement);
2791
+ LeftDiv.appendChild(LeftTopDiv);
2792
+
2793
+ let LeftTable = document.querySelector("body > div > div > center > table"); LeftDiv.appendChild(LeftTable);
2794
+ let RightDiv = document.createElement("div"); RightDiv.className = "col-md-7"; Row.appendChild(RightDiv);
2795
+ RightDiv.innerHTML = "<h5>已解决题目</h5>";
2796
+ for (let i = 0; i < ACProblems.length; i++) {
2797
+ RightDiv.innerHTML += "<a href=\"https://www.xmoj.tech/problem.php?id=" + ACProblems[i] + "\" target=\"_blank\">" + ACProblems[i] + "</a> ";
2798
+ }
2799
+ document.querySelector("body > div > div").innerHTML = "";
2800
+ document.querySelector("body > div > div").appendChild(Row);
2801
+ } else {
2802
+ document.querySelector("body > div > div.mt-3").innerHTML = `<button id="UploadStd" class="btn btn-primary mb-2">上传标程</button>
2803
+ <div class="alert alert-danger mb-3" role="alert" id="ErrorElement" style="display: none;"></div>
2804
+ <div class="progress" role="progressbar">
2805
+ <div id="UploadProgress" class="progress-bar progress-bar-striped" style="width: 0%">0%</div>
2806
+ </div>
2807
+ <p class="mt-2 text-muted">
2808
+ 您必须要上传标程以后才能使用“查看标程”功能。点击“上传标程”按钮以后,系统会自动上传标程,请您耐心等待。<br>
2809
+ 首次上传标程可能会比较慢,请耐心等待。后续上传标程将会快很多。请不要直接抄袭或递交标程,否则会给予"作弊者"badge的惩罚!<br>
2810
+ 上传的内容不是您AC的程序,而是您AC的题目对应的用户std的程序。所以您可以放心上传,不会泄露您的代码。<br>
2811
+ 系统每过30天会自动提醒您上传标程,您必须要上传标程,否则将会被禁止使用“查看标程”功能。<br>
2812
+ </p>`;
2813
+ UploadStd.addEventListener("click", async () => {
2814
+ UploadStd.disabled = true;
2815
+ ErrorElement.style.display = "none";
2816
+ ErrorElement.innerText = "";
2817
+ UploadProgress.classList.remove("bg-success");
2818
+ UploadProgress.classList.remove("bg-warning");
2819
+ UploadProgress.classList.remove("bg-danger");
2820
+ UploadProgress.classList.add("progress-bar-animated");
2821
+ UploadProgress.style.width = "0%";
2822
+ UploadProgress.innerText = "0%";
2823
+ let ACList = [];
2824
+ await fetch("https://www.xmoj.tech/userinfo.php?user=" + CurrentUsername)
2825
+ .then((Response) => {
2826
+ return Response.text();
2827
+ }).then((Response) => {
2828
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
2829
+ let ScriptData = ParsedDocument.querySelector("#statics > tbody > tr:nth-child(2) > td:nth-child(3) > script").innerText;
2830
+ ScriptData = ScriptData.substr(ScriptData.indexOf("}") + 1).trim();
2831
+ ScriptData = ScriptData.split(";");
2832
+ for (let i = 0; i < ScriptData.length; i++) {
2833
+ ACList.push(Number(ScriptData[i].substring(2, ScriptData[i].indexOf(","))));
2834
+ }
2835
+ });
2836
+ RequestAPI("GetStdList", {}, async (Result) => {
2837
+ if (Result.Success) {
2838
+ let StdList = Result.Data.StdList;
2839
+ for (let i = 0; i < ACList.length; i++) {
2840
+ if (StdList.indexOf(ACList[i]) === -1) {
2841
+ await new Promise((Resolve) => {
2842
+ RequestAPI("UploadStd", {
2843
+ "ProblemID": Number(ACList[i])
2844
+ }, (Result) => {
2845
+ if (!Result.Success) {
2846
+ ErrorElement.style.display = "block";
2847
+ ErrorElement.innerText += Result.Message + "<br>";
2848
+ UploadProgress.classList.add("bg-warning");
2849
+ }
2850
+ UploadProgress.innerText = (i / ACList.length * 100).toFixed(1) + "% (" + ACList[i] + ")";
2851
+ UploadProgress.style.width = (i / ACList.length * 100) + "%";
2852
+ Resolve();
2853
+ });
2854
+ });
2855
+ }
2856
+ }
2857
+ UploadProgress.classList.add("bg-success");
2858
+ UploadProgress.classList.remove("progress-bar-animated");
2859
+ UploadProgress.innerText = "100%";
2860
+ UploadProgress.style.width = "100%";
2861
+ UploadStd.disabled = false;
2862
+ localStorage.setItem("UserScript-LastUploadedStdTime", new Date().getTime());
2863
+ }
2864
+ else {
2865
+ ErrorElement.style.display = "block";
2866
+ ErrorElement.innerText = Result.Message;
2867
+ UploadStd.disabled = false;
2868
+ }
2869
+ });
2870
+ });
2871
+ }
2872
+ } else if (location.pathname == "/conteststatistics.php") {
2873
+ document.querySelector("body > div > div.mt-3 > center > h3").innerText = "比赛统计";
2874
+ if (UtilityEnabled("ResetType")) {
2875
+ let Temp = document.getElementById("submission").childNodes;
2876
+ for (let i = 0; i < Temp.length; i++) {
2877
+ Temp[i].remove();
2878
+ }
2879
+ eval(document.querySelector("body > div.container > div > center > table:nth-child(4) > script:nth-child(6)").innerHTML);
2880
+ document.querySelector("#cs > thead > tr > th:nth-child(1)").innerText = "题目编号";
2881
+ document.querySelector("#cs > thead > tr > th:nth-child(10)").remove();
2882
+ document.querySelector("#cs > thead > tr > th:nth-child(11)").innerText = "总和";
2883
+ document.querySelector("#cs > thead > tr > th:nth-child(12)").remove();
2884
+ document.querySelector("#cs > thead > tr > th:nth-child(12)").remove();
2885
+ document.querySelector("#cs > thead > tr > th:nth-child(12)").remove();
2886
+ document.querySelector("#cs > tbody > tr:last-child > td").innerText = "总和";
2887
+ TidyTable(document.getElementById("cs"));
2888
+ Temp = document.querySelector("#cs > tbody").children;
2889
+ for (let i = 0; i < Temp.length; i++) {
2890
+ let CurrentRowChildren = Temp[i].children;
2891
+ CurrentRowChildren[9].remove();
2892
+ CurrentRowChildren[11].remove();
2893
+ CurrentRowChildren[11].remove();
2894
+ CurrentRowChildren[11].remove();
2895
+ for (let j = 0; j < CurrentRowChildren.length; j++) {
2896
+ if (CurrentRowChildren[j].innerText == "") {
2897
+ CurrentRowChildren[j].innerText = "0";
2898
+ }
2899
+ }
2900
+ }
2901
+ }
2902
+ } else if (location.pathname == "/comparesource.php") {
2903
+ if (UtilityEnabled("CompareSource")) {
2904
+ if (location.search == "") {
2905
+ document.querySelector("body > div.container > div").innerHTML = "";
2906
+ let LeftCodeText = document.createElement("span");
2907
+ document.querySelector("body > div.container > div").appendChild(LeftCodeText);
2908
+ LeftCodeText.innerText = "左侧代码的运行编号:";
2909
+ let LeftCode = document.createElement("input");
2910
+ document.querySelector("body > div.container > div").appendChild(LeftCode);
2911
+ LeftCode.classList.add("form-control");
2912
+ LeftCode.style.width = "40%";
2913
+ LeftCode.style.marginBottom = "5px";
2914
+ let RightCodeText = document.createElement("span");
2915
+ document.querySelector("body > div.container > div").appendChild(RightCodeText);
2916
+ RightCodeText.innerText = "右侧代码的运行编号:";
2917
+ let RightCode = document.createElement("input");
2918
+ document.querySelector("body > div.container > div").appendChild(RightCode);
2919
+ RightCode.classList.add("form-control");
2920
+ RightCode.style.width = "40%";
2921
+ RightCode.style.marginBottom = "5px";
2922
+ let CompareButton = document.createElement("button");
2923
+ document.querySelector("body > div.container > div").appendChild(CompareButton);
2924
+ CompareButton.innerText = "比较";
2925
+ CompareButton.className = "btn btn-primary";
2926
+ CompareButton.addEventListener("click", () => {
2927
+ location.href = "https://www.xmoj.tech/comparesource.php?left=" + Number(LeftCode.value) + "&right=" + Number(RightCode.value);
2928
+ });
2929
+ }
2930
+ else {
2931
+ document.querySelector("body > div > div.mt-3").innerHTML = `
2932
+ <div class="form-check">
2933
+ <input class="form-check-input" type="checkbox" checked id="IgnoreWhitespace">
2934
+ <label class="form-check-label" for="IgnoreWhitespace">忽略空白</label>
2935
+ </div>
2936
+ <div id="CompareElement"></div>`;
2937
+
2938
+ let LeftCode = "";
2939
+ await fetch("https://www.xmoj.tech/getsource.php?id=" + SearchParams.get("left"))
2940
+ .then((Response) => {
2941
+ return Response.text();
2942
+ }).then((Response) => {
2943
+ LeftCode = Response.substring(0, Response.indexOf("/**************************************************************")).trim();
2944
+ });
2945
+ let RightCode = "";
2946
+ await fetch("https://www.xmoj.tech/getsource.php?id=" + SearchParams.get("right"))
2947
+ .then((Response) => {
2948
+ return Response.text();
2949
+ }).then((Response) => {
2950
+ RightCode = Response.substring(0, Response.indexOf("/**************************************************************")).trim();
2951
+ });
2952
+
2953
+ let MergeViewElement = CodeMirror.MergeView(CompareElement, {
2954
+ value: LeftCode,
2955
+ origLeft: null,
2956
+ orig: RightCode,
2957
+ lineNumbers: true,
2958
+ mode: "text/x-c++src",
2959
+ collapseIdentical: "true",
2960
+ readOnly: true,
2961
+ theme: (UtilityEnabled("DarkMode") ? "darcula" : "default"),
2962
+ revertButtons: false,
2963
+ ignoreWhitespace: true
2964
+ });
2965
+
2966
+ IgnoreWhitespace.addEventListener("change", () => {
2967
+ MergeViewElement.ignoreWhitespace = ignorews.checked;
2968
+ });
2969
+ }
2970
+ }
2971
+ } else if (location.pathname == "/loginpage.php") {
2972
+ if (UtilityEnabled("NewBootstrap")) {
2973
+ document.querySelector("#login").innerHTML = `<form id="login" action="login.php" method="post">
2974
+ <div class="row g-3 align-items-center mb-3">
2975
+ <div class="col-auto">
2976
+ <label for="user_id" class="col-form-label">用户名(学号)</label>
2977
+ </div>
2978
+ <div class="col-auto">
2979
+ <input type="text" id="user_id" name="user_id" class="form-control">
2980
+ </div>
2981
+ </div>
2982
+ <div class="row g-3 align-items-center mb-3">
2983
+ <div class="col-auto">
2984
+ <label for="password" class="col-form-label">密码</label>
2985
+ </div>
2986
+ <div class="col-auto">
2987
+ <input type="password" id="password" name="password" class="form-control">
2988
+ </div>
2989
+ </div>
2990
+ <div class="row g-3 align-items-center mb-3">
2991
+ <div class="col-auto">
2992
+ <button name="submit" type="button" class="btn btn-primary">登录</button>
2993
+ </div>
2994
+ <div class="col-auto">
2995
+ <a class="btn btn-warning" href="https://www.xmoj.tech/lostpassword.php">忘记密码</a>
2996
+ </div>
2997
+ </div>
2998
+ </form > `;
2999
+ }
3000
+ let ErrorText = document.createElement("div");
3001
+ ErrorText.style.color = "red";
3002
+ ErrorText.style.marginBottom = "5px";
3003
+ document.querySelector("#login").appendChild(ErrorText);
3004
+ let LoginButton = document.getElementsByName("submit")[0];
3005
+ LoginButton.addEventListener("click", async () => {
3006
+ let Username = document.getElementsByName("user_id")[0].value;
3007
+ let Password = document.getElementsByName("password")[0].value;
3008
+ if (Username == "" ||
3009
+ Password == "") {
3010
+ ErrorText.innerText = "用户名或密码不能为空";
3011
+ } else {
3012
+ await fetch("https://www.xmoj.tech/login.php", {
3013
+ method: "POST",
3014
+ headers: {
3015
+ "Content-Type": "application/x-www-form-urlencoded"
3016
+ },
3017
+ body: "user_id=" + encodeURIComponent(Username) +
3018
+ "&password=" + hex_md5(Password)
3019
+ })
3020
+ .then((Response) => {
3021
+ return Response.text();
3022
+ })
3023
+ .then((Response) => {
3024
+ if (UtilityEnabled("LoginFailed")) {
3025
+ if (Response.indexOf("history.go(-2);") != -1) {
3026
+ if (UtilityEnabled("SavePassword")) {
3027
+ localStorage.setItem("UserScript-Username", Username);
3028
+ localStorage.setItem("UserScript-Password", Password);
3029
+ }
3030
+ let NewPage = localStorage.getItem("UserScript-LastPage");
3031
+ if (NewPage == null) {
3032
+ NewPage = "https://www.xmoj.tech/index.php";
3033
+ }
3034
+ location.href = NewPage;
3035
+ } else {
3036
+ if (UtilityEnabled("SavePassword")) {
3037
+ localStorage.removeItem("UserScript-Username");
3038
+ localStorage.removeItem("UserScript-Password");
3039
+ }
3040
+ Response = Response.substring(Response.indexOf("alert('") + 7);
3041
+ Response = Response.substring(0, Response.indexOf("');"));
3042
+ if (Response == "UserName or Password Wrong!") {
3043
+ ErrorText.innerText = "用户名或密码错误!";
3044
+ }
3045
+ else {
3046
+ ErrorText.innerText = Response;
3047
+ }
3048
+ }
3049
+ }
3050
+ else {
3051
+ document.innerHTML = Response;
3052
+ }
3053
+ });
3054
+ }
3055
+ });
3056
+ if (UtilityEnabled("SavePassword") &&
3057
+ localStorage.getItem("UserScript-Username") != null &&
3058
+ localStorage.getItem("UserScript-Password") != null) {
3059
+ document.querySelector("#login > div:nth-child(1) > div > input").value = localStorage.getItem("UserScript-Username");
3060
+ document.querySelector("#login > div:nth-child(2) > div > input").value = localStorage.getItem("UserScript-Password");
3061
+ LoginButton.click();
3062
+ }
3063
+ } else if (location.pathname == "/contest_video.php" || location.pathname == "/problem_video.php") {
3064
+ let ScriptData = document.querySelector("body > div > div.mt-3 > center > script").innerHTML;
3065
+ if (document.getElementById("J_prismPlayer0").innerHTML != "") {
3066
+ document.getElementById("J_prismPlayer0").innerHTML = "";
3067
+ if (player) {
3068
+ player.dispose();
3069
+ }
3070
+ eval(ScriptData);
3071
+ }
3072
+ if (UtilityEnabled("DownloadPlayback")) {
3073
+ ScriptData = ScriptData.substring(ScriptData.indexOf("{"));
3074
+ ScriptData = ScriptData.substring(0, ScriptData.indexOf("}") + 1);
3075
+ ScriptData = ScriptData.replace(/([a-zA-Z0-9]+) ?:/g, "\"$1\":");
3076
+ ScriptData = ScriptData.replace(/'/g, "\"");
3077
+ let VideoData = JSON.parse(ScriptData);
3078
+ let RandomUUID = () => {
3079
+ let t = "0123456789abcdef";
3080
+ let e = [];
3081
+ for (let r = 0; r < 36; r++)
3082
+ e[r] = t.substr(Math.floor(16 * Math.random()), 1);
3083
+ e[14] = "4";
3084
+ e[19] = t.substr(3 & e[19] | 8, 1);
3085
+ e[8] = e[13] = e[18] = e[23] = "-";
3086
+ return e.join("");
3087
+ };
3088
+ let URLParams = new URLSearchParams({
3089
+ "AccessKeyId": VideoData.accessKeyId,
3090
+ "Action": "GetPlayInfo",
3091
+ "VideoId": VideoData.vid,
3092
+ "Formats": "",
3093
+ "AuthTimeout": 7200,
3094
+ "Rand": RandomUUID(),
3095
+ "SecurityToken": VideoData.securityToken,
3096
+ "StreamType": "video",
3097
+ "Format": "JSON",
3098
+ "Version": "2017-03-21",
3099
+ "SignatureMethod": "HMAC-SHA1",
3100
+ "SignatureVersion": "1.0",
3101
+ "SignatureNonce": RandomUUID(),
3102
+ "PlayerVersion": "2.9.3",
3103
+ "Channel": "HTML5"
3104
+ });
3105
+ URLParams.sort();
3106
+ await fetch("https://vod." + VideoData.region + ".aliyuncs.com/?" +
3107
+ URLParams.toString() +
3108
+ "&Signature=" +
3109
+ encodeURIComponent(CryptoJS.HmacSHA1("GET&%2F&" + encodeURIComponent(URLParams.toString()),
3110
+ VideoData.accessKeySecret + "&").toString(CryptoJS.enc.Base64)))
3111
+ .then((Response) => {
3112
+ return Response.json();
3113
+ })
3114
+ .then((Response) => {
3115
+ let DownloadButton = document.createElement("a");
3116
+ DownloadButton.className = "btn btn-outline-secondary";
3117
+ DownloadButton.innerText = "下载";
3118
+ DownloadButton.href = Response.PlayInfoList.PlayInfo[0].PlayURL;
3119
+ DownloadButton.download = Response.VideoBase.Title;
3120
+ document.querySelector("body > div > div.mt-3 > center").appendChild(DownloadButton);
3121
+ });
3122
+ }
3123
+ } else if (location.pathname == "/reinfo.php") {
3124
+ if (document.querySelector("#results > div") == undefined) {
3125
+ document.querySelector("#results").parentElement.innerHTML = "没有测试点信息";
3126
+ }
3127
+ else {
3128
+ for (let i = 0; i < document.querySelector("#results > div").children.length; i++) {
3129
+ let CurrentElement = document.querySelector("#results > div").children[i].children[0].children[0].children[0];
3130
+ let Temp = CurrentElement.innerText.substring(0, CurrentElement.innerText.length - 2).split("/");
3131
+ CurrentElement.innerText = TimeToStringTime(Temp[0]) + "/" + SizeToStringSize(Temp[1]);
3132
+ }
3133
+ if (document.getElementById("apply_data")) {
3134
+ let ApplyDiv = document.getElementById("apply_data").parentElement;
3135
+ console.log("启动!!!");
3136
+ if (UtilityEnabled("ApplyData")) {
3137
+ let GetDataButton = document.createElement("button");
3138
+ GetDataButton.className = "ms-2 btn btn-outline-secondary";
3139
+ GetDataButton.innerText = "获取数据";
3140
+ console.log("按钮创建成功");
3141
+ ApplyDiv.appendChild(GetDataButton);
3142
+ GetDataButton.addEventListener("click", async () => {
3143
+ GetDataButton.disabled = true;
3144
+ GetDataButton.innerText = "正在获取数据...";
3145
+ let PID = localStorage.getItem("UserScript-Solution-" + SearchParams.get("sid") + "-Problem");
3146
+ let Code = "";
3147
+ if (localStorage.getItem(`UserScript-Problem-${PID}-IOFilename`) !== null) {
3148
+ Code = `#define IOFile "${localStorage.getItem(`UserScript-Problem-${PID}-IOFilename`)}"\n`;
3149
+ }
3150
+ Code += `//XMOJ-Script 获取数据代码
3151
+ #include <bits/stdc++.h>
3152
+ using namespace std;
3153
+ string Base64Encode(string Input)
3154
+ {
3155
+ const string Base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3156
+ string Output;
3157
+ for (int i = 0; i < Input.length(); i += 3)
3158
+ {
3159
+ Output.push_back(i + 0 > Input.length() ? '=' : Base64Chars[(Input[i + 0] & 0xfc) >> 2]);
3160
+ Output.push_back(i + 1 > Input.length() ? '=' : Base64Chars[((Input[i + 0] & 0x03) << 4) + ((Input[i + 1] & 0xf0) >> 4)]);
3161
+ Output.push_back(i + 2 > Input.length() ? '=' : Base64Chars[((Input[i + 1] & 0x0f) << 2) + ((Input[i + 2] & 0xc0) >> 6)]);
3162
+ Output.push_back(i + 3 > Input.length() ? '=' : Base64Chars[Input[i + 2] & 0x3f]);
3163
+ }
3164
+ return Output;
3165
+ }
3166
+ int main()
3167
+ {
3168
+ #ifdef IOFile
3169
+ freopen(IOFile ".in", "r", stdin);
3170
+ freopen(IOFile ".out", "w", stdout);
3171
+ #endif
3172
+ string Input;
3173
+ while (1)
3174
+ {
3175
+ char Data = getchar();
3176
+ if (Data == EOF)
3177
+ break;
3178
+ Input.push_back(Data);
3179
+ }
3180
+ throw runtime_error("[" + Base64Encode(Input.c_str()) + "]");
3181
+ return 0;
3182
+ }`;
3183
+
3184
+ await fetch("https://www.xmoj.tech/submit.php", {
3185
+ "headers": {
3186
+ "content-type": "application/x-www-form-urlencoded"
3187
+ },
3188
+ "referrer": "https://www.xmoj.tech/submitpage.php?id=" + PID,
3189
+ "method": "POST",
3190
+ "body": "id=" + PID + "&" +
3191
+ "language=1&" +
3192
+ "source=" + encodeURIComponent(Code) + "&" +
3193
+ "enable_O2=on"
3194
+ });
3195
+
3196
+ let SID = await fetch("https://www.xmoj.tech/status.php").then((Response) => {
3197
+ return Response.text();
3198
+ }).then((Response) => {
3199
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
3200
+ return ParsedDocument.querySelector("#result-tab > tbody > tr:nth-child(1) > td:nth-child(2)").innerText;
3201
+ });
3202
+
3203
+ await new Promise((Resolve) => {
3204
+ let Interval = setInterval(async () => {
3205
+ await fetch("status-ajax.php?solution_id=" + SID).then((Response) => {
3206
+ return Response.text();
3207
+ }).then((Response) => {
3208
+ if (Response.split(",")[0] >= 4) {
3209
+ clearInterval(Interval);
3210
+ Resolve();
3211
+ }
3212
+ });
3213
+ }, 500);
3214
+ });
3215
+
3216
+ await fetch(`https://www.xmoj.tech/reinfo.php?sid=${SID}`).then((Response) => {
3217
+ return Response.text();
3218
+ }).then((Response) => {
3219
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
3220
+ let ErrorData = ParsedDocument.getElementById("errtxt").innerText;
3221
+ let MatchResult = ErrorData.match(/\what\(\): \[([A-Za-z0-9+\/=]+)\]/g);
3222
+ for (let i = 0; i < MatchResult.length; i++) {
3223
+ let Data = CryptoJS.enc.Base64.parse(MatchResult[i].substring(10, MatchResult[i].length - 1)).toString(CryptoJS.enc.Utf8);
3224
+ ApplyDiv.appendChild(document.createElement("hr"));
3225
+ ApplyDiv.appendChild(document.createTextNode("数据" + (i + 1) + ":"));
3226
+ let CodeElement = document.createElement("div");
3227
+ ApplyDiv.appendChild(CodeElement);
3228
+ CodeMirror(CodeElement, {
3229
+ value: Data,
3230
+ theme: (UtilityEnabled("DarkMode") ? "darcula" : "default"),
3231
+ lineNumbers: true,
3232
+ readOnly: true
3233
+ }).setSize("100%", "auto");
3234
+ }
3235
+ GetDataButton.innerText = "获取数据成功";
3236
+ GetDataButton.disabled = false;
3237
+ });
3238
+ });
3239
+ }
3240
+ document.getElementById("apply_data").addEventListener("click", () => {
3241
+ let ApplyElements = document.getElementsByClassName("data");
3242
+ for (let i = 0; i < ApplyElements.length; i++) {
3243
+ ApplyElements[i].style.display = (ApplyElements[i].style.display == "block" ? "" : "block");
3244
+ }
3245
+ });
3246
+ }
3247
+ let ApplyElements = document.getElementsByClassName("data");
3248
+ for (let i = 0; i < ApplyElements.length; i++) {
3249
+ ApplyElements[i].addEventListener("click", async () => {
3250
+ await fetch("https://www.xmoj.tech/data_distribute_ajax_apply.php", {
3251
+ method: "POST",
3252
+ headers: {
3253
+ "Content-Type": "application/x-www-form-urlencoded"
3254
+ },
3255
+ body: "user_id=" + CurrentUsername + "&" +
3256
+ "solution_id=" + SearchParams.get("sid") + "&" +
3257
+ "name=" + ApplyElements[i].getAttribute("name")
3258
+ }).then((Response) => {
3259
+ return Response.json();
3260
+ }).then((Response) => {
3261
+ ApplyElements[i].innerText = Response.msg;
3262
+ setTimeout(() => {
3263
+ ApplyElements[i].innerText = "申请数据";
3264
+ }, 1000);
3265
+ });
3266
+ });
3267
+ }
3268
+ }
3269
+ } else if (location.pathname == "/downloads.php") {
3270
+ let SoftwareList = document.querySelector("body > div > ul");
3271
+ SoftwareList.remove();
3272
+ SoftwareList = document.createElement("ul");
3273
+ SoftwareList.className = "software_list";
3274
+ let Container = document.createElement("div"); document.querySelector("body > div").appendChild(Container);
3275
+ Container.className = "mt-3";
3276
+ Container.appendChild(SoftwareList);
3277
+ if (UtilityEnabled("NewDownload")) {
3278
+ let Softwares = [{
3279
+ "Name": "Bloodshed Dev-C++",
3280
+ "Image": "https://a.fsdn.com/allura/p/dev-cpp/icon",
3281
+ "URL": "https://sourceforge.net/projects/dev-cpp/"
3282
+ }, {
3283
+ "Name": "Orwell Dev-C++",
3284
+ "Image": "https://a.fsdn.com/allura/p/orwelldevcpp/icon",
3285
+ "URL": "https://sourceforge.net/projects/orwelldevcpp/"
3286
+ }, {
3287
+ "Name": "Embarcadero Dev-C++",
3288
+ "Image": "https://a.fsdn.com/allura/s/embarcadero-dev-cpp/icon",
3289
+ "URL": "https://sourceforge.net/software/product/Embarcadero-Dev-Cpp/"
3290
+ }, {
3291
+ "Name": "RedPanda C++",
3292
+ "Image": "https://a.fsdn.com/allura/p/redpanda-cpp/icon",
3293
+ "URL": "https://sourceforge.net/projects/redpanda-cpp/"
3294
+ }, {
3295
+ "Name": "CP Editor",
3296
+ "Image": "https://a.fsdn.com/allura/mirror/cp-editor/icon",
3297
+ "URL": "https://sourceforge.net/projects/cp-editor.mirror/"
3298
+ }, {
3299
+ "Name": "Code::Blocks",
3300
+ "Image": "https://a.fsdn.com/allura/p/codeblocks/icon",
3301
+ "URL": "https://sourceforge.net/projects/codeblocks/"
3302
+ }, {
3303
+ "Name": "Visual Studio Code",
3304
+ "Image": "https://code.visualstudio.com/favicon.ico",
3305
+ "URL": "https://code.visualstudio.com/Download"
3306
+ }, {
3307
+ "Name": "Lazarus",
3308
+ "Image": "https://a.fsdn.com/allura/p/lazarus/icon",
3309
+ "URL": "https://sourceforge.net/projects/lazarus/"
3310
+ }, {
3311
+ "Name": "Geany",
3312
+ "Image": "https://www.geany.org/static/img/geany.svg",
3313
+ "URL": "https://www.geany.org/download/releases/"
3314
+ }, {
3315
+ "Name": "NOI Linux",
3316
+ "Image": "https://www.noi.cn/upload/resources/image/2021/07/16/163780.jpg",
3317
+ "URL": "https://www.noi.cn/gynoi/jsgz/2021-07-16/732450.shtml"
3318
+ }, {
3319
+ "Name": "VirtualBox",
3320
+ "Image": "https://www.virtualbox.org/graphics/vbox_logo2_gradient.png",
3321
+ "URL": "https://www.virtualbox.org/wiki/Downloads"
3322
+ }, {
3323
+ "Name": "MinGW",
3324
+ "Image": "https://www.mingw-w64.org/logo.svg",
3325
+ "URL": "https://sourceforge.net/projects/mingw/"
3326
+ }];
3327
+ for (let i = 0; i < Softwares.length; i++) {
3328
+ SoftwareList.innerHTML +=
3329
+ "<li class=\"software_item\">" +
3330
+ "<a href=\"" + Softwares[i].URL + "\">" +
3331
+ "<div class=\"item-info\">" +
3332
+ "<div class=\"item-img\">" +
3333
+ "<img height=\"50\" src=\"" + Softwares[i].Image + "\" alt=\"点击下载\">" +
3334
+ "</div>" +
3335
+ "<div class=\"item-txt\">" + Softwares[i].Name + "</div>" +
3336
+ "</div>" +
3337
+ "</a>" +
3338
+ "</li>";
3339
+ }
3340
+ }
3341
+ } else if (location.pathname == "/problemstatus.php") {
3342
+ document.querySelector("body > div > div.mt-3 > center").insertBefore(document.querySelector("#statics"), document.querySelector("body > div > div.mt-3 > center > table"));
3343
+ document.querySelector("body > div > div.mt-3 > center").insertBefore(document.querySelector("#problemstatus"), document.querySelector("body > div > div.mt-3 > center > table"));
3344
+
3345
+ document.querySelector("body > div > div.mt-3 > center > table:nth-child(3)").remove();
3346
+ let Temp = document.querySelector("#statics").rows;
3347
+ for (let i = 0; i < Temp.length; i++) {
3348
+ Temp[i].removeAttribute("class");
3349
+ if (Temp[i].children.length == 2) {
3350
+ Temp[i].children[1].innerText = Temp[i].children[1].innerText;
3351
+ }
3352
+ }
3353
+
3354
+ document.querySelector("#problemstatus > thead > tr").innerHTML =
3355
+ document.querySelector("#problemstatus > thead > tr").innerHTML.replaceAll("td", "th");
3356
+ document.querySelector("#problemstatus > thead > tr > th:nth-child(2)").innerText = "运行编号";
3357
+ document.querySelector("#problemstatus > thead > tr > th:nth-child(4)").remove();
3358
+ document.querySelector("#problemstatus > thead > tr > th:nth-child(4)").remove();
3359
+ document.querySelector("#problemstatus > thead > tr > th:nth-child(4)").remove();
3360
+ document.querySelector("#problemstatus > thead > tr > th:nth-child(4)").remove();
3361
+ Temp = document.querySelector("#problemstatus > thead > tr").children;
3362
+ for (let i = 0; i < Temp.length; i++) {
3363
+ Temp[i].removeAttribute("class");
3364
+ }
3365
+ Temp = document.querySelector("#problemstatus > tbody").children;
3366
+ for (let i = 0; i < Temp.length; i++) {
3367
+ if (Temp[i].children[5].children[0] != null) {
3368
+ Temp[i].children[1].innerHTML = `<a href="${Temp[i].children[5].children[0].href}">${Temp[i].children[1].innerText.trim()}</a>`;
3369
+ }
3370
+ GetUsernameHTML(Temp[i].children[2], Temp[i].children[2].innerText);
3371
+ Temp[i].children[3].remove();
3372
+ Temp[i].children[3].remove();
3373
+ Temp[i].children[3].remove();
3374
+ Temp[i].children[3].remove();
3375
+ }
3376
+
3377
+
3378
+ let CurrentPage = parseInt(SearchParams.get("page") || 1);
3379
+ let PID = Number(SearchParams.get("id"));
3380
+ let Pagination = `<nav class="center"><ul class="pagination justify-content-center">`;
3381
+ if (CurrentPage != 1) {
3382
+ Pagination += `<li class="page-item"><a href="https://www.xmoj.tech/problemstatus.php?id=${PID + `&page=1" class="page-link">&laquo;</a></li><li class="page-item"><a href="https://www.xmoj.tech/problemstatus.php?id=` + PID + `&page=` + (CurrentPage - 1) + `" class="page-link">` + (CurrentPage - 1)}</a></li>`;
3383
+ }
3384
+ Pagination += `<li class="active page-item"><a href="https://www.xmoj.tech/problemstatus.php?id=${PID + `&page=` + CurrentPage + `" class="page-link">` + CurrentPage}</a></li>`;
3385
+ if (document.querySelector("#problemstatus > tbody").children != null && document.querySelector("#problemstatus > tbody").children.length == 20) {
3386
+ Pagination += `<li class="page-item"><a href="https://www.xmoj.tech/problemstatus.php?id=${PID + `&page=` + (CurrentPage + 1) + `" class="page-link">` + (CurrentPage + 1) + `</a></li><li class="page-item"><a href="https://www.xmoj.tech/problemstatus.php?id=` + PID + `&page=` + (CurrentPage + 1)}" class="page-link">&raquo;</a></li>`;
3387
+ }
3388
+ Pagination += `</ul></nav>`;
3389
+ document.querySelector("body > div > div.mt-3 > center").innerHTML += Pagination;
3390
+ } else if (location.pathname == "/problem_solution.php") {
3391
+ if (UtilityEnabled("CopyMD")) {
3392
+ await fetch(location.href).then((Response) => {
3393
+ return Response.text();
3394
+ }).then((Response) => {
3395
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
3396
+ let CopyMDButton = document.createElement("button");
3397
+ CopyMDButton.className = "btn btn-sm btn-outline-secondary copy-btn";
3398
+ CopyMDButton.innerText = "复制";
3399
+ CopyMDButton.style.marginLeft = "10px";
3400
+ CopyMDButton.type = "button";
3401
+ document.querySelector("body > div > div.mt-3 > center > h2").appendChild(CopyMDButton);
3402
+ CopyMDButton.addEventListener("click", () => {
3403
+ GM_setClipboard(ParsedDocument.querySelector("body > div > div > div").innerText.trim().replaceAll("\n\t", "\n").replaceAll("\n\n", "\n").replaceAll("\n\n", "\n"));
3404
+ CopyMDButton.innerText = "复制成功";
3405
+ setTimeout(() => {
3406
+ CopyMDButton.innerText = "复制";
3407
+ }, 1000);
3408
+ });
3409
+ });
3410
+ }
3411
+ let Temp = document.getElementsByClassName("prettyprint");
3412
+ for (let i = 0; i < Temp.length; i++) {
3413
+ let Code = Temp[i].innerText;
3414
+ Temp[i].outerHTML = `<textarea class="prettyprint"></textarea>`;
3415
+ Temp[i].value = Code;
3416
+ }
3417
+ for (let i = 0; i < Temp.length; i++) {
3418
+ CodeMirror.fromTextArea(Temp[i], {
3419
+ lineNumbers: true,
3420
+ mode: "text/x-c++src",
3421
+ readOnly: true,
3422
+ theme: (UtilityEnabled("DarkMode") ? "darcula" : "default")
3423
+ }).setSize("100%", "auto");
3424
+ }
3425
+ } else if (location.pathname == "/open_contest.php") {
3426
+ let Temp = document.querySelector("body > div > div.mt-3 > div > div.col-md-8").children;
3427
+ let NewsData = [];
3428
+ for (let i = 0; i < Temp.length; i += 2) {
3429
+ let Title = Temp[i].children[0].innerText;
3430
+ let Time = 0;
3431
+ if (Temp[i].children[1] != null) {
3432
+ Time = Temp[i].children[1].innerText;
3433
+ }
3434
+ let Body = Temp[i + 1].innerHTML;
3435
+ NewsData.push({ "Title": Title, "Time": new Date(Time), "Body": Body });
3436
+ }
3437
+ document.querySelector("body > div > div.mt-3 > div > div.col-md-8").innerHTML = "";
3438
+ for (let i = 0; i < NewsData.length; i++) {
3439
+ let NewsRow = document.createElement("div");
3440
+ NewsRow.className = "cnt-row";
3441
+ let NewsRowHead = document.createElement("div");
3442
+ NewsRowHead.className = "cnt-row-head title";
3443
+ NewsRowHead.innerText = NewsData[i].Title;
3444
+ if (NewsData[i].Time.getTime() != 0) {
3445
+ NewsRowHead.innerHTML += "<small class=\"ms-3\">" + NewsData[i].Time.toLocaleDateString() + "</small>";
3446
+ }
3447
+ NewsRow.appendChild(NewsRowHead);
3448
+ let NewsRowBody = document.createElement("div");
3449
+ NewsRowBody.className = "cnt-row-body";
3450
+ NewsRowBody.innerHTML = NewsData[i].Body;
3451
+ NewsRow.appendChild(NewsRowBody);
3452
+ document.querySelector("body > div > div.mt-3 > div > div.col-md-8").appendChild(NewsRow);
3453
+ }
3454
+ let MyContestData = document.querySelector("body > div > div.mt-3 > div > div.col-md-4 > div:nth-child(2)").innerHTML;
3455
+ let CountDownData = document.querySelector("#countdown_list").innerHTML;
3456
+ document.querySelector("body > div > div.mt-3 > div > div.col-md-4").innerHTML = `<div class="cnt-row">
3457
+ <div class="cnt-row-head title">我的月赛</div>
3458
+ <div class="cnt-row-body">${MyContestData}</div>
3459
+ </div>
3460
+ <div class="cnt-row">
3461
+ <div class="cnt-row-head title">倒计时</div>
3462
+ <div class="cnt-row-body">${CountDownData}</div>
3463
+ </div>`;
3464
+ } else if (location.pathname == "/showsource.php") {
3465
+ let Code = "";
3466
+ if (SearchParams.get("ByUserScript") == null) {
3467
+ await fetch("https://www.xmoj.tech/getsource.php?id=" + SearchParams.get("id"))
3468
+ .then((Response) => {
3469
+ return Response.text();
3470
+ }).then((Response) => {
3471
+ Code = Response.substring(0, Response.indexOf("/**************************************************************")).trim();
3472
+ });
3473
+ }
3474
+ else {
3475
+ if (localStorage.getItem("UserScript-LastUploadedStdTime") === undefined ||
3476
+ new Date().getTime() - localStorage.getItem("UserScript-LastUploadedStdTime") > 1000 * 60 * 60 * 24 * 30) {
3477
+ location.href = "https://www.xmoj.tech/userinfo.php?ByUserScript=1";
3478
+ }
3479
+ await new Promise((Resolve) => {
3480
+ RequestAPI("GetStd", {
3481
+ "ProblemID": Number(SearchParams.get("pid"))
3482
+ }, (Response) => {
3483
+ if (Response.Success) {
3484
+ Code = Response.Data.StdCode;
3485
+ }
3486
+ else {
3487
+ Code = Response.Message;
3488
+ }
3489
+ Resolve();
3490
+ });
3491
+ });
3492
+ }
3493
+ document.querySelector("body > div > div.mt-3").innerHTML = `<textarea>${Code}</textarea>`;
3494
+ CodeMirror.fromTextArea(document.querySelector("body > div > div.mt-3 > textarea"), {
3495
+ lineNumbers: true,
3496
+ mode: "text/x-c++src",
3497
+ readOnly: true,
3498
+ theme: (UtilityEnabled("DarkMode") ? "darcula" : "default")
3499
+ }).setSize("100%", "auto");
3500
+ } else if (location.pathname == "/ceinfo.php") {
3501
+ await fetch(location.href)
3502
+ .then((Result) => {
3503
+ return Result.text();
3504
+ }).then((Result) => {
3505
+ let ParsedDocument = new DOMParser().parseFromString(Result, "text/html");
3506
+ document.querySelector("body > div > div.mt-3").innerHTML = "";
3507
+ let CodeElement = document.createElement("div");
3508
+ CodeElement.className = "mb-3";
3509
+ document.querySelector("body > div > div.mt-3").appendChild(CodeElement);
3510
+ CodeMirror(CodeElement, {
3511
+ value: ParsedDocument.getElementById("errtxt").innerHTML.replaceAll("&lt;", "<").replaceAll("&gt;", ">"),
3512
+ lineNumbers: true,
3513
+ mode: "text/x-c++src",
3514
+ readOnly: true,
3515
+ theme: (UtilityEnabled("DarkMode") ? "darcula" : "default")
3516
+ }).setSize("100%", "auto");
3517
+ });
3518
+ } else if (location.pathname == "/problem_std.php") {
3519
+ await fetch("https://www.xmoj.tech/problem_std.php?cid=" + SearchParams.get("cid") + "&pid=" + SearchParams.get("pid"))
3520
+ .then((Response) => {
3521
+ return Response.text();
3522
+ }).then((Response) => {
3523
+ let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
3524
+ let Temp = ParsedDocument.getElementsByTagName("pre");
3525
+ document.querySelector("body > div > div.mt-3").innerHTML = "";
3526
+ for (let i = 0; i < Temp.length; i++) {
3527
+ let CodeElement = document.createElement("div");
3528
+ CodeElement.className = "mb-3";
3529
+ document.querySelector("body > div > div.mt-3").appendChild(CodeElement);
3530
+ CodeMirror(CodeElement, {
3531
+ value: Temp[i].innerText,
3532
+ lineNumbers: true,
3533
+ mode: "text/x-c++src",
3534
+ readOnly: true,
3535
+ theme: (UtilityEnabled("DarkMode") ? "darcula" : "default")
3536
+ }).setSize("100%", "auto");
3537
+ }
3538
+ });
3539
+ } else if (location.pathname == "/mail.php") {
3540
+ if (SearchParams.get("other") == null) {
3541
+ document.querySelector("body > div > div.mt-3").innerHTML = `<div class="row g-2 align-items-center">
3542
+ <div class="col-auto form-floating">
3543
+ <input class="form-control" id="Username" placeholder=" " spellcheck="false" data-ms-editor="true">
3544
+ <label for="Username">搜索新用户</label>
3545
+ </div>
3546
+ <div class="col-auto form-floating">
3547
+ <button class="btn btn-outline-secondary" id="AddUser">
3548
+ 添加
3549
+ <div class="spinner-border spinner-border-sm" role="status" style="display: none;">
3550
+ </button>
3551
+ </div>
3552
+ </div>
3553
+ <table class="table mb-3" id="ReceiveTable">
3554
+ <thead>
3555
+ <tr>
3556
+ <td class="col-3">接收者</td>
3557
+ <td class="col-7">最新消息</td>
3558
+ <td class="col-2">最后联系时间</td>
3559
+ </tr>
3560
+ </thead>
3561
+ <tbody></tbody>
3562
+ </table>
3563
+ <div class="alert alert-danger mb-3" role="alert" id="ErrorElement" style="display: none;"></div>`;
3564
+ let RefreshMessageList = (Silent = true) => {
3565
+ if (!Silent) {
3566
+ ReceiveTable.children[1].innerHTML = "";
3567
+ for (let i = 0; i < 10; i++) {
3568
+ let Row = document.createElement("tr"); ReceiveTable.children[1].appendChild(Row);
3569
+ for (let j = 0; j < 3; j++) {
3570
+ let Cell = document.createElement("td"); Row.appendChild(Cell);
3571
+ Cell.innerHTML = `<span class="placeholder col-${Math.ceil(Math.random() * 12)}"></span>`;
3572
+ }
3573
+ }
3574
+ }
3575
+ RequestAPI("GetMailList", {}, async (ResponseData) => {
3576
+ if (ResponseData.Success) {
3577
+ ErrorElement.style.display = "none";
3578
+ let Data = ResponseData.Data.MailList;
3579
+ ReceiveTable.children[1].innerHTML = "";
3580
+ for (let i = 0; i < Data.length; i++) {
3581
+ let Row = document.createElement("tr"); ReceiveTable.children[1].appendChild(Row);
3582
+ let UsernameCell = document.createElement("td"); Row.appendChild(UsernameCell);
3583
+ let UsernameSpan = document.createElement("span"); UsernameCell.appendChild(UsernameSpan);
3584
+ GetUsernameHTML(UsernameSpan, Data[i].OtherUser, false, "https://www.xmoj.tech/mail.php?other=");
3585
+ if (Data[i].UnreadCount != 0) {
3586
+ let UnreadCountSpan = document.createElement("span"); UsernameCell.appendChild(UnreadCountSpan);
3587
+ UnreadCountSpan.className = "ms-1 badge text-bg-danger";
3588
+ UnreadCountSpan.innerText = Data[i].UnreadCount;
3589
+ }
3590
+ let LastsMessageCell = document.createElement("td"); Row.appendChild(LastsMessageCell);
3591
+ LastsMessageCell.innerText = Data[i].LastsMessage;
3592
+ let SendTimeCell = document.createElement("td"); Row.appendChild(SendTimeCell);
3593
+ SendTimeCell.innerHTML = GetRelativeTime(Data[i].SendTime);
3594
+ }
3595
+ }
3596
+ else {
3597
+ ErrorElement.innerText = ResponseData.Message;
3598
+ ErrorElement.style.display = "";
3599
+ }
3600
+ });
3601
+ };
3602
+ Username.addEventListener("input", () => {
3603
+ Username.classList.remove("is-invalid");
3604
+ });
3605
+ AddUser.addEventListener("click", () => {
3606
+ let UsernameData = Username.value;
3607
+ if (UsernameData == "") {
3608
+ Username.classList.add("is-invalid");
3609
+ return;
3610
+ }
3611
+ AddUser.children[0].style.display = "";
3612
+ AddUser.disabled = true;
3613
+ RequestAPI("SendMail", {
3614
+ "ToUser": String(UsernameData),
3615
+ "Content": String("您好,我是" + localStorage.getItem("UserScript-Username"))
3616
+ }, (ResponseData) => {
3617
+ AddUser.children[0].style.display = "none";
3618
+ AddUser.disabled = false;
3619
+ if (ResponseData.Success) {
3620
+ ErrorElement.style.display = "none";
3621
+ RefreshMessageList();
3622
+ }
3623
+ else {
3624
+ ErrorElement.innerText = ResponseData.Message;
3625
+ ErrorElement.style.display = "";
3626
+ }
3627
+ });
3628
+ });
3629
+ RefreshMessageList(false);
3630
+ addEventListener("focus", RefreshMessageList);
3631
+ }
3632
+ else {
3633
+ document.querySelector("body > div > div.mt-3").innerHTML = `<div class="row g-2 mb-3">
3634
+ <div class="col-md form-floating">
3635
+ <div class="form-control" id="ToUser"></div>
3636
+ <label for="ToUser">接收用户</label>
3637
+ </div>
3638
+ <div class="col-md form-floating">
3639
+ <input class="form-control" id="Content" placeholder=" ">
3640
+ <label for="Content">内容</label>
3641
+ </div>
3642
+ </div>
3643
+ <button id="Send" type="submit" class="btn btn-primary mb-1">
3644
+ 发送
3645
+ <div class="spinner-border spinner-border-sm" role="status" style="display: none;">
3646
+ </button>
3647
+ <div id="ErrorElement" class="alert alert-danger mb-3" role="alert" style="display: none;"></div>
3648
+ <table class="table mb-3" id="MessageTable">
3649
+ <thead>
3650
+ <tr>
3651
+ <td class="col-3">发送者</td>
3652
+ <td class="col-7">内容</td>
3653
+ <td class="col-1">发送时间</td>
3654
+ <td class="col-1">阅读状态</td>
3655
+ </tr>
3656
+ </thead>
3657
+ <tbody></tbody>
3658
+ </table>`;
3659
+ GetUsernameHTML(ToUser, SearchParams.get("other"));
3660
+ let RefreshMessage = (Silent = true) => {
3661
+ if (!Silent) {
3662
+ MessageTable.children[1].innerHTML = "";
3663
+ for (let i = 0; i < 10; i++) {
3664
+ let Row = document.createElement("tr"); MessageTable.children[1].appendChild(Row);
3665
+ for (let j = 0; j < 4; j++) {
3666
+ let Cell = document.createElement("td"); Row.appendChild(Cell);
3667
+ Cell.innerHTML = `<span class="placeholder col-${Math.ceil(Math.random() * 12)}"></span>`;
3668
+ }
3669
+ }
3670
+ }
3671
+ RequestAPI("GetMail", {
3672
+ "OtherUser": String(SearchParams.get("other"))
3673
+ }, async (ResponseData) => {
3674
+ if (ResponseData.Success) {
3675
+ ErrorElement.style.display = "none";
3676
+ let Data = ResponseData.Data.Mail;
3677
+ MessageTable.children[1].innerHTML = "";
3678
+ for (let i = 0; i < Data.length; i++) {
3679
+ let Row = document.createElement("tr"); MessageTable.children[1].appendChild(Row);
3680
+ if (!Data[i].IsRead && Data[i].FromUser != CurrentUsername) {
3681
+ Row.className = "table-info";
3682
+ }
3683
+ let UsernameCell = document.createElement("td"); Row.appendChild(UsernameCell);
3684
+ GetUsernameHTML(UsernameCell, Data[i].FromUser);
3685
+ let ContentCell = document.createElement("td"); Row.appendChild(ContentCell);
3686
+ ContentCell.innerHTML = PurifyHTML(Data[i].Content);
3687
+ let SendTimeCell = document.createElement("td"); Row.appendChild(SendTimeCell);
3688
+ SendTimeCell.innerHTML = GetRelativeTime(Data[i].SendTime);
3689
+ let IsReadCell = document.createElement("td"); Row.appendChild(IsReadCell);
3690
+ IsReadCell.innerHTML = (Data[i].IsRead ? "已读" : "未读");
3691
+ }
3692
+ }
3693
+ else {
3694
+ ErrorElement.innerText = ResponseData.Message;
3695
+ ErrorElement.style.display = "";
3696
+ }
3697
+ });
3698
+ };
3699
+ Content.addEventListener("input", () => {
3700
+ Content.classList.remove("is-invalid");
3701
+ });
3702
+ Content.addEventListener("keydown", (Event) => {
3703
+ if (Event.keyCode == 13) {
3704
+ Send.click();
3705
+ }
3706
+ });
3707
+ Send.addEventListener("click", () => {
3708
+ if (Content.value == "") {
3709
+ Content.classList.add("is-invalid");
3710
+ return;
3711
+ }
3712
+ Send.disabled = true;
3713
+ Send.children[0].style.display = "";
3714
+ let ContentData = Content.value;
3715
+ RequestAPI("SendMail", {
3716
+ "ToUser": String(SearchParams.get("other")),
3717
+ "Content": String(ContentData)
3718
+ }, (ResponseData) => {
3719
+ Send.disabled = false;
3720
+ Send.children[0].style.display = "none";
3721
+ if (ResponseData.Success) {
3722
+ ErrorElement.style.display = "none";
3723
+ Content.value = "";
3724
+ RefreshMessage();
3725
+ }
3726
+ else {
3727
+ ErrorElement.innerText = ResponseData.Message;
3728
+ ErrorElement.style.display = "";
3729
+ }
3730
+ });
3731
+ });
3732
+ RefreshMessage(false);
3733
+ addEventListener("focus", RefreshMessage);
3734
+ }
3735
+ } else if (location.pathname.indexOf("/discuss3") != -1) {
3736
+ if (UtilityEnabled("Discussion")) {
3737
+ Discussion.classList.add("active");
3738
+ if (location.pathname == "/discuss3/discuss.php") {
3739
+ let ProblemID = parseInt(SearchParams.get("pid"));
3740
+ let Page = Number(SearchParams.get("page")) || 1;
3741
+ document.querySelector("body > div > div").innerHTML = `<h3>讨论列表${(isNaN(ProblemID) ? "" : ` - 题目` + ProblemID)}</h3>
3742
+ <button id="NewPost" type="button" class="btn btn-primary">发布新讨论</button>
3743
+ <nav>
3744
+ <ul class="pagination justify-content-center" id="DiscussPagination">
3745
+ <li class="page-item"><a class="page-link" href="#"><span>&laquo;</span></a></li>
3746
+ <li class="page-item"><a class="page-link" href="#">${Page - 1}</a></li>
3747
+ <li class="page-item"><a class="page-link active" href="#">${Page}</a></li>
3748
+ <li class="page-item"><a class="page-link" href="#">${Page + 1}</a></li>
3749
+ <li class="page-item"><a class="page-link" href="#"><span>&raquo;</span></a></li>
3750
+ </ul>
3751
+ </nav>
3752
+ <div id="GotoBoard"></div>
3753
+ <div id="ErrorElement" class="alert alert-danger" role="alert" style="display: none;"></div>
3754
+ <table id="PostList" class="table table-hover">
3755
+ <thead>
3756
+ <tr>
3757
+ <th class="col-1">编号</th>
3758
+ <th class="col-3">标题</th>
3759
+ <th class="col-3">作者</th>
3760
+ <th class="col-1">题目编号</th>
3761
+ <th class="col-1">发布时间</th>
3762
+ <th class="col-1">回复数</th>
3763
+ <th class="col-1">最后回复</th>
3764
+ </tr>
3765
+ </thead>
3766
+ <tbody>
3767
+ </tbody>
3768
+ </table>`;
3769
+ NewPost.addEventListener("click", () => {
3770
+ if (!isNaN(ProblemID)) {
3771
+ location.href = "https://www.xmoj.tech/discuss3/newpost.php?pid=" + ProblemID;
3772
+ }
3773
+ else if (SearchParams.get("bid") != null) {
3774
+ location.href = "https://www.xmoj.tech/discuss3/newpost.php?bid=" + SearchParams.get("bid");
3775
+ }
3776
+ else {
3777
+ location.href = "https://www.xmoj.tech/discuss3/newpost.php";
3778
+ }
3779
+ });
3780
+ const RefreshPostList = (Silent = true) => {
3781
+ if (!Silent) {
3782
+ PostList.children[1].innerHTML = "";
3783
+ for (let i = 0; i < 10; i++) {
3784
+ let Row = document.createElement("tr"); PostList.children[1].appendChild(Row);
3785
+ for (let j = 0; j < 7; j++) {
3786
+ let Cell = document.createElement("td"); Row.appendChild(Cell);
3787
+ Cell.innerHTML = `<span class="placeholder col-${Math.ceil(Math.random() * 12)}"></span>`;
3788
+ }
3789
+ }
3790
+ }
3791
+ RequestAPI("GetPosts", {
3792
+ "ProblemID": Number(ProblemID || 0),
3793
+ "Page": Number(Page),
3794
+ "BoardID": Number(SearchParams.get("bid") || -1)
3795
+ }, async (ResponseData) => {
3796
+ if (ResponseData.Success == true) {
3797
+ ErrorElement.style.display = "none";
3798
+ if (!Silent) {
3799
+ DiscussPagination.children[0].children[0].href = "https://www.xmoj.tech/discuss3/discuss.php?" + (isNaN(ProblemID) ? "" : "pid=" + ProblemID + "&") + "page=1";
3800
+ DiscussPagination.children[1].children[0].href = "https://www.xmoj.tech/discuss3/discuss.php?" + (isNaN(ProblemID) ? "" : "pid=" + ProblemID + "&") + "page=" + (Page - 1);
3801
+ DiscussPagination.children[2].children[0].href = "https://www.xmoj.tech/discuss3/discuss.php?" + (isNaN(ProblemID) ? "" : "pid=" + ProblemID + "&") + "page=" + Page;
3802
+ DiscussPagination.children[3].children[0].href = "https://www.xmoj.tech/discuss3/discuss.php?" + (isNaN(ProblemID) ? "" : "pid=" + ProblemID + "&") + "page=" + (Page + 1);
3803
+ DiscussPagination.children[4].children[0].href = "https://www.xmoj.tech/discuss3/discuss.php?" + (isNaN(ProblemID) ? "" : "pid=" + ProblemID + "&") + "page=" + ResponseData.Data.PageCount;
3804
+ if (Page <= 1) {
3805
+ DiscussPagination.children[0].classList.add("disabled");
3806
+ DiscussPagination.children[1].remove();
3807
+ }
3808
+ if (Page >= ResponseData.Data.PageCount) {
3809
+ DiscussPagination.children[DiscussPagination.children.length - 1].classList.add("disabled");
3810
+ DiscussPagination.children[DiscussPagination.children.length - 2].remove();
3811
+ }
3812
+ }
3813
+ let Posts = ResponseData.Data.Posts;
3814
+ PostList.children[1].innerHTML = "";
3815
+ if (Posts.length == 0) {
3816
+ PostList.children[1].innerHTML = `<tr><td colspan="7">暂无数据</td></tr>`;
3817
+ }
3818
+ for (let i = 0; i < Posts.length; i++) {
3819
+ let Row = document.createElement("tr"); PostList.children[1].appendChild(Row);
3820
+ let IDCell = document.createElement("td"); Row.appendChild(IDCell);
3821
+ IDCell.innerText = Posts[i].PostID + " " + Posts[i].BoardName;
3822
+ let TitleCell = document.createElement("td"); Row.appendChild(TitleCell);
3823
+ let TitleLink = document.createElement("a"); TitleCell.appendChild(TitleLink);
3824
+ TitleLink.href = "https://www.xmoj.tech/discuss3/thread.php?tid=" + Posts[i].PostID;
3825
+ if (Posts[i].Lock.Locked) {
3826
+ TitleLink.classList.add("link-secondary");
3827
+ TitleLink.innerHTML = "🔒 ";
3828
+ }
3829
+ TitleLink.innerHTML += Posts[i].Title;
3830
+ let AuthorCell = document.createElement("td"); Row.appendChild(AuthorCell);
3831
+ GetUsernameHTML(AuthorCell, Posts[i].UserID);
3832
+ let ProblemIDCell = document.createElement("td"); Row.appendChild(ProblemIDCell);
3833
+ if (Posts[i].ProblemID != 0) {
3834
+ let ProblemIDLink = document.createElement("a"); ProblemIDCell.appendChild(ProblemIDLink);
3835
+ ProblemIDLink.href = "https://www.xmoj.tech/problem.php?id=" + Posts[i].ProblemID;
3836
+ ProblemIDLink.innerText = Posts[i].ProblemID;
3837
+ }
3838
+ let PostTimeCell = document.createElement("td"); Row.appendChild(PostTimeCell);
3839
+ PostTimeCell.innerHTML = GetRelativeTime(Posts[i].PostTime);
3840
+ let ReplyCountCell = document.createElement("td"); Row.appendChild(ReplyCountCell);
3841
+ ReplyCountCell.innerText = Posts[i].ReplyCount;
3842
+ let LastReplyTimeCell = document.createElement("td"); Row.appendChild(LastReplyTimeCell);
3843
+ LastReplyTimeCell.innerHTML = GetRelativeTime(Posts[i].LastReplyTime);
3844
+ }
3845
+ }
3846
+ else {
3847
+ ErrorElement.innerText = ResponseData.Message;
3848
+ ErrorElement.style.display = "block";
3849
+ }
3850
+ });
3851
+ };
3852
+ RefreshPostList(false);
3853
+ addEventListener("focus", RefreshPostList);
3854
+ RequestAPI("GetBoards", {}, (ResponseData) => {
3855
+ if (ResponseData.Success === true) {
3856
+ let LinkElement = document.createElement("a");
3857
+ LinkElement.href = "https://www.xmoj.tech/discuss3/discuss.php";
3858
+ LinkElement.classList.add("me-2");
3859
+ LinkElement.innerText = "全部";
3860
+ GotoBoard.appendChild(LinkElement);
3861
+ for (let i = 0; i < ResponseData.Data.Boards.length; i++) {
3862
+ let LinkElement = document.createElement("a");
3863
+ LinkElement.href = "https://www.xmoj.tech/discuss3/discuss.php?bid=" + ResponseData.Data.Boards[i].BoardID;
3864
+ LinkElement.classList.add("me-2");
3865
+ LinkElement.innerText = ResponseData.Data.Boards[i].BoardName;
3866
+ GotoBoard.appendChild(LinkElement);
3867
+ }
3868
+ }
3869
+ });
3870
+ } else if (location.pathname == "/discuss3/newpost.php") {
3871
+ let ProblemID = parseInt(SearchParams.get("pid"));
3872
+ document.querySelector("body > div > div").innerHTML = `<h3>发布新讨论` + (!isNaN(ProblemID) ? ` - 题目` + ProblemID : ``) + `</h3>
3873
+ <div class="form-group mb-3" id="BoardSelect">
3874
+ <label for="Board" class="mb-1">请选择要发布的板块</label>
3875
+ <div class="row ps-3" id="Board">
3876
+ </div>
3877
+ </div>
3878
+ <div class="form-group mb-3">
3879
+ <label for="Title" class="mb-1">标题</label>
3880
+ <input type="text" class="form-control" id="TitleElement" placeholder="请输入标题">
3881
+ </div>
3882
+ <div>
3883
+ <label for="ContentElement" class="mb-1">回复</label>
3884
+ <div class="input-group">
3885
+ <textarea class="col-6 form-control" id="ContentElement" rows="3" placeholder="请输入内容"></textarea>
3886
+ <div class="col-6 form-control" id="PreviewTab"></div>
3887
+ </div>
3888
+ <div class="cf-turnstile mt-2" id="CaptchaContainer"></div>
3889
+ <button id="SubmitElement" type="button" class="btn btn-primary mb-2" disabled>
3890
+ 发布
3891
+ <div class="spinner-border spinner-border-sm" role="status" style="display: none;">
3892
+ </button>
3893
+ </div>
3894
+ <div id="ErrorElement" class="alert alert-danger" role="alert" style="display: none;"></div>`;
3895
+ let CaptchaSecretKey = "";
3896
+ unsafeWindow.CaptchaLoadedCallback = () => {
3897
+ turnstile.render("#CaptchaContainer", {
3898
+ sitekey: CaptchaSiteKey,
3899
+ callback: function (CaptchaSecretKeyValue) {
3900
+ CaptchaSecretKey = CaptchaSecretKeyValue;
3901
+ SubmitElement.disabled = false;
3902
+ },
3903
+ });
3904
+ };
3905
+ let TurnstileScript = document.createElement("script");
3906
+ TurnstileScript.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit&onload=CaptchaLoadedCallback";
3907
+ document.body.appendChild(TurnstileScript);
3908
+ ContentElement.addEventListener("keydown", (Event) => {
3909
+ if (Event.ctrlKey && Event.keyCode == 13) {
3910
+ SubmitElement.click();
3911
+ }
3912
+ });
3913
+ ContentElement.addEventListener("input", () => {
3914
+ ContentElement.classList.remove("is-invalid");
3915
+ PreviewTab.innerHTML = PurifyHTML(marked.parse(ContentElement.value));
3916
+ RenderMathJax();
3917
+ });
3918
+ TitleElement.addEventListener("input", () => {
3919
+ TitleElement.classList.remove("is-invalid");
3920
+ });
3921
+ ContentElement.addEventListener("paste", (EventData) => {
3922
+ let Items = EventData.clipboardData.items;
3923
+ if (Items.length !== 0) {
3924
+ for (let i = 0; i < Items.length; i++) {
3925
+ if (Items[i].type.indexOf("image") != -1) {
3926
+ let Reader = new FileReader();
3927
+ Reader.readAsDataURL(Items[i].getAsFile());
3928
+ Reader.onload = () => {
3929
+ let Before = ContentElement.value.substring(0, ContentElement.selectionStart);
3930
+ let After = ContentElement.value.substring(ContentElement.selectionEnd, ContentElement.value.length);
3931
+ const UploadMessage = "![正在上传图片...]()";
3932
+ ContentElement.value = Before + UploadMessage + After;
3933
+ ContentElement.dispatchEvent(new Event("input"));
3934
+ RequestAPI("UploadImage", {
3935
+ "Image": Reader.result
3936
+ }, (ResponseData) => {
3937
+ if (ResponseData.Success) {
3938
+ ContentElement.value = Before + `![](https://assets.xmoj-bbs.tech/GetImage?ImageID=${ResponseData.Data.ImageID})` + After;
3939
+ ContentElement.dispatchEvent(new Event("input"));
3940
+ }
3941
+ else {
3942
+ ContentElement.value = Before + `![上传失败!]()` + After;
3943
+ ContentElement.dispatchEvent(new Event("input"));
3944
+ }
3945
+ });
3946
+ };
3947
+ }
3948
+ }
3949
+ }
3950
+ });
3951
+ SubmitElement.addEventListener("click", async () => {
3952
+ ErrorElement.style.display = "none";
3953
+ let Title = TitleElement.value;
3954
+ let Content = ContentElement.value;
3955
+ let ProblemID = parseInt(SearchParams.get("pid"));
3956
+ if (Title === "") {
3957
+ TitleElement.classList.add("is-invalid");
3958
+ return;
3959
+ }
3960
+ if (Content === "") {
3961
+ ContentElement.classList.add("is-invalid");
3962
+ return;
3963
+ }
3964
+ if (document.querySelector("#Board input:checked") === null) {
3965
+ ErrorElement.innerText = "请选择要发布的板块";
3966
+ ErrorElement.style.display = "block";
3967
+ return;
3968
+ }
3969
+ SubmitElement.disabled = true;
3970
+ SubmitElement.children[0].style.display = "inline-block";
3971
+ RequestAPI("NewPost", {
3972
+ "Title": String(Title),
3973
+ "Content": String(Content),
3974
+ "ProblemID": Number(isNaN(ProblemID) ? 0 : ProblemID),
3975
+ "CaptchaSecretKey": String(CaptchaSecretKey),
3976
+ "BoardID": Number(document.querySelector("#Board input:checked").value)
3977
+ }, (ResponseData) => {
3978
+ SubmitElement.disabled = false;
3979
+ SubmitElement.children[0].style.display = "none";
3980
+ if (ResponseData.Success == true) {
3981
+ location.href = "https://www.xmoj.tech/discuss3/thread.php?tid=" + ResponseData.Data.PostID;
3982
+ }
3983
+ else {
3984
+ ErrorElement.innerText = ResponseData.Message;
3985
+ ErrorElement.style.display = "block";
3986
+ }
3987
+ });
3988
+ });
3989
+ RequestAPI("GetBoards", {}, (ResponseData) => {
3990
+ if (ResponseData.Success === true) {
3991
+ let Data = ResponseData.Data.Boards;
3992
+ for (let i = 0; i < Data.length; i++) {
3993
+ let RadioElement = document.createElement("div");
3994
+ RadioElement.className = "col-auto form-check form-check-inline";
3995
+ let RadioInput = document.createElement("input");
3996
+ RadioInput.className = "form-check-input";
3997
+ RadioInput.type = "radio";
3998
+ RadioInput.name = "Board";
3999
+ RadioInput.id = "Board" + Data[i].BoardID;
4000
+ RadioInput.value = Data[i].BoardID;
4001
+ RadioElement.appendChild(RadioInput);
4002
+ if (SearchParams.get("bid") !== null && SearchParams.get("bid") == Data[i].BoardID) {
4003
+ RadioInput.checked = true;
4004
+ }
4005
+ if (!isNaN(ProblemID)) {
4006
+ RadioInput.disabled = true;
4007
+ }
4008
+ if (Data[i].BoardID == 4) {
4009
+ if (!isNaN(ProblemID))
4010
+ RadioInput.checked = true;
4011
+ RadioInput.disabled = true;
4012
+ }
4013
+ let RadioLabel = document.createElement("label");
4014
+ RadioLabel.className = "form-check-label";
4015
+ RadioLabel.htmlFor = "Board" + Data[i].BoardID;
4016
+ RadioLabel.innerText = Data[i].BoardName;
4017
+ RadioElement.appendChild(RadioLabel);
4018
+ Board.appendChild(RadioElement);
4019
+ }
4020
+ }
4021
+ });
4022
+ } else if (location.pathname == "/discuss3/thread.php") {
4023
+ if (SearchParams.get("tid") == null) {
4024
+ location.href = "https://www.xmoj.tech/discuss3/discuss.php";
4025
+ }
4026
+ else {
4027
+ let ThreadID = SearchParams.get("tid");
4028
+ let Page = Number(SearchParams.get("page")) || 1;
4029
+ document.querySelector("body > div > div").innerHTML = `<h3 id="PostTitle"></h3>
4030
+ <div class="row mb-3">
4031
+ <span class="col-5 text-muted">作者:<div style="display: inline-block;" id="PostAuthor"></div></span>
4032
+ <span class="col-3 text-muted">发布时间:<span id="PostTime"></span></span>
4033
+ <span class="col-2 text-muted">板块:<span id="PostBoard"></span></span>
4034
+ <span class="col-2">
4035
+ <button id="Delete" type="button" class="btn btn-sm btn-danger" style="display: none;">
4036
+ 删除
4037
+ <div class="spinner-border spinner-border-sm" role="status" style="display: none;">
4038
+ </button>
4039
+ </span>
4040
+ </div>
4041
+ <div id="PostReplies"></div>
4042
+ <nav>
4043
+ <ul class="pagination justify-content-center" id="DiscussPagination">
4044
+ <li class="page-item"><a class="page-link" href="#"><span>&laquo;</span></a></li>
4045
+ <li class="page-item"><a class="page-link" href="#">${(Page - 1)}</a></li>
4046
+ <li class="page-item"><a class="page-link active" href="#">${Page}</a></li>
4047
+ <li class="page-item"><a class="page-link" href="#">${(Page + 1)}</a></li>
4048
+ <li class="page-item"><a class="page-link" href="#"><span>&raquo;</span></a></li>
4049
+ </ul>
4050
+ </nav>
4051
+ <div>
4052
+ <div class="container p-0 m-0">
4053
+ <div class="row">
4054
+ <div class="col">
4055
+ <label for="ContentElement" class="mb-1">回复</label>
4056
+ </div>
4057
+ <div class="col">
4058
+ <div class="form-check form-switch" id="ToggleLock" style="display: none">
4059
+ <input class="form-check-input" type="checkbox" role="switch" id="ToggleLockButton">
4060
+ <label class="form-check-label" for="ToggleLockButton">锁定本讨论</label>
4061
+ </div>
4062
+ </div>
4063
+ </div>
4064
+ </div>
4065
+ <div class="input-group">
4066
+ <textarea class="col-6 form-control" id="ContentElement" rows="3" placeholder="请输入内容"></textarea>
4067
+ <div class="col-6 form-control" id="PreviewTab"></div>
4068
+ </div>
4069
+ <div class="cf-turnstile mt-2" id="CaptchaContainer"></div>
4070
+ <button id="SubmitElement" type="button" class="btn btn-primary mb-2" disabled>
4071
+ 发布
4072
+ <div class="spinner-border spinner-border-sm" role="status" style="display: none;">
4073
+ </button>
4074
+ </div>
4075
+ <div id="ErrorElement" class="alert alert-danger" role="alert" style="display: none;"></div>`;
4076
+ let CaptchaSecretKey = "";
4077
+ unsafeWindow.CaptchaLoadedCallback = () => {
4078
+ turnstile.render("#CaptchaContainer", {
4079
+ sitekey: CaptchaSiteKey,
4080
+ callback: function (CaptchaSecretKeyValue) {
4081
+ CaptchaSecretKey = CaptchaSecretKeyValue;
4082
+ SubmitElement.disabled = false;
4083
+ },
4084
+ });
4085
+ };
4086
+ let TurnstileScript = document.createElement("script");
4087
+ TurnstileScript.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit&onload=CaptchaLoadedCallback";
4088
+ document.body.appendChild(TurnstileScript);
4089
+ ContentElement.addEventListener("keydown", (Event) => {
4090
+ if (Event.ctrlKey && Event.keyCode == 13) {
4091
+ SubmitElement.click();
4092
+ }
4093
+ });
4094
+ ContentElement.addEventListener("input", () => {
4095
+ PreviewTab.innerHTML = PurifyHTML(marked.parse(ContentElement.value));
4096
+ RenderMathJax();
4097
+ });
4098
+ ContentElement.addEventListener("paste", (EventData) => {
4099
+ let Items = EventData.clipboardData.items;
4100
+ if (Items.length !== 0) {
4101
+ for (let i = 0; i < Items.length; i++) {
4102
+ if (Items[i].type.indexOf("image") != -1) {
4103
+ let Reader = new FileReader();
4104
+ Reader.readAsDataURL(Items[i].getAsFile());
4105
+ Reader.onload = () => {
4106
+ let Before = ContentElement.value.substring(0, ContentElement.selectionStart);
4107
+ let After = ContentElement.value.substring(ContentElement.selectionEnd, ContentElement.value.length);
4108
+ const UploadMessage = "![正在上传图片...]()";
4109
+ ContentElement.value = Before + UploadMessage + After;
4110
+ ContentElement.dispatchEvent(new Event("input"));
4111
+ RequestAPI("UploadImage", {
4112
+ "Image": Reader.result
4113
+ }, (ResponseData) => {
4114
+ if (ResponseData.Success) {
4115
+ ContentElement.value = Before + `![](https://assets.xmoj-bbs.tech/GetImage?ImageID=${ResponseData.Data.ImageID})` + After;
4116
+ ContentElement.dispatchEvent(new Event("input"));
4117
+ }
4118
+ else {
4119
+ ContentElement.value = Before + `![上传失败!]()` + After;
4120
+ ContentElement.dispatchEvent(new Event("input"));
4121
+ }
4122
+ });
4123
+ };
4124
+ }
4125
+ }
4126
+ }
4127
+ });
4128
+ let RefreshReply = (Silent = true) => {
4129
+ if (!Silent) {
4130
+ PostTitle.innerHTML = `<span class="placeholder col-${Math.ceil(Math.random() * 6)}"></span>`;
4131
+ PostAuthor.innerHTML = `<span class="placeholder col-${Math.ceil(Math.random() * 6)}"></span>`;
4132
+ PostTime.innerHTML = `<span class="placeholder col-${Math.ceil(Math.random() * 6)}"></span>`;
4133
+ PostBoard.innerHTML = `<span class="placeholder col-${Math.ceil(Math.random() * 6)}"></span>`;
4134
+ PostReplies.innerHTML = "";
4135
+ for (let i = 0; i < 10; i++) {
4136
+ PostReplies.innerHTML += `<div class="card mb-3">
4137
+ <div class="card-body">
4138
+ <div class="row mb-3">
4139
+ <span class="col-6"><span class="placeholder col-${Math.ceil(Math.random() * 6)}"></span></span>
4140
+ <span class="col-6"><span class="placeholder col-${Math.ceil(Math.random() * 6)}"></span></span>
4141
+ </div>
4142
+ <hr>
4143
+ <span class="placeholder col-${Math.ceil(Math.random() * 12)}"></span>
4144
+ <span class="placeholder col-${Math.ceil(Math.random() * 12)}"></span>
4145
+ <span class="placeholder col-${Math.ceil(Math.random() * 12)}"></span>
4146
+ </div>
4147
+ </div>`;
4148
+ }
4149
+ }
4150
+ RequestAPI("GetPost", {
4151
+ "PostID": Number(ThreadID),
4152
+ "Page": Number(Page)
4153
+ }, async (ResponseData) => {
4154
+ if (ResponseData.Success == true) {
4155
+ let OldScrollTop = document.documentElement.scrollTop;
4156
+ let LockButtons = !IsAdmin && ResponseData.Data.Lock.Locked;
4157
+ if (!Silent) {
4158
+ DiscussPagination.children[0].children[0].href = "https://www.xmoj.tech/discuss3/thread.php?tid=" + ThreadID + "&page=1";
4159
+ DiscussPagination.children[1].children[0].href = "https://www.xmoj.tech/discuss3/thread.php?tid=" + ThreadID + "&page=" + (Page - 1);
4160
+ DiscussPagination.children[2].children[0].href = "https://www.xmoj.tech/discuss3/thread.php?tid=" + ThreadID + "&page=" + Page;
4161
+ DiscussPagination.children[3].children[0].href = "https://www.xmoj.tech/discuss3/thread.php?tid=" + ThreadID + "&page=" + (Page + 1);
4162
+ DiscussPagination.children[4].children[0].href = "https://www.xmoj.tech/discuss3/thread.php?tid=" + ThreadID + "&page=" + ResponseData.Data.PageCount;
4163
+ if (Page <= 1) {
4164
+ DiscussPagination.children[0].classList.add("disabled");
4165
+ DiscussPagination.children[1].remove();
4166
+ }
4167
+ if (Page >= ResponseData.Data.PageCount) {
4168
+ DiscussPagination.children[DiscussPagination.children.length - 1].classList.add("disabled");
4169
+ DiscussPagination.children[DiscussPagination.children.length - 2].remove();
4170
+ }
4171
+ if (IsAdmin || ResponseData.Data.UserID == CurrentUsername) {
4172
+ Delete.style.display = "";
4173
+ }
4174
+ }
4175
+ PostTitle.innerText = ResponseData.Data.Title + (ResponseData.Data.ProblemID == 0 ? "" : ` - 题目` + ResponseData.Data.ProblemID);
4176
+ PostAuthor.innerHTML = "<span></span>";
4177
+ GetUsernameHTML(PostAuthor.children[0], ResponseData.Data.UserID);
4178
+ PostTime.innerHTML = GetRelativeTime(ResponseData.Data.PostTime);
4179
+ PostBoard.innerHTML = ResponseData.Data.BoardName;
4180
+ let Replies = ResponseData.Data.Reply;
4181
+ PostReplies.innerHTML = "";
4182
+ for (let i = 0; i < Replies.length; i++) {
4183
+ let CardElement = document.createElement("div"); PostReplies.appendChild(CardElement);
4184
+ CardElement.className = "card mb-3";
4185
+ let CardBodyElement = document.createElement("div"); CardElement.appendChild(CardBodyElement);
4186
+ CardBodyElement.className = "card-body row";
4187
+ let CardBodyRowElement = document.createElement("div"); CardBodyElement.appendChild(CardBodyRowElement);
4188
+ CardBodyRowElement.className = "row mb-3";
4189
+ let AuthorElement = document.createElement("span"); CardBodyRowElement.appendChild(AuthorElement);
4190
+ AuthorElement.className = "col-4 text-muted";
4191
+ let AuthorSpanElement = document.createElement("span"); AuthorElement.appendChild(AuthorSpanElement);
4192
+ AuthorSpanElement.innerText = "作者:";
4193
+ let AuthorUsernameElement = document.createElement("span"); AuthorElement.appendChild(AuthorUsernameElement);
4194
+ GetUsernameHTML(AuthorUsernameElement, Replies[i].UserID);
4195
+ let SendTimeElement = document.createElement("span"); CardBodyRowElement.appendChild(SendTimeElement);
4196
+ SendTimeElement.className = "col-4 text-muted";
4197
+ SendTimeElement.innerHTML = "发布时间:" + GetRelativeTime(Replies[i].ReplyTime);
4198
+
4199
+ let OKButton;
4200
+ if (!LockButtons) {
4201
+ let ButtonsElement = document.createElement("span"); CardBodyRowElement.appendChild(ButtonsElement);
4202
+ ButtonsElement.className = "col-4";
4203
+ let ReplyButton = document.createElement("button"); ButtonsElement.appendChild(ReplyButton);
4204
+ ReplyButton.type = "button";
4205
+ ReplyButton.className = "btn btn-sm btn-info";
4206
+ ReplyButton.innerText = "回复";
4207
+ ReplyButton.addEventListener("click", () => {
4208
+ let Content = Replies[i].Content;
4209
+ while (Content.startsWith(">")) {
4210
+ Content = Content.substring(Content.indexOf("\n") + 1);
4211
+ }
4212
+ Content = Content.trim();
4213
+ Content = Content.split("\n").map((Line) => {
4214
+ return "> " + Line;
4215
+ }).join("\n");
4216
+ ContentElement.value += Content + `\n\n@${Replies[i].UserID} `;
4217
+ ContentElement.focus();
4218
+ });
4219
+ let DeleteButton = document.createElement("button"); ButtonsElement.appendChild(DeleteButton);
4220
+ DeleteButton.type = "button";
4221
+ DeleteButton.className = "btn btn-sm btn-danger ms-1";
4222
+ DeleteButton.innerText = "删除";
4223
+ DeleteButton.style.display = (IsAdmin || Replies[i].UserID == CurrentUsername ? "" : "none");
4224
+ DeleteButton.addEventListener("click", () => {
4225
+ DeleteButton.disabled = true;
4226
+ DeleteButton.lastChild.style.display = "";
4227
+ RequestAPI("DeleteReply", {
4228
+ "ReplyID": Number(Replies[i].ReplyID)
4229
+ }, (ResponseData) => {
4230
+ if (ResponseData.Success == true) {
4231
+ RefreshReply();
4232
+ }
4233
+ else {
4234
+ DeleteButton.disabled = false;
4235
+ DeleteButton.lastChild.style.display = "none";
4236
+ ErrorElement.innerText = ResponseData.Message;
4237
+ ErrorElement.style.display = "";
4238
+ }
4239
+ });
4240
+ });
4241
+ let DeleteSpin = document.createElement("div"); DeleteButton.appendChild(DeleteSpin);
4242
+ DeleteSpin.className = "spinner-border spinner-border-sm";
4243
+ DeleteSpin.role = "status";
4244
+ DeleteSpin.style.display = "none";
4245
+ OKButton = document.createElement("button"); ButtonsElement.appendChild(OKButton);
4246
+ OKButton.type = "button";
4247
+ OKButton.style.display = "none";
4248
+ OKButton.className = "btn btn-sm btn-success ms-1";
4249
+ OKButton.innerText = "确认";
4250
+ let OKSpin = document.createElement("div"); OKButton.appendChild(OKSpin);
4251
+ OKSpin.className = "spinner-border spinner-border-sm";
4252
+ OKSpin.role = "status";
4253
+ OKSpin.style.display = "none";
4254
+ OKButton.addEventListener("click", () => {
4255
+ OKButton.disabled = true;
4256
+ OKButton.lastChild.style.display = "";
4257
+ RequestAPI("EditReply", {
4258
+ ReplyID: Number(Replies[i].ReplyID),
4259
+ Content: String(ContentEditor.value)
4260
+ }, (ResponseData) => {
4261
+ if (ResponseData.Success == true) {
4262
+ RefreshReply();
4263
+ }
4264
+ else {
4265
+ OKButton.disabled = false;
4266
+ OKButton.lastChild.style.display = "none";
4267
+ ErrorElement.innerText = ResponseData.Message;
4268
+ ErrorElement.style.display = "";
4269
+ }
4270
+ });
4271
+ });
4272
+ let CancelButton = document.createElement("button"); ButtonsElement.appendChild(CancelButton);
4273
+ CancelButton.type = "button";
4274
+ CancelButton.style.display = "none";
4275
+ CancelButton.className = "btn btn-sm btn-secondary ms-1";
4276
+ CancelButton.innerText = "取消";
4277
+ CancelButton.addEventListener("click", () => {
4278
+ CardBodyElement.children[2].style.display = "";
4279
+ CardBodyElement.children[3].style.display = "none";
4280
+ EditButton.style.display = "";
4281
+ OKButton.style.display = "none";
4282
+ CancelButton.style.display = "none";
4283
+ });
4284
+ let EditButton = document.createElement("button"); ButtonsElement.appendChild(EditButton);
4285
+ EditButton.type = "button";
4286
+ EditButton.className = "btn btn-sm btn-warning ms-1";
4287
+ EditButton.innerText = "编辑";
4288
+ EditButton.style.display = (IsAdmin || Replies[i].UserID == CurrentUsername ? "" : "none");
4289
+ EditButton.addEventListener("click", () => {
4290
+ CardBodyElement.children[2].style.display = "none";
4291
+ CardBodyElement.children[3].style.display = "";
4292
+ EditButton.style.display = "none";
4293
+ OKButton.style.display = "";
4294
+ CancelButton.style.display = "";
4295
+ });
4296
+ }
4297
+
4298
+ let CardBodyHRElement = document.createElement("hr"); CardBodyElement.appendChild(CardBodyHRElement);
4299
+
4300
+ let ReplyContentElement = document.createElement("div"); CardBodyElement.appendChild(ReplyContentElement);
4301
+ ReplyContentElement.innerHTML = PurifyHTML(marked.parse(Replies[i].Content)).replaceAll(/@([a-zA-Z0-9]+)/g, `<b>@</b><span class="ms-1 Usernames">$1</span>`);
4302
+ if (Replies[i].EditTime != null) {
4303
+ if (Replies[i].EditPerson == Replies[i].UserID) {
4304
+ ReplyContentElement.innerHTML += `<span class="text-muted" style="font-size: 12px">最后编辑于${GetRelativeTime(Replies[i].EditTime)}</span>`;
4305
+ }
4306
+ else {
4307
+ ReplyContentElement.innerHTML += `<span class="text-muted" style="font-size: 12px">最后被<span class="Usernames">${Replies[i].EditPerson}</span>编辑于${GetRelativeTime(Replies[i].EditTime)}</span>`;
4308
+ }
4309
+ }
4310
+ let ContentEditElement = document.createElement("div"); CardBodyElement.appendChild(ContentEditElement);
4311
+ ContentEditElement.classList.add("input-group");
4312
+ ContentEditElement.style.display = "none";
4313
+ let ContentEditor = document.createElement("textarea"); ContentEditElement.appendChild(ContentEditor);
4314
+ ContentEditor.className = "form-control col-6";
4315
+ ContentEditor.rows = 3;
4316
+ ContentEditor.value = Replies[i].Content;
4317
+ if (ContentEditor.value.indexOf("<br>") != -1) {
4318
+ ContentEditor.value = ContentEditor.value.substring(0, ContentEditor.value.indexOf("<br>"));
4319
+ }
4320
+ ContentEditor.addEventListener("keydown", (Event) => {
4321
+ if (Event.ctrlKey && Event.keyCode == 13) {
4322
+ OKButton.click();
4323
+ }
4324
+ });
4325
+ let PreviewTab = document.createElement("div"); ContentEditElement.appendChild(PreviewTab);
4326
+ PreviewTab.className = "form-control col-6";
4327
+ PreviewTab.innerHTML = PurifyHTML(marked.parse(ContentEditor.value));
4328
+ ContentEditor.addEventListener("input", () => {
4329
+ PreviewTab.innerHTML = PurifyHTML(marked.parse(ContentEditor.value));
4330
+ RenderMathJax();
4331
+ });
4332
+ ContentEditor.addEventListener("paste", (EventData) => {
4333
+ let Items = EventData.clipboardData.items;
4334
+ if (Items.length !== 0) {
4335
+ for (let i = 0; i < Items.length; i++) {
4336
+ if (Items[i].type.indexOf("image") != -1) {
4337
+ let Reader = new FileReader();
4338
+ Reader.readAsDataURL(Items[i].getAsFile());
4339
+ Reader.onload = () => {
4340
+ let Before = ContentEditor.value.substring(0, ContentEditor.selectionStart);
4341
+ let After = ContentEditor.value.substring(ContentEditor.selectionEnd, ContentEditor.value.length);
4342
+ const UploadMessage = "![正在上传图片...]()";
4343
+ ContentEditor.value = Before + UploadMessage + After;
4344
+ ContentEditor.dispatchEvent(new Event("input"));
4345
+ RequestAPI("UploadImage", {
4346
+ "Image": Reader.result
4347
+ }, (ResponseData) => {
4348
+ if (ResponseData.Success) {
4349
+ ContentEditor.value = Before + `![](https://assets.xmoj-bbs.tech/GetImage?ImageID=${ResponseData.Data.ImageID})` + After;
4350
+ ContentEditor.dispatchEvent(new Event("input"));
4351
+ }
4352
+ else {
4353
+ ContentEditor.value = Before + `![上传失败!]()` + After;
4354
+ ContentEditor.dispatchEvent(new Event("input"));
4355
+ }
4356
+ });
4357
+ };
4358
+ }
4359
+ }
4360
+ }
4361
+ });
4362
+ }
4363
+
4364
+ let UsernameElements = document.getElementsByClassName("Usernames");
4365
+ for (let i = 0; i < UsernameElements.length; i++) {
4366
+ GetUsernameHTML(UsernameElements[i], UsernameElements[i].innerText, true);
4367
+ }
4368
+
4369
+ let CodeElements = document.querySelectorAll("#PostReplies > div > div > div:nth-child(3) > pre > code");
4370
+ for (let i = 0; i < CodeElements.length; i++) {
4371
+ let ModeName = "text/x-c++src";
4372
+ if (CodeElements[i].className == "language-c") {
4373
+ ModeName = "text/x-csrc";
4374
+ }
4375
+ else if (CodeElements[i].className == "language-cpp") {
4376
+ ModeName = "text/x-c++src";
4377
+ }
4378
+ CodeMirror(CodeElements[i].parentElement, {
4379
+ value: CodeElements[i].innerText,
4380
+ mode: ModeName,
4381
+ theme: (UtilityEnabled("DarkMode") ? "darcula" : "default"),
4382
+ lineNumbers: true,
4383
+ readOnly: true
4384
+ }).setSize("100%", "auto");
4385
+ CodeElements[i].remove();
4386
+ }
4387
+
4388
+ if (LockButtons) {
4389
+ let LockElement = ContentElement.parentElement.parentElement;
4390
+ LockElement.innerHTML = "讨论已于 " + await GetRelativeTime(ResponseData.Data.Lock.LockTime) + " 被 ";
4391
+ let LockUsernameSpan = document.createElement("span"); LockElement.appendChild(LockUsernameSpan);
4392
+ GetUsernameHTML(LockUsernameSpan, ResponseData.Data.Lock.LockPerson);
4393
+ LockElement.innerHTML += " 锁定";
4394
+ LockElement.classList.add("mb-5");
4395
+ }
4396
+
4397
+ if (IsAdmin) {
4398
+ ToggleLock.style.display = "inline-block";
4399
+ ToggleLockButton.checked = ResponseData.Data.Lock.Locked;
4400
+ ToggleLockButton.onclick = () => {
4401
+ ToggleLockButton.disabled = true;
4402
+ ErrorElement.style.display = "none";
4403
+ RequestAPI((ToggleLockButton.checked ? "LockPost" : "UnlockPost"), {
4404
+ "PostID": Number(ThreadID)
4405
+ }, (LockResponseData) => {
4406
+ ToggleLockButton.disabled = false;
4407
+ if (LockResponseData.Success) {
4408
+ RefreshReply();
4409
+ } else {
4410
+ ErrorElement.style.display = "";
4411
+ ErrorElement.innerText = "错误:" + LockResponseData.Message;
4412
+ ToggleLockButton.checked = !ToggleLockButton.checked;
4413
+ }
4414
+ });
4415
+ };
4416
+ }
4417
+
4418
+ Style.innerHTML += "img {";
4419
+ Style.innerHTML += " width: 50%;";
4420
+ Style.innerHTML += "}";
4421
+
4422
+ RenderMathJax();
4423
+
4424
+ if (Silent) {
4425
+ scrollTo({
4426
+ top: OldScrollTop,
4427
+ behavior: "instant"
4428
+ });
4429
+ }
4430
+ }
4431
+ else {
4432
+ PostTitle.innerText = "错误:" + ResponseData.Message;
4433
+ }
4434
+ });
4435
+ };
4436
+ Delete.addEventListener("click", () => {
4437
+ Delete.disabled = true;
4438
+ Delete.children[0].style.display = "inline-block";
4439
+ RequestAPI("DeletePost", {
4440
+ "PostID": Number(SearchParams.get("tid"))
4441
+ }, (ResponseData) => {
4442
+ Delete.disabled = false;
4443
+ Delete.children[0].style.display = "none";
4444
+ if (ResponseData.Success == true) {
4445
+ location.href = "https://www.xmoj.tech/discuss3/discuss.php";
4446
+ }
4447
+ else {
4448
+ ErrorElement.innerText = ResponseData.Message;
4449
+ ErrorElement.style.display = "block";
4450
+ }
4451
+ });
4452
+ });
4453
+ SubmitElement.addEventListener("click", async () => {
4454
+ ErrorElement.style.display = "none";
4455
+ SubmitElement.disabled = true;
4456
+ SubmitElement.children[0].style.display = "inline-block";
4457
+ RequestAPI("NewReply", {
4458
+ "PostID": Number(SearchParams.get("tid")),
4459
+ "Content": String(ContentElement.value),
4460
+ "CaptchaSecretKey": String(CaptchaSecretKey)
4461
+ }, async (ResponseData) => {
4462
+ SubmitElement.disabled = false;
4463
+ SubmitElement.children[0].style.display = "none";
4464
+ if (ResponseData.Success == true) {
4465
+ RefreshReply();
4466
+ ContentElement.value = "";
4467
+ PreviewTab.innerHTML = "";
4468
+ while (PostReplies.innerHTML.indexOf("placeholder") != -1) {
4469
+ await new Promise((resolve) => {
4470
+ setTimeout(resolve, 100);
4471
+ });
4472
+ }
4473
+ ContentElement.focus();
4474
+ ContentElement.scrollIntoView();
4475
+ turnstile.reset();
4476
+ }
4477
+ else {
4478
+ ErrorElement.innerText = ResponseData.Message;
4479
+ ErrorElement.style.display = "block";
4480
+ }
4481
+ });
4482
+ });
4483
+ RefreshReply(false);
4484
+ addEventListener("focus", RefreshReply);
4485
+ }
4486
+ }
4487
+ }
4488
+ }
4489
+ }
4490
+ }