PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/Gradebook/Scripts/app/class.result.list.js

https://bitbucket.org/crackbrain/gradebook
JavaScript | 310 lines | 248 code | 43 blank | 19 comment | 48 complexity | 82e91331ce7a7258e16ecefbd5ae2e7f MD5 | raw file
  1. /// <reference path="../zepto.min.js" />
  2. /// <reference path="../knockout-2.2.1.debug.js" />
  3. /// <reference path="../underscore-ko-1.2.2.js" />
  4. /// <reference path="../underscore.js" />
  5. /// <reference path="class.subject.js" />
  6. /// <reference path="task.js" />
  7. /// <reference path="task.type.js" />
  8. /// <reference path="main.js" />
  9. /// <reference path="url.helper.js" />
  10. /// <reference path="results.js" />
  11. /// <reference path="task.filter.js" />
  12. function ClassResultList() {
  13. var self = this;
  14. // Data
  15. self.items = ko.observableArray();
  16. self.taskTypes = ko.observableArray(TaskType.defaultValues);
  17. self.students = ko.observableArray();
  18. self.chosenInterval = ko.observable(TaskFilter.overallItem);
  19. self.chosenTaskType = ko.observable(TaskType.all);
  20. self.chosenIntervalType = ko.computed(function () {
  21. return self.chosenInterval().type;
  22. });
  23. self.classes = ko.observableArray();
  24. self.classSubject = ko.observable();
  25. self.classIndex = function () {
  26. return self.classes.indexOf(self.classSubject);
  27. };
  28. // Display
  29. self.showPercents = ko.observable(false);
  30. // Properties
  31. self.isEmpty = ko.computed(function () {
  32. var items = self.items();
  33. return _.isNull(items) || _.isEmpty(items);
  34. });
  35. self.hasNext = ko.computed(function () {
  36. return self.classIndex() + 1 < self.classes().length;
  37. });
  38. self.hasPrev = ko.computed(function () {
  39. return self.classIndex() - 1 >= 0;
  40. });
  41. self.columns = ko.computed(function () {
  42. if (self.isEmpty()) return [];
  43. return self.items()[0].results();
  44. });
  45. self.hasTasks = ko.computed(function () {
  46. return !self.isEmpty() && self.columns().length > 0;
  47. });
  48. // Computed data
  49. self.averageRate = ko.computed(function () {
  50. var items = self.items();
  51. if (self.isEmpty()) return null;
  52. var count = 0;
  53. var sum = _.reduce(items, function (memo, item) {
  54. var rate = item.rate();
  55. if (rate) {
  56. count++;
  57. return memo + rate;
  58. }
  59. return memo;
  60. }, 0);
  61. return count > 0 ? Math.round(sum * 100 / count) / 100 : null;
  62. });
  63. // Load/save data
  64. self.load = function () {
  65. var classSubject = self.classSubject();
  66. if (classSubject == null) {
  67. self.items.removeAll();
  68. return;
  69. }
  70. var url = UrlHelper.getUrl("students", {
  71. code: classSubject.id
  72. });
  73. $.getJSON(url, function (data) {
  74. var mappedData = $.map(data, function (item) {
  75. return new Student(item);
  76. });
  77. self.students(mappedData);
  78. });
  79. url = UrlHelper.getUrl("results", {
  80. code: classSubject.id
  81. });
  82. $.getJSON(url, function (data) {
  83. var items = _.map(self.students(), function(student) {
  84. return new StudentResult(data, student);
  85. });
  86. self.items(items);
  87. self.updateFilters();
  88. });
  89. };
  90. self.save = function () {
  91. $.ajax({
  92. type: 'POST',
  93. url: 'api/grades/list',
  94. contentType: 'application/json',
  95. data: JSON.stringify(self.getGrades())
  96. });
  97. };
  98. self.preload = function () {
  99. var classSubject = self.classSubject();
  100. if (classSubject == null) return;
  101. var url = UrlHelper.getUrl("taskTypes", {
  102. code: classSubject.id
  103. });
  104. $.getJSON(url, function (data) {
  105. var mappedData = $.map(data, function (item) {
  106. return new TaskType(item);
  107. });
  108. self.updateTypeFilter(mappedData);
  109. });
  110. $.getJSON(UrlHelper.resources.classSubjects, function (data) {
  111. var mappedData = $.map(data, function (item) {
  112. return new ClassSubject(item);
  113. });
  114. self.classes(mappedData);
  115. });
  116. };
  117. // Behaviours
  118. self.next = function () {
  119. if (!hasNext) return;
  120. var index = self.classIndex() + 1;
  121. self.goToClass(index);
  122. };
  123. self.prev = function () {
  124. if (!hasPrev) return;
  125. var index = self.classIndex() - 1;
  126. self.goToClass(index);
  127. };
  128. self.goToClass = function (index) {
  129. var item = self.classes()[index];
  130. self.classSubject(item);
  131. };
  132. // Subscriptions
  133. self.classSubject.subscribe(function () {
  134. self.preload();
  135. self.load();
  136. });
  137. self.chosenInterval.subscribe(function (value) {
  138. if (value.type != TaskFilter.options.term) {
  139. self.chosenTaskType(TaskType.assessments);
  140. }
  141. var items = self.items();
  142. if (items) {
  143. _.each(items, function (item) {
  144. item.intervalFilter(value);
  145. });
  146. }
  147. });
  148. self.chosenTaskType.subscribe(function (value) {
  149. var items = self.items();
  150. if (items) {
  151. _.each(items, function (item) {
  152. item.typeFilter(value);
  153. });
  154. }
  155. });
  156. // Functions
  157. self.getRank = function (classResult) {
  158. var items = self.items();
  159. if (_.isNull(items) || _.isEmpty(items) || classResult == undefined) return 0;
  160. var studentRate = classResult.rate();
  161. if (!studentRate) return 0;
  162. var rates = _.map(items, function (item) {
  163. return item.rate();
  164. });
  165. rates = _.sortBy(rates, function (num) { return -num; });
  166. return _.indexOf(rates, studentRate) + 1;
  167. };
  168. self.getAverageResult = function (id, type) {
  169. var items = self.items();
  170. if (self.isEmpty() || type == null || id == null) return null;
  171. var count = 0;
  172. var sum = _.reduce(items, function (memo, item) {
  173. var result = item.getByType(type, id);
  174. if (result) {
  175. var value = result.result();
  176. if (value) {
  177. count++;
  178. return memo + value;
  179. }
  180. }
  181. return memo;
  182. }, 0);
  183. return count > 0 ? Math.round(sum * 100 / count) / 100 : null;
  184. };
  185. self.getAverageRate = function (id, type) {
  186. var items = self.items();
  187. if (self.isEmpty() || type == null || id == null) return null;
  188. var count = 0;
  189. var sum = _.reduce(items, function (memo, item) {
  190. var result = item.getByType(type, id);
  191. if (result) {
  192. var rate = result.rate();
  193. if (rate) {
  194. count++;
  195. return memo + rate;
  196. }
  197. }
  198. return memo;
  199. }, 0);
  200. return count > 0 ? Math.round(sum * 100 / count) / 100 : null;
  201. };
  202. self.allDone = function (taskId) {
  203. var items = self.items();
  204. if (_.isNull(items) || _.isEmpty(items)) return false;
  205. return _.all(items, function (item) {
  206. var result = item.getByType("Task", taskId);
  207. if (result != null) {
  208. return result.result() > 0;
  209. }
  210. return false;
  211. });
  212. };
  213. self.getGrades = function () {
  214. if (self.isEmpty()) return null;
  215. return _.reduce(self.items(), function (memo, item) {
  216. return _.union(memo, item.getGrades());
  217. }, []);
  218. };
  219. self.updateFilters = function() {
  220. var items = self.items();
  221. var interval = self.chosenInterval();
  222. var type = self.chosenTaskType();
  223. if (items) {
  224. _.each(items, function (item) {
  225. item.intervalFilter(interval);
  226. item.typeFilter(type);
  227. });
  228. }
  229. };
  230. self.updateTypeFilter = function (data) {
  231. var selectedType = self.chosenTaskType();
  232. self.taskTypes.remove(function(item) {
  233. return _.all(data, function(type) {
  234. return item.id > 0 && type.id != item.id;
  235. })
  236. })
  237. var newTypes = _.filter(data, function(type) {
  238. return _.all(self.taskTypes(), function(item) {
  239. return item.id != type.id;
  240. })
  241. })
  242. ko.utils.arrayPushAll(self.taskTypes(), newTypes);
  243. self.taskTypes.valueHasMutated();
  244. var newSelectedType = _.find(self.taskTypes(), function(item) {
  245. return item.name == selectedType.name;
  246. });
  247. if (newSelectedType) {
  248. self.chosenTaskType(newSelectedType);
  249. }
  250. }
  251. self.sortDirection = true;
  252. self.sortItems = function (task) {
  253. if (self.isEmpty()) return;
  254. var ascSort = function (left, right) {
  255. return left == right ? 0 : (left < right ? -1 : 1);
  256. };
  257. var descSort = function (left, right) {
  258. return left == right ? 0 : (left > right ? -1 : 1);
  259. };
  260. self.items.sort(function (left, right) {
  261. var leftValue = left.getTaskResult(task);
  262. var rightValue = right.getTaskResult(task);
  263. return self.sortDirection ? ascSort(leftValue, rightValue) : descSort(leftValue, rightValue);
  264. });
  265. self.sortDirection = !self.sortDirection;
  266. };
  267. }