Luogu Tasks

在洛谷侧边栏显示题单与自己存的题

As of 2021-05-15. See the latest version.

  1. // ==UserScript==
  2. // @name Luogu Tasks
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.3
  5. // @run-at document-start
  6. // @description 在洛谷侧边栏显示题单与自己存的题
  7. // @author __OwO__
  8. // @match https://www.luogu.com.cn/*
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @grant unsafeWindow
  12. // @require https://cdn.staticfile.org/jquery/3.5.1/jquery.min.js
  13. // @require https://cdn.staticfile.org/sweetalert/2.1.2/sweetalert.min.js
  14. // ==/UserScript==
  15.  
  16. window.onload = async () => {
  17. const inject_lantency = 500;
  18. var _wr = (type) => {
  19. var orig = history[type];
  20. return function () {
  21. var e = new Event(type);
  22. e.arguments = arguments;
  23. window.dispatchEvent(e);
  24. var rv = orig.apply(this, arguments);
  25. return rv;
  26. };
  27. };
  28. history.pushState = _wr("pushState");
  29. history.replaceState = _wr("replaceState");
  30.  
  31. let configs = {
  32. set train(v) {
  33. GM_setValue("problem-helper-local-train-list", v);
  34. },
  35. get train() {
  36. return GM_getValue("problem-helper-local-train-list") || [];
  37. },
  38. set local(v) {
  39. GM_setValue("problem-helper-local-id", v);
  40. },
  41. get local() {
  42. return GM_getValue("problem-helper-local-id") || null;
  43. },
  44. set hideac(v) {
  45. GM_setValue("problem-helper-hide-aced", v);
  46. },
  47. get hideac() {
  48. return GM_getValue("problem-helper-hide-aced") || false;
  49. },
  50. };
  51.  
  52. let local_problems;
  53. let geticon = (pid, uid, scr, fscr, stat = null) => {
  54. let res;
  55. let ua = (uid, pid) =>
  56. `<a data-v-303bbf52="" data-v-357e29e4="" href="/record/list?pid=${pid}&amp;user=${uid}" target="_blank" colorscheme="default" class="color-default" data-v-83961efe="" style="color: inherit; float:left; padding-right: 0.5em;"><svg data-v-1b44b3e6="" data-v-357e29e4="" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="times" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 352 512" class="icon svg-inline--fa fa-times fa-w-11" data-v-303bbf52="" style="transform: scale(1.2); color: rgb(231, 76, 60);"><path data-v-1b44b3e6="" fill="currentColor" d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z" class=""></path></svg></a>`;
  57. let ac = (uid, pid) =>
  58. `<a data-v-303bbf52="" data-v-357e29e4="" href="/record/list?pid=${pid}&amp;user=${uid}" target="_blank" colorscheme="default" class="color-default" data-v-83961efe="" style="color: inherit; float:left; padding-right: 0.5em;"><svg data-v-1b44b3e6="" data-v-357e29e4="" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon svg-inline--fa fa-check fa-w-16" data-v-303bbf52="" style="color: rgb(82, 196, 26);"><path data-v-1b44b3e6="" fill="currentColor" d="M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z" class=""></path></svg></a>`;
  59. let nt = (uid, pid) =>
  60. `<a data-v-303bbf52="" data-v-357e29e4="" href="/record/list?pid=${pid}&amp;user=${uid}" target="_blank" colorscheme="default" class="color-default" data-v-83961efe="" style="color: inherit; float:left; padding-right: 0.5em;"><svg data-v-1b44b3e6="" data-v-357e29e4="" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="minus" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="icon svg-inline--fa fa-minus fa-w-14" data-v-303bbf52="" style="opacity: 0.7;"><path data-v-1b44b3e6="" fill="currentColor" d="M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z" class=""></path></svg></a>`;
  61. if (scr == fscr || stat) res = ac(uid, pid);
  62. else if (scr == null) res = nt(uid, pid);
  63. else res = ua(uid, pid);
  64. return (
  65. `<span data-v-3fb75f36="" style="font-weight: bold;">` + res + `</span>`
  66. );
  67. };
  68. let renderList = (title, content, float) =>
  69. `
  70. <div
  71. data-v-796309f8=""
  72. data-v-3fb75f36=""
  73. class="card padding-default"
  74. data-v-6febb0e8=""
  75. id="problem-helper-container"
  76. >
  77. ${float}
  78. <h4 data-v-3fb75f36="" data-v-796309f8="" class="lfe-h4">${title}</h4>
  79. <div class="problem-helper-inner" style="display:none;">
  80. ${content}
  81. </div>
  82. <div data-v-e4b7c2ca="" data-v-3fb75f36="" class="expand-tip lfe-caption" data-v-796309f8="" >
  83. <span class="problem-helper-fold-off" style="display:none;" data-v-e4b7c2ca=""><svg data-v-e4b7c2ca="" aria-hidden="true" focusable="false" data-prefix="fal" data-icon="chevron-up" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="svg-inline--fa fa-chevron-up fa-w-14" ><path data-v-e4b7c2ca="" fill="currentColor" d="M4.465 366.475l7.07 7.071c4.686 4.686 12.284 4.686 16.971 0L224 178.053l195.494 195.493c4.686 4.686 12.284 4.686 16.971 0l7.07-7.071c4.686-4.686 4.686-12.284 0-16.97l-211.05-211.051c-4.686-4.686-12.284-4.686-16.971 0L4.465 349.505c-4.687 4.686-4.687 12.284 0 16.97z" class=""></path></svg> 隐藏列表</span>
  84. <span class="problem-helper-fold-on" data-v-e4b7c2ca=""><svg data-v-e4b7c2ca="" aria-hidden="true" focusable="false" data-prefix="fal" data-icon="chevron-down" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="svg-inline--fa fa-chevron-down fa-w-14"><path data-v-e4b7c2ca="" fill="currentColor" d="M443.5 162.6l-7.1-7.1c-4.7-4.7-12.3-4.7-17 0L224 351 28.5 155.5c-4.7-4.7-12.3-4.7-17 0l-7.1 7.1c-4.7 4.7-4.7 12.3 0 17l211 211.1c4.7 4.7 12.3 4.7 17 0l211-211.1c4.8-4.7 4.8-12.3.1-17z" class=""></path></svg> 查看列表</span>
  85. </div>
  86. </div>
  87. `;
  88. function getTask(id) {
  89. return new Promise((r) => {
  90. $.get(`https://www.luogu.com.cn/training/${id}?_contentOnly=any`).then(
  91. (u) => r(u.currentData.training)
  92. );
  93. });
  94. }
  95. let loadProblemList = async (id) => {
  96. task = await getTask(id);
  97. let getList = (x, is_local) => {
  98. let id = task.problems[x].problem.pid;
  99. if (configs.hideac && task.userScore.status[id] && id != configs.local)
  100. return "";
  101. return `
  102. <div>
  103. <div>
  104. <span data-v-3a151854="">
  105. <a
  106. data-v-303bbf52=""
  107. data-v-3fb75f36=""
  108. href="/record/list?pid=${id}&amp;user=${task.userScore.user.uid}"
  109. class="color-default"
  110. style="text-decoration: none;"
  111. >
  112. ${geticon(
  113. id,
  114. task.userScore.user.uid,
  115. task.userScore.score[id],
  116. task.problems[x].problem.fullScore,
  117. task.userScore.status[id]
  118. )}
  119. </a>
  120. ${
  121. is_local
  122. ? `
  123. <a
  124. data-v-3fb75f36=""
  125. style="float: right;font-weight: light;"
  126. class="problem-helper-delete-from-list"
  127. data="${id}"
  128. >
  129. <svg data-v-4121e124="" aria-hidden="true" focusable="false" data-prefix="fal" data-icon="times" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" class="svg-inline--fa fa-times fa-w-10"><path data-v-4121e124="" fill="currentColor" d="M193.94 256L296.5 153.44l21.15-21.15c3.12-3.12 3.12-8.19 0-11.31l-22.63-22.63c-3.12-3.12-8.19-3.12-11.31 0L160 222.06 36.29 98.34c-3.12-3.12-8.19-3.12-11.31 0L2.34 120.97c-3.12 3.12-3.12 8.19 0 11.31L126.06 256 2.34 379.71c-3.12 3.12-3.12 8.19 0 11.31l22.63 22.63c3.12 3.12 8.19 3.12 11.31 0L160 289.94 262.56 392.5l21.15 21.15c3.12 3.12 8.19 3.12 11.31 0l22.63-22.63c3.12-3.12 3.12-8.19 0-11.31L193.94 256z" class=""></path></svg>
  130. </a>
  131. `
  132. : ""
  133. }
  134. </span>
  135. <a
  136. class="colored problem-helper-text"
  137. style="padding-left: 3px"
  138. href="/problemnew/show/${id}"
  139. target="_blank"
  140. >
  141. <b>${id}</b> ${task.problems[x].problem.title}
  142. </a>
  143. </div>
  144. </div>`;
  145. };
  146. let content = "",
  147. float =
  148. '<a style="float:right;" data="${task.id}" data-v-303bbf52="" data-v-3fb75f36="" href="javascript:void 0" class="problem-helper-train-remove color-default">删除</a>';
  149. if (id == configs.local)
  150. (float = ""), (local_problems = task.problems.map((u) => u.problem.pid));
  151. for (let i in task.problems) content += getList(i, id == configs.local);
  152. return renderList(task.title, content, float);
  153. };
  154. let saveTrain = async (problems) => {
  155. return new Promise((r) => {
  156. $.ajax({
  157. type: "POST",
  158. url: `https://www.luogu.com.cn/api/training/editProblems/${configs.local}`,
  159. beforeSend: function (request) {
  160. request.setRequestHeader(
  161. "x-csrf-token",
  162. $("meta[name='csrf-token']")[0].content
  163. );
  164. },
  165. contentType: "application/json;charset=UTF-8",
  166. data: JSON.stringify({ pids: problems }),
  167. success: () => r(),
  168. });
  169. });
  170. };
  171. let saveConfig = async (config) => {
  172. return new Promise((r) => {
  173. $.ajax({
  174. type: "POST",
  175. url: `https://www.luogu.com.cn/paste/new`,
  176. beforeSend: function (request) {
  177. request.setRequestHeader(
  178. "x-csrf-token",
  179. $("meta[name='csrf-token']")[0].content
  180. );
  181. },
  182. contentType: "application/json;charset=UTF-8",
  183. data: JSON.stringify({
  184. public: false,
  185. data: "#lgtsk" + JSON.stringify(config),
  186. }),
  187. success: () => r(),
  188. });
  189. });
  190. };
  191. let loadConfig = () => {
  192. return new Promise((r) => {
  193. $.get("https://www.luogu.com.cn/paste?_contentOnly").then((u) => {
  194. u = u.currentData.pastes.result;
  195. let nc = null;
  196. for (let i in u) {
  197. try {
  198. if (u[i].data.substr(0, 6) !== "#lgtsk") continue;
  199. let k = u[i].data;
  200. nc = JSON.parse(k.substr(6, k.lentgh));
  201. break;
  202. } catch (e) {}
  203. }
  204. if (!nc) return r(0);
  205. configs.train = nc.train;
  206. configs.local = nc.local;
  207. configs.hideac = nc.hideac;
  208. r(1);
  209. });
  210. });
  211. };
  212. let getScore = async (sett) => {
  213. if (sett.method == "train")
  214. return {
  215. uid: sett.task.userScore.user.uid,
  216. scr: sett.task.userScore.score[sett.id],
  217. fscr: sett.task.problems[sett.id].problem.fullScore,
  218. };
  219. else if (sett.method == "local")
  220. return new Promise((res, rej) => {
  221. $.get(`https://www.luogu.com.cn/problem/${sett.id}?_contentOnly`).then(
  222. (u) => {
  223. res({
  224. uid: u.currentUser.uid,
  225. scr: u.currentData.problem.score,
  226. fscr: u.currentData.problem.fullScore,
  227. });
  228. }
  229. );
  230. });
  231. };
  232. // let loadLocalProblem = async () => {
  233. // let local = GM_getValue("problem-helper-local-list");
  234. // let getList = async (id, opt = 1) => {
  235. // let h = "";
  236. // if (opt) {
  237. // let info = await getScore({ method: "local", id: id });
  238. // h = geticon(info.uid, id, info.scr, info.fscr);
  239. // }
  240. // return `
  241. // <div>
  242. // <div>
  243. // ${h}
  244. // <span data-v-3a151854="">
  245. // <a
  246. // data-v-303bbf52=""
  247. // data-v-3fb75f36=""
  248. // href="javascript:void 0"
  249. // class="color-default"
  250. // style="text-decoration: none;"
  251. // >
  252. // <span
  253. // data-v-3fb75f36=""
  254. // style="float: right;font-weight: light;"
  255. // data="${id}"
  256. // class="problem-helper-delete-from-list"
  257. // >
  258. // 删除
  259. // </span>
  260. // </a>
  261. // </span>
  262. // <a
  263. // class="colored problem-helper-text
  264. // style="padding-left: 3px"
  265. // href="/problemnew/show/${id}"
  266. // target="_blank"
  267. // >
  268. // <b>${id}</b> ${local[id]}
  269. // </a>
  270. // </div>
  271. // </div>`;
  272. // };
  273. // let content = "";
  274. // for (let i in local) content += await getList(i);
  275. // return renderList("本地列表", content, "");
  276. // };
  277. function renderItem(title, id) {
  278. return `
  279. <div>
  280. <div>
  281. <span data-v-3a151854="">
  282. <a
  283. data-v-303bbf52=""
  284. data-v-3fb75f36=""
  285. href="/record/list?pid=${id}&amp;user=${task.userScore.user.uid}"
  286. class="color-default"
  287. style="text-decoration: none;"
  288. >
  289. ${geticon(
  290. id,
  291. task.userScore.user.uid,
  292. task.userScore.score[id],
  293. task.problems[x].problem.fullScore,
  294. task.userScore.status[id]
  295. )}
  296. </a>
  297. </span>
  298. <a
  299. class="colored problem-helper-text
  300. style="padding-left: 3px"
  301. href="/problemnew/show/${id}"
  302. target="_blank"
  303. >
  304. <b>${id}</b> ${task.problems[x].problem.title}
  305. </a>
  306. </div>
  307. </div>
  308. `;
  309. }
  310. async function loaderProblemEntry() {
  311. let lists = "";
  312. let urls = configs.train;
  313. // console.log(urls);
  314. if (configs.local && !urls[configs.local]) urls[configs.local] = "本地列表";
  315. for (let i in urls) lists += await loadProblemList(i);
  316. lists += renderList(
  317. "设置",
  318. `<div data-v-59a1d633="" data-v-83961efe="" class="row">
  319. <div data-v-72d91c56="" data-v-59a1d633="" class="checkbox" data-v-83961efe=""><input id="problem-helper-hide-aced" type="checkbox" value="65560" ${
  320. configs.hideac ? 'checked=""' : ""
  321. }"> <lable>
  322. 隐藏已通过题目
  323. </label> </div>
  324. <div>
  325. <label>本地题单</label>
  326. <input data-v-a7f7c968="" type="text" placeholder="题单id" class="lfe-form-sz-middle" style="width: 30%;" value="${
  327. configs.local || ""
  328. }" id="problem-helper-set-local-list">
  329. </div>
  330. <div>
  331. <a id="problem-helper-save">保存到洛谷云剪贴板</a>
  332. </div>
  333. <div>
  334. <a id="problem-helper-load">从洛谷云剪贴板加载</a>
  335. </div>
  336. <div>
  337. <label>批量导入</label>
  338. <input data-v-a7f7c968="" type="text" class="lfe-form-sz-middle" style="width: 30%;" id="problem-helper-import">
  339. </div>
  340. </div>`,
  341. ""
  342. );
  343. $("#problem-helper-entry").html(lists);
  344. $(".problem-helper-fold-on").click((u) => {
  345. u = $(u.target);
  346. u.parent().prev(".problem-helper-inner").removeAttr("style");
  347. u.attr("style", "display:none;");
  348. u.prev(".problem-helper-fold-off").removeAttr("style");
  349. });
  350. $(".problem-helper-fold-off").click((u) => {
  351. u = $(u.target);
  352. u.parent().prev(".problem-helper-inner").attr("style", "display:none;");
  353. u.attr("style", "display:none;");
  354. u.next(".problem-helper-fold-on").removeAttr("style");
  355. });
  356. $("#problem-helper-hide-aced").click((u) => {
  357. u = $(u.target);
  358. configs.hideac = u[0].checked;
  359. unsafeWindow._feInstance.$swalToastSuccess("修改成功");
  360. loaderProblemEntry();
  361. });
  362. $("#problem-helper-save").click((u) => {
  363. saveConfig(configs);
  364. unsafeWindow._feInstance.$swalToastSuccess("保存成功");
  365. loaderProblemEntry();
  366. });
  367. $("#problem-helper-load").click(async (u) => {
  368. if (await loadConfig())
  369. unsafeWindow._feInstance.$swalToastSuccess("加载成功");
  370. else unsafeWindow._feInstance.$swalToastError("加载失败");
  371. loaderProblemEntry();
  372. });
  373. $("#problem-helper-set-local-list").keydown(function (e) {
  374. if (e.keyCode == 13) {
  375. configs.local = $("#problem-helper-set-local-list").val();
  376. unsafeWindow._feInstance.$swalToastSuccess("修改成功");
  377. loaderProblemEntry();
  378. }
  379. });
  380. $("#problem-helper-import").keydown(function (e) {
  381. if (e.keyCode == 13) {
  382. let u = $("#problem-helper-import").val().trim().split(",");
  383. let t = local_problems;
  384. for (let i in u) if (t.indexOf(u[i]) == -1) t.push(u[i]);
  385. saveTrain(t);
  386. unsafeWindow._feInstance.$swalToastSuccess("导入成功");
  387. loaderProblemEntry();
  388. }
  389. });
  390. $("#problem-helper-add-to-list").click((u) => {
  391. let r = unsafeWindow.location.href.split("/");
  392. r = r[r.length - 1];
  393. while (r[r.length - 1] == "#") r = r.slice(0, r.length - 1);
  394. if (!unsafeWindow._feInjection.currentData.problem.title) return;
  395. if (local_problems.indexOf(r) == -1) local_problems.push(r);
  396. saveTrain(local_problems);
  397. unsafeWindow._feInstance.$swalToastSuccess("添加成功");
  398. loaderProblemEntry();
  399. });
  400. $(".problem-helper-delete-from-list").click((u) => {
  401. u = $(u.target).parents(".problem-helper-delete-from-list");
  402. let r = u.attr("data");
  403. let now = local_problems;
  404. let newone = [];
  405. for (let i in now) if (now[i] != r) newone.push(now[i]);
  406. saveTrain(newone);
  407. unsafeWindow._feInstance.$swalToastSuccess("删除成功");
  408. loaderProblemEntry();
  409. });
  410. $(".problem-helper-train-remove").click((u) => {
  411. u = $(u.target);
  412. let r = u.attr("data");
  413. let now = configs.train;
  414. let newone = {};
  415. for (let i in now) if (i != r) newone[i] = now[i];
  416. configs.train = now;
  417. unsafeWindow._feInstance.$swalToastSuccess("删除成功");
  418. loaderProblemEntry();
  419. });
  420. }
  421. let deferredInjectProblemPage = () => {
  422. $("#problem-helper-container").remove();
  423. $(".side").prepend(
  424. renderList(
  425. "做题助手",
  426. '<div id="problem-helper-entry"></div>',
  427. '<a style="float:right;" data-v-303bbf52="" data-v-3fb75f36="" href="javascript:void 0" id="problem-helper-add-to-list" class="color-default"><svg data-v-b35188f4="" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="plus-square" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="svg-inline--fa fa-plus-square fa-w-14"><path data-v-b35188f4="" fill="currentColor" d="M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-32 252c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92H92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z" class=""></path></svg>添加至列表</a >'
  428. )
  429. );
  430. loaderProblemEntry();
  431. };
  432. let loadTrainList = (id) => {
  433. let local = configs.train;
  434. let getList = (id) => {
  435. return `
  436. <div>
  437. <div>
  438. <span data-v-3a151854="">
  439. <a
  440. style="text-decoration: none;float: right;font-weight: light;"
  441. data="${id}"
  442. class="color-default problem-helper-delete-from-list"
  443. data-v-303bbf52=""
  444. data-v-3fb75f36=""
  445. href="javascript:void 0"
  446. >
  447. <svg data-v-4121e124="" aria-hidden="true" focusable="false" data-prefix="fal" data-icon="times" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" class="svg-inline--fa fa-times fa-w-10"><path data-v-4121e124="" fill="currentColor" d="M193.94 256L296.5 153.44l21.15-21.15c3.12-3.12 3.12-8.19 0-11.31l-22.63-22.63c-3.12-3.12-8.19-3.12-11.31 0L160 222.06 36.29 98.34c-3.12-3.12-8.19-3.12-11.31 0L2.34 120.97c-3.12 3.12-3.12 8.19 0 11.31L126.06 256 2.34 379.71c-3.12 3.12-3.12 8.19 0 11.31l22.63 22.63c3.12 3.12 8.19 3.12 11.31 0L160 289.94 262.56 392.5l21.15 21.15c3.12 3.12 8.19 3.12 11.31 0l22.63-22.63c3.12-3.12 3.12-8.19 0-11.31L193.94 256z" class=""></path></svg>
  448. </a>
  449. </span>
  450. <a
  451. class="colored problem-helper-text"
  452. style="padding-left: 3px"
  453. href="https://www.luogu.com.cn/training/${id}#information"
  454. target="_blank"
  455. >
  456. <b>${id}</b> ${local[id]}
  457. </a>
  458. </div>
  459. </div>`;
  460. };
  461. let lists = "";
  462. for (let i in local) lists += getList(i);
  463. return lists;
  464. };
  465. let loaderTrainEntry = async () => {
  466. let lists = loadTrainList();
  467. $("#problem-helper-entry").html(lists);
  468. $(".problem-helper-fold-on").click((u) => {
  469. u = $(u.target);
  470. u.parent().prev(".problem-helper-inner").removeAttr("style");
  471. u.attr("style", "display:none;");
  472. u.prev(".problem-helper-fold-off").removeAttr("style");
  473. });
  474. $(".problem-helper-fold-off").click((u) => {
  475. u = $(u.target);
  476. u.parent().prev(".problem-helper-inner").attr("style", "display:none;");
  477. u.attr("style", "display:none;");
  478. u.next(".problem-helper-fold-on").removeAttr("style");
  479. });
  480. $("#problem-helper-add-to-list").click((u) => {
  481. let r = unsafeWindow.location.href.split("/");
  482. r = r[r.length - 1].split("#")[0];
  483. if (!unsafeWindow._feInjection.currentData.training.title) return;
  484. let now = configs.train;
  485. if (!now) now = {};
  486. now[r] = unsafeWindow._feInjection.currentData.training.title;
  487. configs.train = now;
  488. unsafeWindow._feInstance.$swalToastSuccess("添加成功");
  489. loaderTrainEntry();
  490. });
  491. $(".problem-helper-delete-from-list").click((u) => {
  492. u = $(u.target).parents(".problem-helper-delete-from-list");
  493. let r = u.attr("data");
  494. let now = configs.train;
  495. let newone = {};
  496. for (let i in now) if (i != r) newone[i] = now[i];
  497. configs.train = newone;
  498. unsafeWindow._feInstance.$swalToastSuccess("删除成功");
  499. loaderProblemEntry();
  500. });
  501. };
  502. let deferredInjectTrainPage = () => {
  503. $("#problem-helper-container").remove();
  504. $(".side").prepend(
  505. renderList(
  506. "做题助手",
  507. '<div id="problem-helper-entry"></div>',
  508. '<a style="float:right;" data-v-303bbf52="" data-v-3fb75f36="" href="javascript:void 0" id="problem-helper-add-to-list" class="color-default"><svg data-v-b35188f4="" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="plus-square" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="svg-inline--fa fa-plus-square fa-w-14"><path data-v-b35188f4="" fill="currentColor" d="M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-32 252c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92H92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z" class=""></path></svg>添加至列表</a>'
  509. )
  510. );
  511. loaderTrainEntry();
  512. };
  513. let deferredInjectProblemlist = async () => {
  514. local_problems = (await getTask(configs.local)).problems.map(
  515. (u) => u.problem.pid
  516. );
  517. $(".problem-helper-inlist-adder").remove();
  518. let pid = "",
  519. name = "";
  520. let h = (pid, name) => `
  521. <a style="float:right; padding-right: 2em;" data="${pid}" data-v-303bbf52="" data-v-3fb75f36="" href="javascript:void 0" class="problem-helper-inlist-adder color-default"><svg data-v-b35188f4="" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="plus-square" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="svg-inline--fa fa-plus-square fa-w-14"><path data-v-b35188f4="" fill="currentColor" d="M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-32 252c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92H92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z" class=""></path></svg>
  522. 添加
  523. </a>`;
  524. let rows = $(".row");
  525. let trim = (s) => {
  526. return s.replace(/(^\s*)|(\s*$)/g, "");
  527. };
  528. rows.each((u) => {
  529. u = $(rows[u]);
  530. pid = u.children(".pid").text();
  531. name = u.children(".title").children(".title").text();
  532. name = trim(name);
  533. u.children(".title").prepend(h(pid, name));
  534. });
  535. $(".problem-helper-inlist-adder").click((u) => {
  536. u = $(u.target);
  537. let r = u.attr("data");
  538. let now = local_problems;
  539. if (now.indexOf(r) == -1) now.push(r);
  540. saveTrain(now);
  541. unsafeWindow._feInstance.$swalToastSuccess("添加成功");
  542. });
  543. };
  544.  
  545. /* main controller */
  546. function inject() {
  547. if (unsafeWindow.location.href.includes("problem/list"))
  548. deferredInjectProblemlist();
  549. else if (unsafeWindow.location.href.includes("training"))
  550. deferredInjectTrainPage(), deferredInjectProblemlist();
  551. else if (unsafeWindow.location.href.includes("problem"))
  552. deferredInjectProblemPage();
  553. }
  554. window.addEventListener("pushState", function (e) {
  555. setTimeout(inject, inject_lantency);
  556. });
  557. window.addEventListener("replaceState", function (e) {
  558. setTimeout(inject, inject_lantency);
  559. });
  560. setTimeout(inject, 100);
  561. $(document.body).append(
  562. `<style>
  563. .problem-helper-text{
  564. -webkit-line-clamp: 1; overflow: hidden; display: -webkit-box;
  565. -webkit-box-orient: vertical; white-space: normal;
  566. }
  567. .expand-tip > span[data-v-e4b7c2ca] {
  568. -webkit-user-select: none;
  569. -moz-user-select: none;
  570. -ms-user-select: none;
  571. cuser-select: none;
  572. cursor: pointer;
  573. color: rgba(0, 0, 0, .3);
  574. }
  575. .expand-tip[data-v-e4b7c2ca] {
  576. text-align: center;
  577. }
  578. .expand-tip > span[data-v-e4b7c2ca]:hover {
  579. color: inherit;
  580. }
  581. </style>`
  582. );
  583. };