Greasy Fork镜像 支持简体中文。

Grid Smartschool

Calculate the point total of your grades in Smartschool. I got permissions from Ebbe to do this.

目前為 2023-12-04 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/481384/1290399/Grid%20Smartschool.js

  1. // @license This library may only be used by ChromeExtensions!!!
  2. // Grid
  3.  
  4. // License: https://raw.githubusercontent.com/EbbDrop/SmarterSmartchool/main/LICENSE
  5.  
  6. let wideToolbarCallback = function (mutationsList, _) {
  7. for (let mutation of mutationsList) {
  8. if (mutation.type == 'childList' && mutation.removedNodes.length != 0) {
  9. for (const node of mutation.removedNodes) {
  10. if (node.id == "show-grid2") {
  11. $(".wide-toolbar").append(node);
  12. }
  13. }
  14. }
  15. }
  16. };
  17.  
  18. let wideToolbarObserver = new MutationObserver(wideToolbarCallback);
  19.  
  20. let smscMainCallback = function (mutationsList, observer) {
  21. for (let mutation of mutationsList) {
  22. if (mutation.type == 'childList' && mutation.addedNodes.length == 1 && mutation.addedNodes[0].classList.contains('wide-toolbar')) {
  23. observer.disconnect();
  24. wideToolbarObserver.observe($('.wide-toolbar')[0], { attributes: false, childList: true, subtree: false });
  25. onLoad();
  26. addButton();
  27. }
  28. }
  29. };
  30.  
  31. let smscMainObserver = new MutationObserver(smscMainCallback);
  32. smscMainObserver.observe($('#smscMain')[0], { attributes: false, childList: true, subtree: false });
  33.  
  34. function totalToStr(total_numerator, total_denominator) {
  35. return (Math.round(total_numerator / total_denominator * 1000) / 10).toString() + '%';
  36. }
  37.  
  38. function addButton() {
  39. var host = window.location.host;
  40. console.log(host+"/static/img/icon_128.png")
  41. $(".wide-toolbar").append(
  42. $("<button/>")
  43. .attr("id", "show-grid2")
  44. .addClass("wide-toolbar__item")
  45. .append(
  46. $("<img/>")
  47. .addClass("wide-toolbar__item__icon")
  48. .attr("src", host + "/static/img/icon_128.png")
  49. )
  50. .append(
  51. $("<span/>").addClass("wide-toolbar__item__name").text("Grid")
  52. )
  53. .click(openGrid)
  54. );
  55. }
  56.  
  57.  
  58. function makeGrid() {
  59. let loading = $("<h3>Loading!</h3>");
  60. fetch('/results/api/v1/evaluations?itemsOnPage=500').then(r => r.json()).then(results => {
  61. let data = {};
  62. let course_to_graphic = {};
  63. let latest_period = null;
  64. for (const result of results) {
  65. if (result["type"] != "normal") {
  66. continue;
  67. }
  68. let period = result["period"]["name"];
  69. if (latest_period === null) {
  70. latest_period = period;
  71. }
  72. if (!(period in data)) {
  73. data[period] = {};
  74. }
  75.  
  76. period = data[period];
  77. for (const course of result["courses"]) {
  78. course_to_graphic[course["name"]] = course["graphic"];
  79. const course_name = course["name"];
  80. if (!(course_name in period)) {
  81. period[course_name] = [];
  82. }
  83. period[course_name].push({ "date": result["date"], "name": result["name"], "graphic": result["graphic"] });
  84. }
  85. }
  86.  
  87. for (let period_name of Object.keys(data)) {
  88. let period = data[period_name];
  89.  
  90. let grid = $("<div/>").attr("id", "period").append($("<h2/>").text(period_name + ":"));
  91. let table = $("<table/>").attr("id", "result-table");
  92.  
  93. let longest = 0;
  94. for (let [_, course] of Object.entries(period)) {
  95. course.sort((a, b) => { return a["date"].localeCompare(b["date"]); });
  96. if (course.length > longest) {
  97. longest = course.length;
  98. }
  99. }
  100. // Add row for disclamer
  101. let disc_row = $("<tr/>");
  102. for (let i = 0; i < longest + 1; i++) {
  103. disc_row.append($("<td/>").addClass("hidden-cell"));
  104. }
  105. disc_row.append($("<td/>").attr("id", "disclamer").text("!"));
  106. table.append(disc_row);
  107.  
  108. let overallTotalNumerator = 0;
  109. let overallTotalDenominator = 0;
  110.  
  111. for (let [course_name, course] of Object.entries(period)) {
  112. let row = $("<tr/>");
  113. if (course_to_graphic[course_name].type == "icon") {
  114. row.append($("<th/>").append(
  115. $("<span/>")
  116. .addClass("icon-label icon-label--24 smsc-svg--" + course_to_graphic[course_name]["value"] + "--24")
  117. .text(course_name)
  118. ));
  119. } else {
  120. row.append($("<th/>").text(course_name));
  121. }
  122.  
  123. let total_numerator = 0;
  124. let total_denominator = 0;
  125.  
  126. for (const result of course) {
  127. const desc = result["graphic"]["description"];
  128. const color = result["graphic"]["color"];
  129. const name = result["name"];
  130.  
  131. row.append($("<td/>").addClass("c-" + color + "-combo--100").attr({ id: "details", content: name }).text(desc));
  132.  
  133. let match = desc.match(/^([\d\,\.]+)\/([\d\,\.]+)$/);
  134. if (match) {
  135. total_numerator += parseFloat(match[1].replace(',', '.'));
  136. total_denominator += parseFloat(match[2].replace(',', '.'));
  137. }
  138. }
  139.  
  140. for (let i = 0; i < longest - course.length; i++) {
  141. row.append($("<td/>"));
  142. }
  143.  
  144. let last_cell = $("<td/>").addClass("total");
  145. if (total_denominator != 0) {
  146. last_cell.text(totalToStr(total_numerator, total_denominator));
  147. if (total_numerator / total_denominator < 0.5) {
  148. last_cell.addClass('is-low');
  149. }
  150. }
  151. row.append(last_cell);
  152.  
  153. overallTotalNumerator += total_numerator;
  154. overallTotalDenominator += total_denominator;
  155.  
  156. table.append(row);
  157. }
  158.  
  159. let overallTotalRow = $("<tr/>");
  160. overallTotalRow.append($("<th/>").text("Total"));
  161. for (let i = 0; i < longest; i++) {
  162. overallTotalRow.append($("<td/>"));
  163. }
  164. let overallTotalCell = $("<td/>").addClass("total");
  165. if (overallTotalDenominator != 0) {
  166. overallTotalCell.text(totalToStr(overallTotalNumerator, overallTotalDenominator));
  167. if (overallTotalNumerator / overallTotalDenominator < 0.5) {
  168. overallTotalCell.addClass('is-low');
  169. }
  170. }
  171. overallTotalRow.append(overallTotalCell);
  172. table.append(overallTotalRow);
  173.  
  174. grid.append($("<div/>").attr("id", "table-container").append(table));
  175. data[period_name] = grid;
  176. }
  177.  
  178. let modal = $("<div/>").attr("id", "content-container");
  179. let period_buttons = $("<div/>");
  180. let main_grid = $("<div/>").attr("id", "period-container");
  181. for (let [period_name, grid] of Object.entries(data).reverse()) {
  182. // We are using two lambda's sice otherwice they will all use the same scope.
  183. period_buttons.append($("<button/>").addClass("period_button").text(period_name).click(((grid) => {
  184. return () => {
  185. main_grid.empty();
  186. main_grid.append(grid);
  187. };
  188. })(grid)));
  189. }
  190. if (period_buttons.children().length > 1) {
  191. period_buttons.prepend($("<span/>").text("Select period: "));
  192. modal.append(period_buttons);
  193. }
  194.  
  195. if (latest_period !== null) {
  196. main_grid.append(data[latest_period]);
  197. }
  198. modal.append(main_grid);
  199. loading.replaceWith(modal);
  200. });
  201. return loading;
  202. }
  203.  
  204. function onLoad() {
  205. let style = document.createElement('style');
  206. style.innerHTML = `
  207.  
  208. #result-table #disclamer {
  209. border: none !important;
  210. color: red;
  211. font-weight: bold;
  212. position: relative;
  213. }
  214. #disclamer:hover::before {
  215. visibility: visible;
  216. opacity: 1;
  217. }
  218. #disclamer::before {
  219. z-index: 1;
  220. content: "Deze totalen kunnen afwijken van uw werkelijke resultaten doordat niet altijd alle gegevens gekend zijn.";
  221. position: absolute;
  222. left: -20rem;
  223. border: 3px solid red;
  224. padding: 0.2rem;
  225. border-radius: 3px;
  226. background-color: white;
  227. width: 20rem;
  228. visibility: hidden;
  229. opacity: 0;
  230. transition: visibility 0s, opacity 0.5s linear;
  231. }
  232. #details {
  233. position: relative;
  234. }
  235.  
  236. #details:hover::before {
  237. visibility: visible;
  238. opacity: 0.9;
  239. }
  240.  
  241. #details::before {
  242. z-index: 2;
  243. content: attr(content);
  244. color: white;
  245. background-color: #1a1a1a;
  246. visibility: hidden;
  247. position: absolute;
  248. text-align: center;
  249. padding: 0.313rem 0;
  250. border-radius: 0.375rem;
  251. opacity: 0;
  252. transition: opacity .6s;
  253. width: 15rem;
  254. top: 100%;
  255. left: 50%;
  256. margin-left: -7.5rem;
  257. }
  258.  
  259. #result-table .hidden-cell {
  260. border: none !important;
  261. }
  262.  
  263. .period_button {
  264. background-color: #ff520e;
  265. border-radius: 3px;
  266. border-style: none;
  267. color: #FFFFFF;
  268. margin-right: 0.5rem;
  269. padding: 0.4rem;
  270. text-align: center;
  271. transition: 100ms;
  272. }
  273.  
  274. .period_button:hover {
  275. background-color: #ef4200;
  276. }
  277.  
  278. .period_button:active {
  279. background-color: #ff6210;
  280. }
  281.  
  282. .total {
  283. font-weight: bold;
  284. }
  285.  
  286. .is-low {
  287. color: red !important;
  288. }
  289.  
  290. #table-container {
  291. flex: 1 1 auto;
  292. overflow: auto;
  293. }
  294.  
  295. #period {
  296. height: 100%;
  297. display: flex;
  298. flex-direction: column;
  299. }
  300.  
  301. #period-container {
  302. flex: 1;
  303. min-height: 0;
  304. }
  305.  
  306. #content-container {
  307. display: flex;
  308. flex-direction: column;
  309. height: 100%;
  310. width: 100%;
  311. }
  312.  
  313. #result-table {
  314. margin-top: 1rem;
  315. border: 0px;
  316. }
  317.  
  318. #result-table th {
  319. text-align: left;
  320. }
  321.  
  322. #result-table td {
  323. text-align: center;
  324. }
  325.  
  326. #result-table th, #result-table td {
  327. border: 1px solid gray !important;
  328. padding: 0.5rem;
  329. min-width: 5.5rem;
  330. }
  331. #modal-background {
  332. display: none;
  333. position: fixed;
  334. top: 0;
  335. left: 0;
  336. width: 100%;
  337. height: 100%;
  338. background-color: white;
  339. opacity: .50;
  340. -webkit-opacity: .5;
  341. -moz-opacity: .5;
  342. filter: alpha(opacity=50);
  343. z-index: 1000;
  344. }
  345.  
  346. #modal-content {
  347. background-color: white;
  348. border-radius: 10px;
  349. -webkit-border-radius: 10px;
  350. -moz-border-radius: 10px;
  351. box-shadow: 0 0 20px 0 #222;
  352. -webkit-box-shadow: 0 0 20px 0 #222;
  353. -moz-box-shadow: 0 0 20px 0 #222;
  354. display: none;
  355. padding: 10px;
  356. position: fixed;
  357. z-index: 1000;
  358. left: 10%;
  359. top: 10%;
  360. width: 80%;
  361. height: 80%;
  362. }
  363.  
  364. #modal-background.active, #modal-content.active {
  365. display: block;
  366. }
  367.  
  368. #modal-close {
  369. background-color: #ee0000;
  370. border-radius: 3px;
  371. border-style: none;
  372. color: #FFFFFF;
  373. padding: 0.4rem;
  374. text-align: center;
  375. transition: 100ms;
  376. position: absolute;
  377. right: 0.5rem;
  378. }
  379. #modal-close:hover {
  380. background-color: #dd0000;
  381. }
  382. #modal-close:active {
  383. background-color: #ff0000;
  384. }
  385. `;
  386. document.head.appendChild(style);
  387.  
  388. $("body").append(
  389. $("<div/>").attr("id", "modal-background")
  390. ).append(
  391. $("<div/>").attr("id", "modal-content").append(
  392. $("<button/>").attr("id", "modal-close").text("Close")
  393. ).append(makeGrid())
  394. );
  395.  
  396. $("#modal-background, #modal-close").click(function () {
  397. $("#modal-content, #modal-background").toggleClass("active");
  398. });
  399. }
  400.  
  401. function openGrid() {
  402. $("#modal-content, #modal-background").toggleClass("active");
  403. }

QingJ © 2025

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