Ex124OJ

Extend 124OJ!

当前为 2022-12-16 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Ex124OJ
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.10.3
  5. // @description Extend 124OJ!
  6. // @author Sukwants
  7. // @license MIT
  8. // @match http://124.221.194.184
  9. // @match http://124.221.194.184/*
  10. // @icon https://www.imageoss.com/images/2022/11/29/ex124OJba563861978a769d.png
  11. // @grant GM_addStyle
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM_listValues
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // @grant GM_deleteValue
  17. // @connect ex124oj.netlify.app
  18. // ==/UserScript==
  19.  
  20.  
  21. const HomepageRegExp = /^http:\/\/124.221.194.184(\/){0,1}(\?.*){0,1}$/;
  22. function isHomepage() {
  23. return HomepageRegExp.test(window.location.href);
  24. }
  25. const submissionRegExp = /^http:\/\/124.221.194.184\/submission\/\d{1,}/;
  26. function isSubmission() {
  27. return submissionRegExp.test(window.location.href);
  28. }
  29. const ProblemRegExp = /^http:\/\/124.221.194.184.*\/problem\/(\d{1,})(\?.*){0,1}$/;
  30. function isProblem() {
  31. return ProblemRegExp.test(window.location.href);
  32. }
  33. const UserProfileRegExp = /^http:\/\/124.221.194.184\/user\/profile\/.{1,}/;
  34. function isUserProfile() {
  35. return UserProfileRegExp.test(window.location.href);
  36. }
  37. const BlogRegExp = /^http:\/\/124.221.194.184\/blog\/.{1,}/;
  38. function isBlog() {
  39. return BlogRegExp.test(window.location.href);
  40. }
  41.  
  42. var BackgroundImage;
  43. var SiteIconImage;
  44. var SiteIconSmallImage;
  45. var Academic;
  46. function resetVariables() {
  47. BackgroundImage = GM_getValue('BackgroundImage') != undefined ? GM_getValue('BackgroundImage') : '';
  48. SiteIconImage = GM_getValue('SiteIconImage') != undefined ? GM_getValue('SiteIconImage') : 'https://www.imageoss.com/images/2022/11/29/ex124OJba563861978a769d.png';
  49. SiteIconSmallImage = GM_getValue('SiteIconSmallImage') != undefined ? GM_getValue('SiteIconSmallImage') : 'https://www.imageoss.com/images/2022/12/13/icon1ca65ac1e49f8ec3c.png';
  50. Academic = GM_getValue('Academic') != undefined ? GM_getValue('Academic') : false;
  51. }
  52. resetVariables();
  53.  
  54. var NameColorList = GM_getValue('NameColorList') != undefined ? GM_getValue('NameColorList') : {};
  55. var CCFBadgeList = GM_getValue('CCFBadgeList') != undefined ? GM_getValue('CCFBadgeList') : {};
  56. var TagBadgeList = GM_getValue('TagBadgeList') != undefined ? GM_getValue('TagBadgeList') : {};
  57. GM_xmlhttpRequest({
  58. method: "GET",
  59. url: "https://ex124oj.netlify.app/public/variables.json",
  60. onload: function(data) {
  61. var variables = JSON.parse(data.responseText);
  62. NameColorList = variables.NameColorList;
  63. GM_setValue('NameColorList', NameColorList);
  64. CCFBadgeList = variables.CCFBadgeList;
  65. GM_setValue('CCFBadgeList', CCFBadgeList);
  66. TagBadgeList = variables.TagBadgeList;
  67. GM_setValue('TagBadgeList', TagBadgeList);
  68. FunctionsWithUniversalVariables();
  69. }
  70. });
  71.  
  72. (function() {
  73. 'use strict';
  74. Settings();
  75. FontAwesome();
  76. Background();
  77. changeIcon();
  78. DiscussionCard();
  79. CodeBlock();
  80. TableStyle();
  81. RandomProblem();
  82. if (isHomepage()) exAnnouncements();
  83. if (isSubmission()) SubmissionCard();
  84. if (isProblem()) downloadData();
  85. if (isUserProfile() || isBlog()) changeGravatarURL();
  86. FunctionsWithUniversalVariables();
  87. })();
  88.  
  89. function FunctionsWithUniversalVariables() {
  90. clearNameStyle();
  91. NameColor();
  92. NameBadge();
  93. }
  94.  
  95. function Settings() {
  96. GM_addStyle('\
  97. .settings-popup-active .settings-overlay {\
  98. background: rgb(0,0,0,.3);\
  99. visibility: visible;\
  100. }\
  101. .settings-overlay {\
  102. position: fixed;\
  103. height: 100%;\
  104. width: 100%;\
  105. transition: visibility 0.4s, background 0.4s;\
  106. top: 0;\
  107. left: 0;\
  108. visibility: hidden;\
  109. z-index: 229;\
  110. }\
  111. .settings-popup {\
  112. width: 60%;\
  113. position: relative;\
  114. top: 50%;\
  115. left: 50%;\
  116. transform: translate(-50%, -50%);\
  117. background: #ffffff;\
  118. border-radius: .5rem;\
  119. padding: 20px 20px;\
  120. }\
  121. .settings-popup .row {\
  122. padding: 0 30px 30px;\
  123. }\
  124. .settings-titlebar {\
  125. padding: 10px 20px 30px 20px !important;\
  126. }\
  127. .settings-titlebar h4 {\
  128. position: relative;\
  129. top: 50%;\
  130. left: 0;\
  131. transform: translate(0, -50%);\
  132. }\
  133. .settings-footerbar {\
  134. height: 60px;\
  135. padding: 20px 20px;\
  136. }\
  137. ');
  138. var HomepageEntrance = document.createElement('li');
  139. document.getElementsByClassName('container')[0].children[0].children[0].children[0].before(HomepageEntrance);
  140. HomepageEntrance.setAttribute('class', 'nav-item');
  141. HomepageEntrance.innerHTML = '<span style="padding: 0.5rem 1rem; cursor:pointer"><span style="background-color: #28adca;padding:0.2em 0.6em;border-radius: 1em;color:#fff;font-size: 0.7em;font-weight:bold;display:inline-block;position: relative;top: 50%;transform: translate(0,-50%);">Ex124OJ</span></span>';
  142. HomepageEntrance.onclick = function() {
  143. document.body.setAttribute('class', 'settings-popup-active');
  144. }
  145. var SettingsOverlay = document.createElement('div');
  146. document.body.children[0].before(SettingsOverlay);
  147. SettingsOverlay.setAttribute('class', 'settings-overlay');
  148. var SettingsPopup = document.createElement('div');
  149. SettingsOverlay.appendChild(SettingsPopup);
  150. SettingsPopup.setAttribute('class', 'settings-popup');
  151. var SettingsTitlebar = document.createElement('div');
  152. SettingsPopup.appendChild(SettingsTitlebar);
  153. SettingsTitlebar.setAttribute('class', 'row settings-titlebar');
  154. SettingsTitlebar.innerHTML = '<h3 style="width: 100%;"><img src="https://ex124oj.netlify.app/images/icon.png" style="height:3.5rem;width:3.5rem;margin-right:10px"><span style="line-height: 3.5rem;vertical-align: middle"> Ex124OJ 控制面板</span><span style="padding: 0.5rem 1rem;vertical-align: middle;cursor: pointer" onclick="window.open(\'https://ex124oj.netlify.app/\');"><span style="background-color: #28adca;padding:0.2em 0.6em;border-radius: 1em;color:#fff;font-size: 0.7em;font-weight:bold;display:inline-block;">Ex124OJ</span></span></h3>';
  155. var SettingsCloseButton = document.createElement('span');
  156. SettingsPopup.appendChild(SettingsCloseButton);
  157. SettingsCloseButton.setAttribute('style', 'position: fixed;right: 20px;top:20px;cursor: pointer');
  158. SettingsCloseButton.setAttribute('onclick', 'document.body.setAttribute(\'class\', \'\');');
  159. SettingsCloseButton.innerHTML = '<h4><i class="fa fa-xmark"></i></h4>';
  160.  
  161. var background = document.createElement('div');
  162. SettingsPopup.appendChild(background);
  163. background.setAttribute('class', 'row');
  164. var backgroundImageLabel = document.createElement('strong');
  165. background.appendChild(backgroundImageLabel);
  166. backgroundImageLabel.setAttribute('style', 'font-size: 1.25em');
  167. backgroundImageLabel.innerHTML = '背景图片&emsp;&emsp;&emsp;&emsp;';
  168. var backgroundImageInput = document.createElement('input');
  169. background.appendChild(backgroundImageInput);
  170. backgroundImageInput.setAttribute('style', 'flex-grow: 1; height: 2em; width: initial');
  171. backgroundImageInput.setAttribute('class', 'form-control');
  172.  
  173. var siteIcon = document.createElement('div');
  174. SettingsPopup.appendChild(siteIcon);
  175. siteIcon.setAttribute('class', 'row');
  176. var siteIconImageLabel = document.createElement('strong');
  177. siteIcon.appendChild(siteIconImageLabel);
  178. siteIconImageLabel.setAttribute('style', 'font-size: 1.25em');
  179. siteIconImageLabel.innerHTML = '网站图标&emsp;&emsp;&emsp;&emsp;';
  180. var siteIconImageInput = document.createElement('input');
  181. siteIcon.appendChild(siteIconImageInput);
  182. siteIconImageInput.setAttribute('style', 'flex-grow: 1; height: 2em; width: initial');
  183. siteIconImageInput.setAttribute('class', 'form-control');
  184.  
  185. var siteIconSmall = document.createElement('div');
  186. SettingsPopup.appendChild(siteIconSmall);
  187. siteIconSmall.setAttribute('class', 'row');
  188. var siteIconSmallImageLabel = document.createElement('strong');
  189. siteIconSmall.appendChild(siteIconSmallImageLabel);
  190. siteIconSmallImageLabel.setAttribute('style', 'font-size: 1.25em');
  191. siteIconSmallImageLabel.innerHTML = '网站图标(小)&emsp;';
  192. var siteIconSmallImageInput = document.createElement('input');
  193. siteIconSmall.appendChild(siteIconSmallImageInput);
  194. siteIconSmallImageInput.setAttribute('style', 'flex-grow: 1; height: 2em; width: initial');
  195. siteIconSmallImageInput.setAttribute('class', 'form-control');
  196.  
  197. var academic = document.createElement('div');
  198. SettingsPopup.appendChild(academic);
  199. academic.setAttribute('class', 'row');
  200. academic.setAttribute('style', 'line-height: 2.5em;vertical-align: middle');
  201. var academicLabel = document.createElement('strong');
  202. academic.appendChild(academicLabel);
  203. academicLabel.setAttribute('style', 'font-size: 1.25em');
  204. academicLabel.innerHTML = '学术模式&emsp;&emsp;&emsp;&emsp;';
  205. var academicOff = document.createElement('div');
  206. academic.appendChild(academicOff);
  207. academicOff.innerHTML = '<input type="radio" id="AcademicOff"> 关闭&emsp;';
  208. var academicOn = document.createElement('div');
  209. academic.appendChild(academicOn);
  210. academicOn.innerHTML = '<input type="radio" id="AcademicOn"> 开启&emsp;';
  211. document.getElementById('AcademicOff').onclick = function() {
  212. document.getElementById('AcademicOn').checked = false;
  213. }
  214. document.getElementById('AcademicOn').onclick = function() {
  215. document.getElementById('AcademicOff').checked = false;
  216. }
  217.  
  218. function resetModified() {
  219. backgroundImageInput.value = BackgroundImage;
  220. siteIconImageInput.value = SiteIconImage;
  221. siteIconSmallImageInput.value = SiteIconSmallImage;
  222. if (Academic != true) {
  223. document.getElementById('AcademicOff').checked = true;
  224. document.getElementById('AcademicOn').checked = false;
  225. }
  226. else {
  227. document.getElementById('AcademicOff').checked = false;
  228. document.getElementById('AcademicOn').checked = true;
  229. }
  230. }
  231. resetModified();
  232.  
  233. var FooterRow = document.createElement('div');
  234. FooterRow.setAttribute('class', 'settings-footerbar');
  235. SettingsPopup.appendChild(FooterRow);
  236. var Ok = document.createElement('button');
  237. FooterRow.appendChild(Ok);
  238. Ok.setAttribute('class', 'btn btn-search btn-outline-primary float-right');
  239. Ok.innerHTML = '保存';
  240. Ok.onclick = function() {
  241. GM_setValue('BackgroundImage', backgroundImageInput.value);
  242. GM_setValue('SiteIconImage', siteIconImageInput.value);
  243. GM_setValue('SiteIconSmallImage', siteIconSmallImageInput.value);
  244. GM_setValue('Academic', document.getElementById('AcademicOn').checked);
  245. resetVariables();
  246. window.location.href = window.location.href;
  247. };
  248. var Clear = document.createElement('button');
  249. FooterRow.appendChild(Clear);
  250. Clear.setAttribute('class', 'btn btn-search btn-outline-primary float-right');
  251. Clear.innerHTML = '恢复默认';
  252. Clear.onclick = function() {
  253. var values = GM_listValues();
  254. for (var value in values) {
  255. GM_deleteValue(values[value]);
  256. }
  257. resetVariables();
  258. resetModified();
  259. window.location.href = window.location.href;
  260. }
  261. }
  262.  
  263. function FontAwesome() {
  264. var fa = document.createElement('link');
  265. fa.setAttribute('href', 'https://cdn.bootcdn.net/ajax/libs/font-awesome/6.2.1/css/fontawesome.css');
  266. fa.setAttribute('rel', 'stylesheet');
  267. document.head.appendChild(fa);
  268. var fab = document.createElement('link');
  269. fab.setAttribute('href', 'https://cdn.bootcdn.net/ajax/libs/font-awesome/6.2.1/css/brands.css');
  270. fab.setAttribute('rel', 'stylesheet');
  271. document.head.appendChild(fab);
  272. var fas = document.createElement('link');
  273. fas.setAttribute('href', 'https://cdn.bootcdn.net/ajax/libs/font-awesome/6.2.1/css/solid.css');
  274. fas.setAttribute('rel', 'stylesheet');
  275. document.head.appendChild(fas);
  276. }
  277.  
  278. function Background() {
  279. if (BackgroundImage) {
  280. document.getElementsByClassName('navbar-brand')[0].innerHTML = '<img src="http://124.221.194.184/images/logo_small.png" alt="Logo" class="img-rounded" style="width:39px; height:39px;">';
  281. document.getElementsByClassName('container')[0].children[0].children[1].innerHTML = document.getElementsByClassName('container')[0].children[0].children[1].innerHTML.match(/(.*> ){0,1}(.*)/)[2];
  282. GM_addStyle('\
  283. body {\
  284. background: url("' + BackgroundImage + '");\
  285. background-repeat: no-repeat;\
  286. background-attachment: fixed;\
  287. background-position: 50% 50%;\
  288. background-size: cover;\
  289. }\
  290. .uoj-content {\
  291. background-color: #fff;\
  292. margin: 16px -16px;\
  293. padding: 16px 16px;\
  294. opacity: 0.85;\
  295. border-radius: 8px;\
  296. }\
  297. .navbar {\
  298. margin: 16px -16px;\
  299. padding: 8px 16px;\
  300. opacity: 0.85;\
  301. border-radius: 8px;\
  302. }\
  303. .giscus {\
  304. opacity: 0.85;\
  305. }');
  306. }
  307. }
  308.  
  309. function getIcon() {
  310. if (SiteIconImage) return SiteIconImage;
  311. else return '/images/logo.png';
  312. }
  313. function getIconSmall() {
  314. if (SiteIconSmallImage) return SiteIconSmallImage;
  315. else return getIcon();
  316. }
  317. function changeIcon() {
  318. const LogoURLRegExp = /^.*\/images\/logo(_small){0,1}.png$/;
  319. var Links = document.getElementsByTagName('link');
  320. for (var link in Links) {
  321. if (Links[link] && Links[link].nodeType && Links[link].getAttribute('rel') == 'shortcut icon') {
  322. Links[link].setAttribute('href', getIconSmall());
  323. }
  324. }
  325. var Icons = document.getElementsByTagName('img');
  326. for (var icon in Icons) {
  327. if (Icons[icon] && Icons[icon].nodeType && LogoURLRegExp.test(Icons[icon].getAttribute('src'))) {
  328. if (!Icons[icon].getAttribute('style')) {
  329. Icons[icon].setAttribute('src', getIcon());
  330. Icons[icon].setAttribute('style', 'width:100%;height:auto;object-fit:cover');
  331. }
  332. else {
  333. Icons[icon].setAttribute('src', getIconSmall());
  334. }
  335. }
  336. }
  337. }
  338.  
  339. function exAnnouncements() {
  340. const HtmlBodyInnerExp = /^[\s\S]*<div id="archives">([\s\S]*)<\/div>\s*?<footer id="footer">[\s\S]*$/;
  341. const WrittenByExp = /^by (.*)$/;
  342. const DateTimeExp = /^(.*?) .*$/;
  343. if (document.getElementsByClassName('uoj-content')[0].children[0].children[0].children[0]) {
  344. GM_xmlhttpRequest({
  345. method: "GET",
  346. url: "https://ex124oj.netlify.app/categories/announcements/",
  347. onload: function(data) {
  348. var Announcements = document.getElementsByClassName('uoj-content')[0].children[0].children[0].children[0].children[0].children[0];
  349. Announcements.children[0].children[0].innerHTML = '<th style="width:30%">公告</th><th style="width:10%"></th><th style="width:10%"></th><th style="width:30%">Ex 公告</th><th style="width:10%"></th><th style="width:10%"></th>';
  350. var trs = Announcements.children[1].getElementsByTagName('tr');
  351. for (var tr = 0; tr < trs.length - 1; ++tr) {
  352. if (trs[tr].innerHTML) {
  353. trs[tr].innerHTML = (trs[tr].children.length > 2 ? trs[tr].innerHTML : '<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>') + '<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>';
  354. if (WrittenByExp.test(trs[tr].children[1] && trs[tr].children[1].innerHTML)) {
  355. trs[tr].children[1].innerHTML = trs[tr].children[1].innerHTML.match(WrittenByExp)[1];
  356. }
  357. if (DateTimeExp.test(trs[tr].children[2] && trs[tr].children[2].innerHTML)) {
  358. trs[tr].children[2].innerHTML = '<small>' + trs[tr].children[2].textContent.match(DateTimeExp)[1] + '</small>';
  359. }
  360. }
  361. }
  362. Announcements.children[1].children[Announcements.children[1].children.length - 1].innerHTML = '<td class="text-right" colspan="3"><a href="/announcements">所有公告……</a></td><td class="text-right" colspan="3"><a href="https://ex124oj.netlify.app/categories/announcements/">所有公告……</a></td>';
  363. var Posts = document.createElement('div');
  364. Posts.innerHTML = data.responseText.match(HtmlBodyInnerExp)[1];
  365. for (var i = 0; i < Posts.children.length && i < 5; ++i) {
  366. Announcements.children[1].children[i].children[3].innerHTML = '<a href="https://ex124oj.netlify.app' + Posts.children[i].children[0].children[0].children[1].getAttribute('href') + '">' + Posts.children[i].children[0].children[0].children[1].children[0].innerHTML.match(/^\s*(.*?)\s*$/)[1] + '</a>';
  367. Announcements.children[1].children[i].children[4].innerHTML = '<a class="uoj-username" href="https://ex124oj.netlify.app" style="color:rgb(40,173,202)">Ex124OJ</a>';
  368. var Date = Posts.children[i].children[0].children[0].children[0].innerHTML.match(/^(\d*)\/(\d*)\/(\d*)$/);
  369. if (Date[2].length < 2) Date[2] = '0' + Date[2];
  370. if (Date[3].length < 2) Date[3] = '0' + Date[3];
  371. Announcements.children[1].children[i].children[5].innerHTML = '<small>' + Date[1] + '-' + Date[2] + '-' + Date[3] + '</small>'
  372. }
  373. }
  374. });
  375. }
  376. }
  377.  
  378. function RandomProblem() {
  379. var SearchBox = document.getElementById('form-search-problem')
  380. if (SearchBox) {
  381. var RandomButton = document.createElement('div');
  382. RandomButton.setAttribute('class', 'input-group-append');
  383. RandomButton.innerHTML = '<button class="btn btn-search btn-outline-primary" onclick="randomProblem();">随机跳题</button>';
  384. var RandomScript = document.createElement('script');
  385. RandomScript.innerHTML = '\
  386. var randomProblemId, randomProblemResult;\
  387. function randomProblem() {\
  388. randomProblemId = Math.ceil(Math.random() * 3000);\
  389. randomProblemResult = ($.get(\'/problem/\' + randomProblemId));\
  390. turntoProblem();\
  391. }\
  392. function turntoProblem() {\
  393. console.log(randomProblemResult.status);\
  394. if (randomProblemResult.status) {\
  395. if (randomProblemResult.status == 200) {\
  396. window.location.href = \'http://124.221.194.184/problem/\' + randomProblemId;\
  397. }\
  398. else {\
  399. randomProblem();\
  400. }\
  401. }\
  402. else {\
  403. setTimeout(turntoProblem, 10);\
  404. }\
  405. }';
  406. SearchBox.after(RandomButton);
  407. RandomButton.after(RandomScript);
  408. }
  409. }
  410.  
  411. function DiscussionCard() {
  412. var discrd = document.createElement('div');
  413. discrd.setAttribute('class', 'giscus');
  414. document.getElementsByClassName('uoj-footer')[0].before(discrd);
  415. var script = document.createElement('script');
  416. script.setAttribute('src', 'https://giscus.app/client.js');
  417. script.setAttribute('data-repo', 'Sukwants/Discuss124OJ');
  418. script.setAttribute('data-repo-id', 'R_kgDOImiZLA');
  419. script.setAttribute('data-category', 'Ideas');
  420. script.setAttribute('data-category-id', 'DIC_kwDOImiZLM4CTCIj');
  421. script.setAttribute('data-mapping', 'pathname');
  422. script.setAttribute('data-strict', '0');
  423. script.setAttribute('data-reactions-enabled', '1');
  424. script.setAttribute('data-emit-metadata', '0');
  425. script.setAttribute('data-input-position', 'top');
  426. script.setAttribute('data-theme', 'preferred_color_scheme');
  427. script.setAttribute('data-lang', 'zh-CN');
  428. script.setAttribute('crossorigin', 'anonymous');
  429. script.setAttribute('async', '');
  430. document.getElementsByTagName('body')[0].appendChild(script);
  431. GM_addStyle('\
  432. .giscus {\
  433. margin-top: 20px;\
  434. display: ' + (Academic == true ? 'none' : 'unset') + ';\
  435. }');
  436. }
  437.  
  438. function CodeBlock() {
  439. const ManageStatementExp = /^.*\/manage\/statement(\?.*){0,1}$/
  440. GM_addStyle('\
  441. @import url(https://cdn.jsdelivr.net/npm/firacode@6.2.0/distr/fira_code.css);\
  442. code {\
  443. font-family: "Fira Code";\
  444. }\
  445. code.sh_cpp>span {\
  446. font-style: normal !important;\
  447. font-weight: 400 !important;\
  448. }\
  449. code.sh_cpp>span.sh_preproc,\
  450. code.sh_cpp>span.sh_keyword,\
  451. code.sh_cpp>span.sh_type {\
  452. color: #8959a8;\
  453. }\
  454. code.sh_cpp>span.sh_string {\
  455. color: #718c00;\
  456. }\
  457. code.sh_cpp>span.sh_cbracket {\
  458. color: #4d4d4c;\
  459. }\
  460. code.sh_cpp>span.sh_symbol {\
  461. color: #3e999f;\
  462. }\
  463. code.sh_cpp>span.sh_number {\
  464. color: #f5871f;\
  465. }\
  466. code.sh_cpp>span.sh_function {\
  467. color: #4271ae;\
  468. }\
  469. code.sh_cpp>span.sh_comment {\
  470. color: #8e908c;\
  471. }\
  472. .copybutton {\
  473. float: right;\
  474. background-color: rgb(0,0,0,.1);\
  475. padding: .25em .625em;\
  476. border: 0 solid transparent;\
  477. border-radius: .28571429rem;\
  478. }\
  479. .copybutton:hover {\
  480. background-color: rgb(0,0,0,.2);\
  481. }\
  482. .copybutton:focus {\
  483. background-color: rgb(0,0,0,.2);\
  484. outline: none;\
  485. }');
  486. if (!ManageStatementExp.test(window.location.href)) {
  487. setTimeout(function(){
  488. var CodeBlocks = document.getElementsByTagName('pre');
  489. for (var cb in CodeBlocks) {
  490. if (CodeBlocks[cb] && CodeBlocks[cb].nodeType) {
  491. var Content = CodeBlocks[cb].textContent;
  492. var InputId = Math.round(Math.random() * 998244353);
  493. var ButtonId = Math.round(Math.random() * 998244353);
  494. CodeBlocks[cb].innerHTML = '<button class="copybutton" id = "' + ButtonId + '" onclick="\
  495. var ib = document.getElementById(\'' + InputId + '\');\
  496. ib.setAttribute(\'style\', \'display:initial\');\
  497. ib.value = \'' + Content.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/'/g, '\\&#39;').replace(/"/g, '&#34;') + '\';\
  498. ib.select();\
  499. document.execCommand(\'copy\');\
  500. ib.setAttribute(\'style\', \'display:none\');\
  501. var ic = document.getElementById(\'' + ButtonId + '\');\
  502. ic.innerHTML = \'已复制\';\
  503. setTimeout(function() { ic.innerHTML = \'复制\'; }, 500);">复制</button>' + CodeBlocks[cb].innerHTML;
  504. var InputBox = document.createElement('textarea');
  505. InputBox.setAttribute('id', InputId);
  506. InputBox.setAttribute('style', 'display:none');
  507. CodeBlocks[cb].appendChild(InputBox);
  508. }
  509. }
  510.  
  511. }, 30);
  512. }
  513. }
  514.  
  515. function TableStyle() {
  516. var Tables = document.getElementsByTagName('table');
  517. for (var table in Tables) {
  518. if (Tables[table].nodeType && Tables[table].parentNode.getAttribute('class') != 'legend' && !Tables[table].classList.length) {
  519. Tables[table].classList.add('table', 'table-bordered');
  520. }
  521. }
  522. var ths = document.getElementsByTagName('th');
  523. for (var th in ths) {
  524. if (ths[th].nodeType && ths[th].getAttribute('align')) {
  525. ths[th].setAttribute('style', 'text-align:' + ths[th].getAttribute('align'));
  526. }
  527. }
  528. }
  529.  
  530. function SubmissionCard() {
  531. setTimeout(function() {
  532. var Content = document.getElementsByClassName('uoj-content')[0];
  533. if (Content.childElementCount == 3) {
  534. var Table = Content.children[0];
  535. var TabList = document.createElement('ul');
  536. TabList.setAttribute('class', 'nav nav-tabs');
  537. TabList.setAttribute('role', 'tablist');
  538. TabList.innerHTML = '<li class="nav-item"><a class="nav-link active" href="#test-cases" role="tab" data-toggle="tab" aria-selected="true"><span class="glyphicon glyphicon-check"></span> 测试点信息</a></li><li class="nav-item"><a class="nav-link" href="#source" role="tab" data-toggle="tab" aria-selected="false"><span class="glyphicon glyphicon-file"></span> 源代码</a></li>';
  539. var TabContent = document.createElement('div');
  540. TabContent.setAttribute('class', 'tab-content');
  541. TabContent.innerHTML = '<div class="tab-pane card active" id="test-cases"><div class="card-body">' + Content.children[2].children[1].innerHTML + '</div></div><div class="tab-pane card" id="source"><div class="card-body">' + Content.children[1].children[1].innerHTML + '</div></div>';
  542. Content.innerHTML = "";
  543. Content.appendChild(Table);
  544. Content.appendChild(TabList);
  545. Content.appendChild(TabContent);
  546. }
  547. }, 50);
  548. }
  549.  
  550. function downloadData() {
  551. var DownloadTag = document.createElement('a');
  552. DownloadTag.setAttribute('role', 'button');
  553. DownloadTag.setAttribute('class', 'btn btn-primary float-right');
  554. DownloadTag.setAttribute('href', '/download.php?type=problem&id=' + window.location.href.match(ProblemRegExp)[1]);
  555. DownloadTag.setAttribute('target', '_blank');
  556. DownloadTag.innerHTML = '<span class="glyphicon glyphicon-download-alt"></span> 下载数据';
  557. document.getElementsByClassName("btn btn-info float-right")[0].after(DownloadTag);
  558. }
  559.  
  560. function changeGravatarURL() {
  561. const GravatarURLRegExp = /\/\/cn.gravatar.com\/avatar\/(.*)$/;
  562. var Gravatar = document.getElementsByClassName('img-thumbnail')[0];
  563. if (Gravatar && Gravatar.nodeType){
  564. console.log(Gravatar);
  565. Gravatar.setAttribute('src', '//gravatar.loli.net/avatar/' + Gravatar.getAttribute('src').match(GravatarURLRegExp)[1]);
  566. }
  567. var Gravatars = document.getElementsByClassName('img-rounded');
  568. for (var gravatar in Gravatars) {
  569. if (Gravatars[gravatar] && Gravatars[gravatar].nodeType && GravatarURLRegExp.test(Gravatars[gravatar].getAttribute('src'))) {
  570. Gravatars[gravatar].setAttribute('src', '//gravatar.loli.net/avatar/' + Gravatars[gravatar].getAttribute('src').match(GravatarURLRegExp)[1]);
  571. }
  572. }
  573. }
  574.  
  575. function clearNameStyle() {
  576. const NameExp = /^(.{1,}?)( .*)*$/;
  577. var Names = document.getElementsByClassName('uoj-username');
  578. for (var i in Names) {
  579. if (!Names[i].innerHTML) continue;
  580. Names[i].innerHTML = Names[i].textContent.match(NameExp)[1];
  581. }
  582. var Honors = document.getElementsByClassName('uoj-honor');
  583. for (var j in Honors) {
  584. if (!Honors[j].innerHTML) continue;
  585. Honors[j].innerHTML = Honors[j].textContent.match(NameExp)[1];
  586. }
  587. }
  588.  
  589. function NameColor() {
  590. var Names = document.getElementsByClassName('uoj-username');
  591. var NeedsRepeat = false;
  592. for (var i in Names) {
  593. if (Names[i].innerHTML && NameColorList[Names[i].innerHTML]) {
  594. Names[i].style = 'color:' + NameColorList[Names[i].innerHTML][0];
  595. var resN = '';
  596. for (var charN = 1; charN < NameColorList[Names[i].innerHTML].length; ++charN) {
  597. resN = resN + '<font style="color:' + NameColorList[Names[i].innerHTML][charN] + '">' + Names[i].innerHTML.substring(charN - 1, charN) + '</font>';
  598. }
  599. Names[i].innerHTML = resN + Names[i].innerHTML.substring(NameColorList[Names[i].innerHTML].length - 1);
  600. if (Names[i].parentElement.getAttribute('class') == 'legendLabel') {
  601. NeedsRepeat = true;
  602. }
  603. }
  604. }
  605. if (NeedsRepeat) {
  606. setInterval(function(){
  607. var Names = document.getElementsByClassName('uoj-username');
  608. for (var i in Names) {
  609. if (Names[i].innerHTML && Names[i].parentElement.getAttribute('class') == 'legendLabel' && NameColorList[Names[i].innerHTML]) {
  610. Names[i].style = 'color:' + NameColorList[Names[i].innerHTML][0];
  611. var resN = '';
  612. for (var charN = 1; charN < NameColorList[Names[i].innerHTML].length; ++charN) {
  613. resN = resN + '<font style="color:' + NameColorList[Names[i].innerHTML][charN] + '">' + Names[i].innerHTML.substring(charN - 1, charN) + '</font>';
  614. }
  615. Names[i].innerHTML = resN + Names[i].innerHTML.substring(NameColorList[Names[i].innerHTML].length - 1);
  616. }
  617. }
  618. }, 200);
  619. }
  620. var Honors = document.getElementsByClassName('uoj-honor');
  621. for (var j in Honors) {
  622. if (Honors[j].innerHTML && NameColorList[Honors[j].innerHTML]) {
  623. Honors[j].style = 'color:' + NameColorList[Honors[j].innerHTML][0];
  624. var resH = '';
  625. for (var charH = 1; charH < NameColorList[Honors[j].innerHTML].length; ++charH) {
  626. resH = resH + '<font style="color:' + NameColorList[Honors[j].innerHTML][charH] + '">' + Honors[j].innerHTML.substring(charH - 1, charH) + '</font>';
  627. }
  628. Honors[j].innerHTML = resH + Honors[j].innerHTML.substring(NameColorList[Honors[j].innerHTML].length - 1);
  629. }
  630. }
  631. }
  632.  
  633. function NameBadge() {
  634. var Names = document.getElementsByClassName('uoj-username');
  635. for (var i in Names) {
  636. if (!Names[i].innerHTML) continue;
  637. var name = Names[i].textContent;
  638. if (CCFBadgeList[name] && Names[i].parentElement.getAttribute('class') != 'legendLabel') {
  639. Names[i].innerHTML = Names[i].innerHTML + ' <svg width="1em" height="1em" data-v-303bbf52="" aria-hidden="true" focusable="false" data-prefix="fad" data-icon="badge-check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="margin-bottom:.25em!important;bottom:10px;--fa-primary-color:#fff;--fa-secondary-color:' + CCFBadgeList[name] + ';--fa-secondary-opacity:1;"><g data-v-303bbf52="" class="fa-group"><path data-v-303bbf52="" fill="var(--fa-secondary-color)" d="M512 256a88 88 0 0 0-57.1-82.4A88 88 0 0 0 338.4 57.1a88 88 0 0 0-164.8 0A88 88 0 0 0 57.1 173.6a88 88 0 0 0 0 164.8 88 88 0 0 0 116.5 116.5 88 88 0 0 0 164.8 0 88 88 0 0 0 116.5-116.5A88 88 0 0 0 512 256zm-144.8-44.25l-131 130a11 11 0 0 1-15.55-.06l-75.72-76.33a11 11 0 0 1 .06-15.56L171 224a11 11 0 0 1 15.56.06l42.15 42.49 97.2-96.42a11 11 0 0 1 15.55.06l25.82 26a11 11 0 0 1-.08 15.56z" class="fa-secondary"></path></g></svg>';
  640. }
  641. if (TagBadgeList[name] && Names[i].parentElement.getAttribute('class') != 'legendLabel') {
  642. Names[i].innerHTML = Names[i].innerHTML + ' <span style="background-color:' + TagBadgeList[name][0] + ';padding:0.2em 0.6em;border-radius:.2em;color:#fff;font-size:0.7em;font-weight:bold;display:inline-block">' + TagBadgeList[name][1] + '</span>';
  643. }
  644. }
  645. var Honors = document.getElementsByClassName('uoj-honor');
  646. for (var j in Honors) {
  647. if (!Honors[j].innerHTML) continue;
  648. var honor = Honors[j].textContent;
  649. if (CCFBadgeList[honor]) {
  650. Honors[j].innerHTML = Honors[j].innerHTML + ' <svg width="1em" height="1em" data-v-303bbf52="" aria-hidden="true" focusable="false" data-prefix="fad" data-icon="badge-check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="margin-bottom:.25em!important;bottom:10px;--fa-primary-color:#fff;--fa-secondary-color:' + CCFBadgeList[honor] + ';--fa-secondary-opacity:1;"><g data-v-303bbf52="" class="fa-group"><path data-v-303bbf52="" fill="var(--fa-secondary-color)" d="M512 256a88 88 0 0 0-57.1-82.4A88 88 0 0 0 338.4 57.1a88 88 0 0 0-164.8 0A88 88 0 0 0 57.1 173.6a88 88 0 0 0 0 164.8 88 88 0 0 0 116.5 116.5 88 88 0 0 0 164.8 0 88 88 0 0 0 116.5-116.5A88 88 0 0 0 512 256zm-144.8-44.25l-131 130a11 11 0 0 1-15.55-.06l-75.72-76.33a11 11 0 0 1 .06-15.56L171 224a11 11 0 0 1 15.56.06l42.15 42.49 97.2-96.42a11 11 0 0 1 15.55.06l25.82 26a11 11 0 0 1-.08 15.56z" class="fa-secondary"></path></g></svg>';
  651. }
  652. if (TagBadgeList[honor]) {
  653. Honors[j].innerHTML = Honors[j].innerHTML + ' <span style="background-color:' + TagBadgeList[honor][0] + ';padding:0.2em 0.6em;border-radius:.2em;color:#fff;font-size:0.7em;font-weight:bold;display:inline-block">' + TagBadgeList[honor][1] + '</span>';
  654. }
  655. }
  656. }