Ex124OJ

Extend 124OJ!

当前为 2023-07-22 提交的版本,查看 最新版本

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