exercises styling, script from upstream
[edumed.git] / catalogue / static / catalogue / js / edumed.js
1 // Generated by CoffeeScript 1.4.0
2 (function() {
3   var $, Binding, EduModule, Exercise, Luki, PrawdaFalsz, Przyporzadkuj, Uporzadkuj, Wybor, Zastap, exercise,
4     __hasProp = {}.hasOwnProperty,
5     __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
6
7   $ = jQuery;
8
9   Binding = (function() {
10
11     function Binding(handler, element) {
12       this.handler = handler;
13       this.element = element;
14       $(this.element).data(this.handler, this);
15     }
16
17     return Binding;
18
19   })();
20
21   EduModule = (function(_super) {
22
23     __extends(EduModule, _super);
24
25     function EduModule(element) {
26       EduModule.__super__.constructor.call(this, 'edumodule', element);
27     }
28
29     return EduModule;
30
31   })(Binding);
32
33   Exercise = (function(_super) {
34
35     __extends(Exercise, _super);
36
37     function Exercise(element) {
38       var _this = this;
39       Exercise.__super__.constructor.call(this, 'exercise', element);
40       $(this.element).data("exercise-html", $(this.element).html());
41       $(".check", this.element).click(function(ev) {
42         _this.check();
43         $(ev.target).next(".retry").show();
44         return $(ev.target).hide();
45       });
46       $(".retry", this.element).click(function(ev) {
47         $(".correct, .incorrect", _this.element).removeClass("correct incorrect");
48         $(ev.target).prev(".check").show();
49         return $(ev.target).hide();
50       });
51       $('.solutions', this.element).click(function() {
52         _this.show_solutions();
53         return $(".comment", _this.element).show();
54       });
55       $('.reset', this.element).click(function() {
56         return _this.reset();
57       });
58     }
59
60     Exercise.prototype.reset = function() {
61       $(this.element).html($(this.element).data('exercise-html'));
62       return exercise(this.element);
63     };
64
65     Exercise.prototype.piece_correct = function(qpiece) {
66       return $(qpiece).removeClass('incorrect').addClass('correct');
67     };
68
69     Exercise.prototype.piece_incorrect = function(qpiece) {
70       return $(qpiece).removeClass('correct').addClass('incorrect');
71     };
72
73     Exercise.prototype.check = function() {
74       var score, scores,
75         _this = this;
76       scores = [];
77       $(".question", this.element).each(function(i, question) {
78         return scores.push(_this.check_question(question));
79       });
80       score = [0, 0];
81       $.each(scores, function(i, s) {
82         score[0] += s[0];
83         return score[1] += s[1];
84       });
85       return this.show_score(score);
86     };
87
88     Exercise.prototype.show_solutions = function() {
89       var _this = this;
90       this.reset();
91       return $(".question", this.element).each(function(i, question) {
92         return _this.solve_question(question);
93       });
94     };
95
96     Exercise.prototype.get_value_list = function(elem, data_key, numbers) {
97       var vl;
98       vl = $(elem).attr("data-" + data_key).split(/[ ,]+/).map($.trim);
99       if (numbers) {
100         vl = vl.map(function(x) {
101           return parseInt(x);
102         });
103       }
104       return vl;
105     };
106
107     Exercise.prototype.get_value_optional_list = function(elem, data_key) {
108       var mandat, opt, v, vals, _i, _len;
109       vals = this.get_value_list(elem, data_key);
110       mandat = [];
111       opt = [];
112       for (_i = 0, _len = vals.length; _i < _len; _i++) {
113         v = vals[_i];
114         if (v.slice(-1) === "?") {
115           opt.push(v.slice(0, -1));
116         } else {
117           mandat.push(v);
118         }
119       }
120       return [mandat, opt];
121     };
122
123     Exercise.prototype.show_score = function(score) {
124       return $(".message", this.element).text("Wynik: " + score[0] + " / " + score[1]);
125     };
126
127     Exercise.prototype.draggable_equal = function($draggable1, $draggable2) {
128       return false;
129     };
130
131     Exercise.prototype.draggable_accept = function($draggable, $droppable) {
132       var d, dropped, _i, _len;
133       dropped = $droppable.closest("ul, ol").find(".draggable");
134       for (_i = 0, _len = dropped.length; _i < _len; _i++) {
135         d = dropped[_i];
136         if (this.draggable_equal($draggable, $(d))) {
137           return false;
138         }
139       }
140       return true;
141     };
142
143     Exercise.prototype.draggable_move = function($draggable, $placeholder, ismultiple) {
144       var $added,
145         _this = this;
146       $added = $draggable.clone();
147       $added.data("original", $draggable.get(0));
148       if (!ismultiple) {
149         $draggable.addClass('disabled').draggable('disable');
150       }
151       $placeholder.after($added);
152       if (!$placeholder.hasClass('multiple')) {
153         $placeholder.hide();
154       }
155       if ($added.is(".add-li")) {
156         $added.wrap("<li/>");
157       }
158       $added.append('<span class="remove">x</span><div class="clr"></div>');
159       return $('.remove', $added).click(function(ev) {
160         if (!ismultiple) {
161           $($added.data('original')).removeClass('disabled').draggable('enable');
162         }
163         if ($added.is(".add-li")) {
164           $added = $added.closest('li');
165         }
166         $added.prev(".placeholder:not(.multiple)").show();
167         return $added.remove();
168       });
169     };
170
171     Exercise.prototype.dragging = function(ismultiple, issortable) {
172       var _this = this;
173       return $(".question", this.element).each(function(i, question) {
174         var draggable_opts, self;
175         draggable_opts = {
176           revert: 'invalid',
177           helper: 'clone'
178         };
179         $(".draggable", question).draggable(draggable_opts);
180         self = _this;
181         return $(".placeholder", question).droppable({
182           accept: function(draggable) {
183             var $draggable, is_accepted;
184             $draggable = $(draggable);
185             is_accepted = true;
186             if (!$draggable.is(".draggable")) {
187               is_accepted = false;
188             }
189             if (is_accepted) {
190               is_accepted = self.draggable_accept($draggable, $(this));
191             }
192             if (is_accepted) {
193               $(this).addClass('accepting');
194             } else {
195               $(this).removeClass('accepting');
196             }
197             return is_accepted;
198           },
199           drop: function(ev, ui) {
200             $(ev.target).removeClass('accepting dragover');
201             return _this.draggable_move($(ui.draggable), $(ev.target), ismultiple);
202           },
203           over: function(ev, ui) {
204             return $(ev.target).addClass('dragover');
205           },
206           out: function(ev, ui) {
207             return $(ev.target).removeClass('dragover');
208           }
209         });
210       });
211     };
212
213     return Exercise;
214
215   })(Binding);
216
217   Wybor = (function(_super) {
218
219     __extends(Wybor, _super);
220
221     function Wybor(element) {
222       Wybor.__super__.constructor.call(this, element);
223     }
224
225     Wybor.prototype.check_question = function(question) {
226       var all, good, solution,
227         _this = this;
228       all = 0;
229       good = 0;
230       solution = this.get_value_list(question, 'solution');
231       $(".question-piece", question).each(function(i, qpiece) {
232         var is_checked, piece_name, piece_no, should_be_checked;
233         piece_no = $(qpiece).attr('data-no');
234         piece_name = $(qpiece).attr('data-name');
235         if (piece_name) {
236           should_be_checked = solution.indexOf(piece_name) >= 0;
237         } else {
238           should_be_checked = solution.indexOf(piece_no) >= 0;
239         }
240         is_checked = $("input", qpiece).is(":checked");
241         if (should_be_checked) {
242           all += 1;
243         }
244         if (is_checked) {
245           if (should_be_checked) {
246             good += 1;
247             return _this.piece_correct(qpiece);
248           } else {
249             return _this.piece_incorrect(qpiece);
250           }
251         } else {
252           return $(qpiece).removeClass("correct,incorrect");
253         }
254       });
255       return [good, all];
256     };
257
258     Wybor.prototype.solve_question = function(question) {
259       var solution,
260         _this = this;
261       solution = this.get_value_list(question, 'solution');
262       return $(".question-piece", question).each(function(i, qpiece) {
263         var piece_name, piece_no, should_be_checked;
264         piece_no = $(qpiece).attr('data-no');
265         piece_name = $(qpiece).attr('data-name');
266         if (piece_name) {
267           should_be_checked = solution.indexOf(piece_name) >= 0;
268         } else {
269           should_be_checked = solution.indexOf(piece_no) >= 0;
270         }
271         console.log("check " + $("input[type=checkbox]", qpiece).attr("id") + " -> " + should_be_checked);
272         return $("input[type=checkbox],input[type=radio]", qpiece).prop('checked', should_be_checked);
273       });
274     };
275
276     return Wybor;
277
278   })(Exercise);
279
280   Uporzadkuj = (function(_super) {
281
282     __extends(Uporzadkuj, _super);
283
284     function Uporzadkuj(element) {
285       Uporzadkuj.__super__.constructor.call(this, element);
286       $('ol, ul', this.element).sortable({
287         items: "> li"
288       });
289     }
290
291     Uporzadkuj.prototype.check_question = function(question) {
292       var all, correct, pkt, pkts, positions, sorted, _i, _ref;
293       positions = this.get_value_list(question, 'original', true);
294       sorted = positions.sort();
295       pkts = $('.question-piece', question);
296       correct = 0;
297       all = 0;
298       for (pkt = _i = 0, _ref = pkts.length; 0 <= _ref ? _i < _ref : _i > _ref; pkt = 0 <= _ref ? ++_i : --_i) {
299         all += 1;
300         if (pkts.eq(pkt).data('pos') === sorted[pkt]) {
301           correct += 1;
302           this.piece_correct(pkts.eq(pkt));
303         } else {
304           this.piece_incorrect(pkts.eq(pkt));
305         }
306       }
307       return [correct, all];
308     };
309
310     Uporzadkuj.prototype.solve_question = function(question) {
311       var p, parent, pkts, positions, sorted, _i, _len, _results;
312       positions = this.get_value_list(question, 'original', true);
313       sorted = positions.sort();
314       pkts = $('.question-piece', question);
315       pkts.sort(function(a, b) {
316         var q, w;
317         q = $(a).data('pos');
318         w = $(b).data('pos');
319         if (q < w) {
320           return 1;
321         }
322         if (q > w) {
323           return -1;
324         }
325         return 0;
326       });
327       parent = pkts.eq(0).parent();
328       _results = [];
329       for (_i = 0, _len = pkts.length; _i < _len; _i++) {
330         p = pkts[_i];
331         _results.push(parent.prepend(p));
332       }
333       return _results;
334     };
335
336     return Uporzadkuj;
337
338   })(Exercise);
339
340   Luki = (function(_super) {
341
342     __extends(Luki, _super);
343
344     function Luki(element) {
345       Luki.__super__.constructor.call(this, element);
346       this.dragging(false, false);
347     }
348
349     Luki.prototype.check = function() {
350       var all, correct,
351         _this = this;
352       all = 0;
353       correct = 0;
354       $(".placeholder + .question-piece", this.element).each(function(i, qpiece) {
355         var $placeholder;
356         $placeholder = $(qpiece).prev(".placeholder");
357         if ($placeholder.data('solution') === $(qpiece).data('no')) {
358           _this.piece_correct(qpiece);
359           correct += 1;
360         } else {
361           _this.piece_incorrect(qpiece);
362         }
363         return all += 1;
364       });
365       return this.show_score([correct, all]);
366     };
367
368     Luki.prototype.solve_question = function(question) {
369       var _this = this;
370       return $(".placeholder", question).each(function(i, placeholder) {
371         var $qp;
372         $qp = $(".question-piece[data-no=" + $(placeholder).data('solution') + "]", question);
373         return _this.draggable_move($qp, $(placeholder), false);
374       });
375     };
376
377     return Luki;
378
379   })(Exercise);
380
381   Zastap = (function(_super) {
382
383     __extends(Zastap, _super);
384
385     function Zastap(element) {
386       var _this = this;
387       Zastap.__super__.constructor.call(this, element);
388       $(".paragraph", this.element).each(function(i, par) {
389         return _this.wrap_words($(par), $('<span class="placeholder zastap"/>'));
390       });
391       this.dragging(false, false);
392     }
393
394     Zastap.prototype.check = function() {
395       var all, correct,
396         _this = this;
397       all = 0;
398       correct = 0;
399       $(".paragraph", this.element).each(function(i, par) {
400         return $(".placeholder", par).each(function(j, qpiece) {
401           var $dragged, $qp;
402           $qp = $(qpiece);
403           $dragged = $qp.next(".draggable");
404           if ($qp.data("solution")) {
405             if ($dragged && $qp.data("solution") === $dragged.data("no")) {
406               _this.piece_correct($dragged);
407               correct += 1;
408             }
409             return all += 1;
410           }
411         });
412       });
413       return this.show_score([correct, all]);
414     };
415
416     Zastap.prototype.show_solutions = function() {
417       var _this = this;
418       this.reset();
419       return $(".paragraph", this.element).each(function(i, par) {
420         return $(".placeholder[data-solution]", par).each(function(j, qpiece) {
421           var $dr, $qp;
422           $qp = $(qpiece);
423           $dr = $(".draggable[data-no=" + $qp.data('solution') + "]", _this.element);
424           return _this.draggable_move($dr, $qp, false);
425         });
426       });
427     };
428
429     Zastap.prototype.wrap_words = function(element, wrapper) {
430       var chld, i, ignore, insertWrapped, j, len, space, wordb, _i, _ref, _results;
431       ignore = /^[ \t.,:;()]+/;
432       insertWrapped = function(txt, elem) {
433         var nw;
434         nw = wrapper.clone();
435         return $(document.createTextNode(txt)).wrap(nw).parent().attr("data-original", txt).insertBefore(elem);
436       };
437       _results = [];
438       for (j = _i = _ref = element.get(0).childNodes.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; j = _ref <= 0 ? ++_i : --_i) {
439         chld = element.get(0).childNodes[j];
440         if (chld.nodeType === document.TEXT_NODE) {
441           len = chld.textContent.length;
442           wordb = 0;
443           i = 0;
444           while (i < len) {
445             space = ignore.exec(chld.textContent.substr(i));
446             if (space != null) {
447               if (wordb < i) {
448                 insertWrapped(chld.textContent.substr(wordb, i - wordb), chld);
449               }
450               $(document.createTextNode(space[0])).insertBefore(chld);
451               i += space[0].length;
452               wordb = i;
453             } else {
454               i = i + 1;
455             }
456           }
457           if (wordb < len - 1) {
458             insertWrapped(chld.textContent.substr(wordb, len - 1 - wordb), chld);
459           }
460           _results.push($(chld).remove());
461         } else {
462           _results.push(void 0);
463         }
464       }
465       return _results;
466     };
467
468     return Zastap;
469
470   })(Exercise);
471
472   Przyporzadkuj = (function(_super) {
473
474     __extends(Przyporzadkuj, _super);
475
476     Przyporzadkuj.prototype.is_multiple = function() {
477       var qp, _i, _len, _ref;
478       _ref = $(".question-piece", this.element);
479       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
480         qp = _ref[_i];
481         if ($(qp).data('solution').split(/[ ,]+/).length > 1) {
482           return true;
483         }
484       }
485       return false;
486     };
487
488     function Przyporzadkuj(element) {
489       Przyporzadkuj.__super__.constructor.call(this, element);
490       this.multiple = this.is_multiple();
491       this.dragging(this.multiple, true);
492     }
493
494     Przyporzadkuj.prototype.draggable_equal = function(d1, d2) {
495       return d1.data("no") === d2.data("no");
496     };
497
498     Przyporzadkuj.prototype.check_question = function(question) {
499       var all, count, mandatory, minimum, optional, pn, pred, qp, v, _i, _j, _len, _len1, _ref, _ref1;
500       minimum = $(question).data("minimum");
501       count = 0;
502       all = 0;
503       if (!minimum) {
504         all = $(".subjects .question-piece", question).length;
505       }
506       _ref = $(".predicate [data-predicate]", question);
507       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
508         pred = _ref[_i];
509         pn = $(pred).attr('data-predicate');
510         if (minimum != null) {
511           all += minimum;
512         }
513         _ref1 = $(".question-piece", pred);
514         for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
515           qp = _ref1[_j];
516           v = this.get_value_optional_list(qp, 'solution');
517           mandatory = v[0];
518           optional = v[1];
519           if (mandatory.indexOf(pn) >= 0 || (minimum && optional.indexOf(pn) >= 0)) {
520             count += 1;
521             this.piece_correct(qp);
522           } else {
523             this.piece_incorrect(qp);
524           }
525         }
526       }
527       return [count, all];
528     };
529
530     Przyporzadkuj.prototype.solve_question = function(question) {
531       var $ph, $pr, draggables, m, mandatory, minimum, optional, qp, v, _i, _len, _ref, _results;
532       minimum = $(question).data("min");
533       _ref = $(".subject .question-piece", question);
534       _results = [];
535       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
536         qp = _ref[_i];
537         v = this.get_value_optional_list(qp, 'solution');
538         mandatory = v[0];
539         optional = v[1];
540         if (minimum) {
541           draggables = mandatory.count(optional).slice(0, minimum);
542         } else {
543           draggables = mandatory;
544         }
545         _results.push((function() {
546           var _j, _len1, _results1;
547           _results1 = [];
548           for (_j = 0, _len1 = draggables.length; _j < _len1; _j++) {
549             m = draggables[_j];
550             $pr = $(".predicate [data-predicate=" + m + "]", question);
551             $ph = $pr.find(".placeholder:visible");
552             _results1.push(this.draggable_move($(qp), $ph, this.multiple));
553           }
554           return _results1;
555         }).call(this));
556       }
557       return _results;
558     };
559
560     return Przyporzadkuj;
561
562   })(Exercise);
563
564   PrawdaFalsz = (function(_super) {
565
566     __extends(PrawdaFalsz, _super);
567
568     function PrawdaFalsz(element) {
569       var qp, _i, _len, _ref;
570       PrawdaFalsz.__super__.constructor.call(this, element);
571       _ref = $(".question-piece", this.element);
572       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
573         qp = _ref[_i];
574         $(".true", qp).click(function(ev) {
575           ev.preventDefault();
576           $(this).closest(".question-piece").data("value", "true");
577           return $(this).addClass('chosen').siblings('a').removeClass('chosen');
578         });
579         $(".false", qp).click(function(ev) {
580           ev.preventDefault();
581           $(this).closest(".question-piece").data("value", "false");
582           return $(this).addClass('chosen').siblings('a').removeClass('chosen');
583         });
584       }
585     }
586
587     PrawdaFalsz.prototype.check_question = function() {
588       var all, good, qp, _i, _len, _ref;
589       all = 0;
590       good = 0;
591       _ref = $(".question-piece", this.element);
592       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
593         qp = _ref[_i];
594         if ($(qp).data("solution").toString() === $(qp).data("value")) {
595           good += 1;
596           this.piece_correct(qp);
597         } else {
598           this.piece_incorrect(qp);
599         }
600         all += 1;
601       }
602       return [good, all];
603     };
604
605     PrawdaFalsz.prototype.show_solutions = function() {
606       var qp, _i, _len, _ref, _results;
607       this.reset();
608       _ref = $(".question-piece", this.element);
609       _results = [];
610       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
611         qp = _ref[_i];
612         if ($(qp).data('solution') === true) {
613           _results.push($(".true", qp).click());
614         } else {
615           _results.push($(".false", qp).click());
616         }
617       }
618       return _results;
619     };
620
621     return PrawdaFalsz;
622
623   })(Exercise);
624
625   exercise = function(ele) {
626     var cls, es;
627     es = {
628       wybor: Wybor,
629       uporzadkuj: Uporzadkuj,
630       luki: Luki,
631       zastap: Zastap,
632       przyporzadkuj: Przyporzadkuj,
633       prawdafalsz: PrawdaFalsz
634     };
635     cls = es[$(ele).attr('data-type')];
636     return new cls(ele);
637   };
638
639   window.edumed = {
640     'EduModule': EduModule
641   };
642
643   $(document).ready(function() {
644     new EduModule($("#book-text"));
645     return $(".exercise").each(function(i, el) {
646       return exercise(this);
647     });
648   });
649
650 }).call(this);