Grid Smartschool

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

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

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

QingJ © 2025

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