studentportalen-extended

Add missing functionality to studenportalen.liu.se

当前为 2015-10-28 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name studentportalen-extended
  3. // @namespace http://ventureinto.space
  4. // @version 0.7
  5. // @user-agent Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:22.0) Gecko/20130328 Firefox/22.0
  6. // @description Add missing functionality to studenportalen.liu.se
  7. // @author Nils Eriksson niler851@student.liu.se
  8. // @match https://www3.student.liu.se/portal/studieresultat/resultat*
  9. // @grant GM_getResourceText
  10. // @grant GM_addStyle
  11. // @grant GM_xmlhttpRequest
  12. // @require http://code.jquery.com/jquery-2.1.4.min.js
  13. // @require https://cdn.firebase.com/js/client/2.3.1/firebase.js
  14. // @resource bootcss https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css
  15. // ==/UserScript==
  16.  
  17. /* set up FireBASE */
  18.  
  19. var myFirebaseRef = new Firebase("https://studentportalen-data.firebaseio.com/");
  20.  
  21. var getAllCourseData = function(){
  22. var fireCourses = myFirebaseRef.child("courses");
  23. fireCourses.on("value", function(snapshot) {
  24. var courses = snapshot.val();
  25. $('.course-row').each(function(i, row){
  26. var rowID = $(row).attr('id').replace('*','');
  27. if(rowID in courses){
  28. var level = courses[rowID].level
  29. var select = $(row).find('select');
  30. selectAlternative(level, select);
  31. // $(row).find('.'+level).attr('selected',true);
  32.  
  33. }
  34. });
  35.  
  36.  
  37. }, function (errorObject) {
  38. console.log("The read failed: " + errorObject.code);
  39. });
  40. }();
  41.  
  42.  
  43. var updateCourseLevel = function(course ,level){
  44. var fireCourses = myFirebaseRef.child("courses");
  45. fireCourses.child(course).set({ "level": level});
  46. }
  47.  
  48. /* END OF FIREBASE */
  49.  
  50.  
  51.  
  52. $("head").prepend('<meta charset="utf-8">');
  53.  
  54. console.debug('start: add CSS');
  55. var bootcss = GM_getResourceText('bootcss');
  56. GM_addStyle(bootcss);
  57. console.debug('done: add CSS');
  58.  
  59.  
  60. var studiehandbokenBase = "http://kdb-5.liu.se/liu/lith/studiehandboken/svkursplan.lasso?&k_budget_year=2015&k_kurskod="
  61.  
  62.  
  63. //// VIEW ////
  64. /*
  65. Create area for grade info
  66. */
  67. $("form").append("<div id='info-container' class='container'><div id='snitt' class='col-md-6'><h1>Snitt</h1></div></div>");
  68. $("#snitt").append("<h3 style='margin:0;'>Viktat: <span id='weighted-average-grade'></span></h3>");
  69. $("#snitt").append("<h3 style='margin:1px;'>Oviktat: <span id='average-grade'></span></h3>");
  70. $("#snitt").append("<p>Alla <input id='select-all' type='checkbox'></p>");
  71. $("#snitt").append("<p>Avklarade <input id='select-all-done' type='checkbox'></p>");
  72.  
  73. $("#snitt").append("<p><button id='calculate-btn' type='button'>Beräkna</button></p>");
  74.  
  75. $("#info-container").append("<div id='course-level' class='col-md-6'></div>");
  76. $("#course-level").append("<h1>Statestik</h1>");
  77. $("#course-level").append("<h3>Avancerade hp: <span id='sum-advanced-points'></span></h3>");
  78.  
  79.  
  80.  
  81.  
  82. /*
  83. Give the table of courses a id
  84. */
  85. $("table.resultlist > tbody").attr('id','grade-table');
  86.  
  87.  
  88. //var createLevelBox = function(selectedLevel){
  89.  
  90.  
  91. var levelBox ='\
  92. <td>\
  93. <select class="course-levels">\
  94. <option class="G1" value="G1">G1</option>\
  95. <option class="G2" value="G2">G2</option>\
  96. <option class="A" value="A">A</option>\
  97. <option class="empty" value="empty" selected></option>\
  98. </select>\
  99. </td>';
  100.  
  101.  
  102.  
  103. /**
  104. MODIFY THE TABLE OF GRADES
  105. -Add new header "Selected"
  106. -Add checkbox for all courses
  107. -Add plus minus sign next to grades to se the impact
  108. of rasing them
  109. **/
  110. (function expandTableOfGrades(){
  111. $("#grade-table").children().each(function(){
  112.  
  113. var row = rowType(this);
  114. if( row.numericGrade || row.letterGrade){
  115. if(row.numericGrade){
  116. $(this).prepend("<td><input type='checkbox' class='course-checkbox'></td>");
  117. $(this).children().eq(4).attr('nowrap','nowrap');
  118. $(this).children().eq(4).wrapInner("<span class='grade' style='padding-right: 6px; display:inline-block; width:4px;'></span>");
  119. $(this).children().eq(4).append(" <input type='button' value='+' class='plus' /><input type='button' value='-' class='minus' />");
  120. }
  121. if(row.letterGrade){
  122. $(this).prepend("<td></td>");
  123. }
  124. $(this).children().eq(3).addClass("hp");
  125. $(this).children().eq(1).addClass("course-code");
  126. //is course finished ?
  127. if($(this).children().eq(1).text().indexOf("*") > 0){ $(this).children().eq(1).addClass("is-finished");}
  128. //
  129. $(this).children().eq(1).wrapInner("<a href='"+studiehandbokenBase+$(this).children().eq(1).text()+"'></a>");
  130. $(this).addClass('course-row');
  131. $(this).attr('id',$(this).children().eq(1).text());
  132. $(this).append(levelBox);
  133. }
  134. if($(this).children().eq(0).text() == "Kurskod"){
  135. $(this).prepend("<th>Vald</th>");
  136. //HP padding
  137. $(this).children().eq(3).attr('style','padding-right:23px');
  138. $(this).append("<th>Nivå</th>");
  139. }
  140. });
  141. })();
  142.  
  143. function rowType( row ){
  144. var header = $(row).children().eq(0).is("th");
  145. var numberOfEntrys = $(row).children().size();
  146. var hasNumbericGrade = !isNaN(Number($(row).children().eq(3).text()));
  147.  
  148. var numericGrade = false;
  149. var letterGrade = false;
  150. var notAcourse = false;
  151.  
  152. if( !header && numberOfEntrys >2 && hasNumbericGrade ){
  153. numericGrade = true;
  154. }
  155. else if( !header && numberOfEntrys >2 && !hasNumbericGrade){
  156. letterGrade =true;
  157. }
  158. else{
  159. notACourse = true;
  160. }
  161.  
  162. return {
  163. numericGrade:numericGrade,
  164. letterGrade:letterGrade,
  165. notACourse:notACourse
  166. }
  167. }
  168.  
  169. /*
  170. when we click select all,
  171. all checkboxes shoul be selected.
  172. */
  173. $("#select-all").click(function(event){
  174. event.stopPropagation();
  175. if(this.checked){
  176. $('.course-checkbox').each(function(){
  177. this.checked = true;
  178. $(this).closest("tr").addClass('selected');
  179. });
  180. }
  181. else{
  182. $('.course-checkbox').each(function(){
  183. this.checked = false;
  184. $(this).closest("tr").removeClass('selected');
  185. });
  186. }
  187.  
  188. });
  189. $("#select-all-done").click(function(event){
  190. event.stopPropagation();
  191.  
  192. if(this.checked){
  193. $('.course-checkbox').each(function(){
  194. var row = $(this).closest("tr");
  195. if(row.find('.is-finished').length != 0){
  196. this.checked = true;
  197. row.addClass('selected');
  198. }
  199.  
  200. });
  201. }
  202. else{
  203. $('.course-checkbox').each(function(){
  204. this.checked = false;
  205. $(this).closest("tr").removeClass('selected');
  206. });
  207. }
  208.  
  209. });
  210.  
  211. /*
  212. pression a row should make it checked and highlighted
  213. */
  214.  
  215.  
  216. $( '#grade-table' ).delegate( 'tr', 'click', function ( e ) {
  217. if ( $( e.target ).is( 'input:checkbox' ) ) {
  218. this.checked = !this.checked;
  219. $(this).toggleClass('selected');
  220. }else if($( e.target ).parent().is( "a")){
  221. e.stopPropagation();
  222. }
  223. else {
  224. $(this).find("input[type='checkbox']").click();
  225.  
  226. }
  227. });
  228.  
  229.  
  230.  
  231. /**
  232. When we click the button "Calculate"
  233. we first call calculateAverages();
  234. then put the numbers in the view for the user to se
  235. **/
  236. $("#calculate-btn").click(function(event){
  237. var levelPoints = sumPointsInLevels();
  238. var grades = calculateAverages();
  239. $('#sum-advanced-points').text(levelPoints.A);
  240. $('#average-grade').text(grades.average.toFixed(2));
  241. $('#weighted-average-grade').text(grades.WeightedAverage.toFixed(2));
  242. });
  243.  
  244. /*
  245. Add hover highlighting for course-rows
  246.  
  247. */
  248. document.styleSheets[0].insertRule('.course-row:hover { background-color: #FF9; outline: thin solid black;}', 0);
  249. document.styleSheets[0].insertRule('.selected { background-color: #FFC; outline: thin solid black;}', 0);
  250.  
  251.  
  252.  
  253.  
  254.  
  255. /// Controllers /////
  256.  
  257.  
  258. /*
  259. This function calculated the average and weighted average
  260. of selected fields.
  261. */
  262.  
  263. function calculateAverages(){
  264.  
  265. var selectedRows = $(".course-checkbox:checked").parent().parent();
  266.  
  267.  
  268. var avrage = (function(){
  269. var gradesWithoutNumbers = 0;
  270. var sum = 0;
  271. selectedRows.each(function(){
  272. var grade = Number($(this).children().eq(4).text());
  273. if( !isNaN(grade)){
  274. sum += grade;
  275. }else{
  276. gradesWithoutNumbers++;
  277. }
  278. });
  279.  
  280. var coursesWithRegularGrades = selectedRows.size() - gradesWithoutNumbers;
  281. var avrage = sum/coursesWithRegularGrades;
  282.  
  283. return avrage;
  284. })();
  285.  
  286. var WeightedAverage = (function(){
  287. var pointsSum = 0;
  288. var pointsTimesGradeSum =0;
  289. selectedRows.each(function(){
  290. var grade = Number($(this).children().eq(4).text());
  291. var points = Number($(this).children().eq(3).text());
  292. if( !isNaN(grade)){
  293. pointsSum += points;
  294. pointsTimesGradeSum += points*grade;
  295. }
  296. });
  297. return pointsTimesGradeSum/pointsSum;
  298. })();
  299.  
  300.  
  301. return {
  302. WeightedAverage: WeightedAverage,
  303. average: avrage
  304. }
  305. }
  306.  
  307.  
  308. (function plusMinus(){
  309.  
  310. $('.plus').click(function(e){
  311. e.stopPropagation();
  312. var gradeElement =$(this).prev(".grade");
  313. var grade = Number(gradeElement.text());
  314. // If is not undefined
  315. if (!isNaN(grade)) {
  316. // Increment
  317. $(gradeElement).text(boundValue(grade+1));
  318. } else {
  319. // Otherwise put a 0 there
  320. $(gradeElement).text(0);
  321. }
  322. });
  323.  
  324. $('.minus').click(function(e){
  325. e.stopPropagation();
  326. var gradeElement = $(this).prevAll(".grade");
  327. var grade = Number(gradeElement.text());
  328. // If is not undefined
  329. if (!isNaN(grade)) {
  330. // Increment
  331. $(gradeElement).text(boundValue(grade-1));
  332. } else {
  333. // Otherwise put a 0 there
  334. $(gradeElement).text(0);
  335. }
  336. });
  337.  
  338. var boundValue = function(value){
  339. if(value > 5)return 5;
  340. if(value < 3)return 3;
  341. return value;
  342. }
  343.  
  344. })();
  345.  
  346. (function selectLevel(){
  347. $('select').click(function(e){
  348. e.preventDefault();
  349. e.stopPropagation();
  350. });
  351. })();
  352.  
  353. (function onCourseSelected(){
  354. $('select').on('change', function(e) {
  355. var level = $(this).val();
  356. var select = $(this).closest('select');
  357. selectAlternative(level, select);
  358.  
  359. var courseID = $(this).closest('tr').attr('id').replace('*','');
  360. updateCourseLevel(courseID,level);
  361. });
  362.  
  363. })();
  364.  
  365.  
  366. var sumPointsInLevels = function(){
  367.  
  368. var selectedRows = $(".course-checkbox:checked").parent().parent();
  369. function findAndSumLevel(level){
  370. var sum = 0;
  371. var selectedRows = $(".course-checkbox:checked").parent().parent();
  372. selectedRows.each(function(i,obj){
  373. if($(obj).find('.course-levels').val() === level)
  374. {
  375. var hp = Number($(obj).find('.hp').text());
  376. sum +=hp;
  377. }
  378. });
  379.  
  380. return sum;
  381. }
  382. var levelA = findAndSumLevel("A");
  383. var levelG1 = findAndSumLevel("G1");
  384. var levelG2 = findAndSumLevel("G2");
  385. var empty = findAndSumLevel("empty");
  386. return {
  387. G1: levelG1,
  388. G2: levelG2,
  389. A: levelA,
  390. empty:empty
  391. }
  392. };
  393.  
  394.  
  395.  
  396.  
  397. //Helper Functions
  398.  
  399. var selectAlternative = function(alt, select){
  400. select.children().removeAttr('selected');
  401. select.find('.'+alt).attr('selected',true);
  402. }
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.  
  421.  
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428.