Commit 9788839fb9912c15c4cd64dec050d8ec23ed03be

Authored by Miguel Barão
1 parent 24e493a4
Exists in master and in 1 other branch dev

- fixed inactivate input on submit (also double clicks)

- changed animations and shows a spinner while correcting
- improved submit button dynamics
- link to latest mathjax from cdn
1 1
2 # BUGS 2 # BUGS
3 3
4 -- apos clicar no botao responder, inactivar o input (importante quando o tempo de correcção é grande)  
5 - nao esta a seguir o max_tries definido no ficheiro de dependencias. 4 - nao esta a seguir o max_tries definido no ficheiro de dependencias.
6 -- initdb da integrity error se no mesmo comando existirem alunos repetidos (p.ex em ficheiros csv diferentes ou entre csv e opcao -a)  
7 -- double click submits twice.  
8 -- duplo clicks no botao "responder" dessincroniza as questões, ver debounce em https://stackoverflow.com/questions/20281546/how-to-prevent-calling-of-en-event-handler-twice-on-fast-clicks  
9 - devia mostrar timeout para o aluno saber a razao. 5 - devia mostrar timeout para o aluno saber a razao.
10 - permitir configuracao para escolher entre static files locais ou remotos 6 - permitir configuracao para escolher entre static files locais ou remotos
11 - templates question-*.html tem input hidden question_ref que não é usado. remover? 7 - templates question-*.html tem input hidden question_ref que não é usado. remover?
12 - shift-enter não está a funcionar 8 - shift-enter não está a funcionar
13 - default prefix should be obtained from each course (yaml conf)? 9 - default prefix should be obtained from each course (yaml conf)?
  10 +- initdb da integrity error se no mesmo comando existirem alunos repetidos (p.ex em ficheiros csv diferentes ou entre csv e opcao -a)
14 11
15 # TODO 12 # TODO
16 13
@@ -34,6 +31,8 @@ @@ -34,6 +31,8 @@
34 31
35 # FIXED 32 # FIXED
36 33
  34 +- apos clicar no botao responder, inactivar o input (importante quando o tempo de correcção é grande)
  35 +- double click submits twice.
37 - checkbox devia ter correct no intervalo [0,1] tal como radio. em caso de desconto a correccção faz 2*x-1. isto permite a mesma semantica nos dois tipos de perguntas. 36 - checkbox devia ter correct no intervalo [0,1] tal como radio. em caso de desconto a correccção faz 2*x-1. isto permite a mesma semantica nos dois tipos de perguntas.
38 - marking all options right in a radio question breaks! 37 - marking all options right in a radio question breaks!
39 - implementar servidor http com redirect para https. 38 - implementar servidor http com redirect para https.
aprendizations/__init__.py
@@ -30,7 +30,7 @@ are progressively uncovered as the students progress. @@ -30,7 +30,7 @@ are progressively uncovered as the students progress.
30 ''' 30 '''
31 31
32 APP_NAME = 'aprendizations' 32 APP_NAME = 'aprendizations'
33 -APP_VERSION = '2019.11.dev4' 33 +APP_VERSION = '2019.12.dev1'
34 APP_DESCRIPTION = __doc__ 34 APP_DESCRIPTION = __doc__
35 35
36 __author__ = 'Miguel Barão' 36 __author__ = 'Miguel Barão'
aprendizations/questions.py
@@ -220,11 +220,11 @@ class QuestionCheckbox(Question): @@ -220,11 +220,11 @@ class QuestionCheckbox(Question):
220 if self['discount'] and not all(0.0 <= x <= 1.0 220 if self['discount'] and not all(0.0 <= x <= 1.0
221 for x in self['correct']): 221 for x in self['correct']):
222 222
223 - msg0 = ('+-------------- BEHAVIOR CHANGE NOTICE --------------+')  
224 - msg1 = ('| Correct values must be in the interval [0.0, 1.0]. |')  
225 - msg2 = ('| I will convert to the new behavior, but you should |')  
226 - msg3 = ('| fix it in the question. |')  
227 - msg4 = ('+----------------------------------------------------+') 223 + msg0 = ('+--------------- BEHAVIOR CHANGE NOTICE ---------------+')
  224 + msg1 = ('| Correct values in checkbox questions must be in the |')
  225 + msg2 = ('| interval [0.0, 1.0]. I will convert to the new |')
  226 + msg3 = ('| behavior, for now, but you should fix it. |')
  227 + msg4 = ('+------------------------------------------------------+')
228 logger.warning(msg0) 228 logger.warning(msg0)
229 logger.warning(msg1) 229 logger.warning(msg1)
230 logger.warning(msg2) 230 logger.warning(msg2)
aprendizations/serve.py
@@ -345,7 +345,7 @@ class QuestionHandler(BaseHandler): @@ -345,7 +345,7 @@ class QuestionHandler(BaseHandler):
345 return 345 return
346 346
347 # --- brain hacking ;) 347 # --- brain hacking ;)
348 - await asyncio.sleep(2) 348 + await asyncio.sleep(1.5)
349 349
350 # --- answers are in a list. fix depending on question type 350 # --- answers are in a list. fix depending on question type
351 qtype = self.learn.get_student_question_type(user) 351 qtype = self.learn.get_student_question_type(user)
aprendizations/static/js/topic.js
1 $.fn.extend({ 1 $.fn.extend({
2 - animateCSS: function (animation) { 2 + animateCSS: function (animation, run_on_end) {
3 var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend'; 3 var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
4 this.addClass('animated ' + animation).one(animationEnd, function() { 4 this.addClass('animated ' + animation).one(animationEnd, function() {
5 $(this).removeClass('animated ' + animation); 5 $(this).removeClass('animated ' + animation);
6 - $("#submit").removeClass("disabled"); 6 + if (run_on_end !== undefined) {
  7 + run_on_end();
  8 + }
7 }); 9 });
8 } 10 }
9 }); 11 });
@@ -21,7 +23,9 @@ function showTriesLeft(tries) { @@ -21,7 +23,9 @@ function showTriesLeft(tries) {
21 23
22 // Get current question 24 // Get current question
23 function getQuestion() { 25 function getQuestion() {
  26 + $("#comments").html("").hide();
24 $("#submit").addClass("disabled"); 27 $("#submit").addClass("disabled");
  28 +
25 $.ajax({ 29 $.ajax({
26 type: "GET", 30 type: "GET",
27 url: "/question", 31 url: "/question",
@@ -37,6 +41,7 @@ function updateQuestion(response) { @@ -37,6 +41,7 @@ function updateQuestion(response) {
37 var params = response["params"]; 41 var params = response["params"];
38 42
39 $("#right, #wrong").hide(); 43 $("#right, #wrong").hide();
  44 +
40 switch (method) { 45 switch (method) {
41 case "new_question": 46 case "new_question":
42 new_question(params["type"], params["question"], params["tries"], params["progress"]); 47 new_question(params["type"], params["question"], params["tries"], params["progress"]);
@@ -52,13 +57,18 @@ function updateQuestion(response) { @@ -52,13 +57,18 @@ function updateQuestion(response) {
52 57
53 function new_question(type, question, tries, progress) { 58 function new_question(type, question, tries, progress) {
54 window.scrollTo(0, 0); 59 window.scrollTo(0, 0);
55 - $("#question_div").html(question).animateCSS('bounceInDown');  
56 - showTriesLeft(tries);  
57 - $("#comments").html("").hide(); 60 + $("#submit").hide();
  61 + $("#question_div").animateCSS('bounceOutUp', function() {
  62 + $("#question_div").html(question);
  63 + MathJax.typeset();
  64 + $("#question_div").animateCSS('bounceInDown', function() {
  65 + showTriesLeft(tries);
  66 + $("#submit").removeClass("disabled").show();
  67 + });
  68 + });
58 var btntext = (type == "information") ? "Continuar" : "Responder"; 69 var btntext = (type == "information") ? "Continuar" : "Responder";
59 $("#submit").html(btntext).off().click(postAnswer); 70 $("#submit").html(btntext).off().click(postAnswer);
60 $('#topic_progress').css('width', (100*progress)+'%').attr('aria-valuenow', 100*progress); 71 $('#topic_progress').css('width', (100*progress)+'%').attr('aria-valuenow', 100*progress);
61 - MathJax.typeset();  
62 72
63 if (type == "radio") { 73 if (type == "radio") {
64 $(".list-group-item").click(function (e) { 74 $(".list-group-item").click(function (e) {
@@ -93,6 +103,8 @@ function postAnswer() { @@ -93,6 +103,8 @@ function postAnswer() {
93 success: getFeedback, 103 success: getFeedback,
94 error: function() {alert("O servidor não responde.");} 104 error: function() {alert("O servidor não responde.");}
95 }); 105 });
  106 + $("#submit").addClass("disabled").html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>');
  107 + $("fieldset").prop("disabled", true);
96 } 108 }
97 109
98 function getFeedback(response) { 110 function getFeedback(response) {
@@ -106,32 +118,39 @@ function getFeedback(response) { @@ -106,32 +118,39 @@ function getFeedback(response) {
106 118
107 switch (method) { 119 switch (method) {
108 case "right": 120 case "right":
  121 + $('#wrong').hide();
109 $('#comments').html(params['comments']).show(); 122 $('#comments').html(params['comments']).show();
110 $('#solution_right').html(params['solution']); 123 $('#solution_right').html(params['solution']);
111 MathJax.typeset(); 124 MathJax.typeset();
112 - $('#wrong').hide();  
113 - $('#right').show().animateCSS('flipInX');  
114 - $("#submit").html("Continuar").off().click(getQuestion); 125 + $('#right').show().animateCSS('zoomIn', function(){
  126 + $("#submit").html("Continuar").removeClass("disabled").off().click(getQuestion);
  127 + });
115 break; 128 break;
116 129
117 case "try_again": 130 case "try_again":
118 $('#comments').html(params['comments']).show(); 131 $('#comments').html(params['comments']).show();
119 MathJax.typeset(); 132 MathJax.typeset();
120 - $('#question_div').animateCSS('shake');  
121 $('#topic_progress').css('width', (100*params["progress"])+'%').attr('aria-valuenow', 100*params["progress"]); 133 $('#topic_progress').css('width', (100*params["progress"])+'%').attr('aria-valuenow', 100*params["progress"]);
122 - showTriesLeft(params["tries"]); 134 + $('#question_div').animateCSS('shake', function() {
  135 + showTriesLeft(params["tries"]);
  136 + $("fieldset").prop("disabled", false);
  137 + $("#submit").html("Responder").removeClass("disabled");
  138 + });
123 break; 139 break;
124 140
125 case "wrong": 141 case "wrong":
  142 + $("fieldset").prop("disabled", true);
  143 + $('#right').hide();
126 $('#comments').html(params['comments']).show(); 144 $('#comments').html(params['comments']).show();
127 $('#solution_wrong').html(params['solution']); 145 $('#solution_wrong').html(params['solution']);
128 MathJax.typeset(); 146 MathJax.typeset();
129 - $('#right').hide();  
130 - $('#wrong').show().animateCSS('flipInX'); 147 + $('#question_div').animateCSS('shake', function() {
  148 + showTriesLeft(params["tries"]);
  149 + $('#wrong').show().animateCSS('zoomIn', function() {
  150 + $("#submit").html("Continuar").removeClass("disabled").off().click(getQuestion);
  151 + });
  152 + });
131 $('#topic_progress').css('width', (100*params["progress"])+'%').attr('aria-valuenow', 100*params["progress"]); 153 $('#topic_progress').css('width', (100*params["progress"])+'%').attr('aria-valuenow', 100*params["progress"]);
132 - showTriesLeft(params["tries"]);  
133 - $("fieldset").attr("disabled", "disabled");  
134 - $("#submit").html("Continuar").off().click(getQuestion);  
135 break; 154 break;
136 155
137 case "invalid": 156 case "invalid":
aprendizations/templates/topic.html
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 } 21 }
22 }; 22 };
23 </script> 23 </script>
24 - <script async type="text/javascript" id="MathJax-script" src="/static/mathjax/es5/tex-svg.js"></script> 24 + <script async type="text/javascript" id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
25 <!-- Styles --> 25 <!-- Styles -->
26 <link rel="stylesheet" href="/static/mdbootstrap/css/bootstrap.min.css"> 26 <link rel="stylesheet" href="/static/mdbootstrap/css/bootstrap.min.css">
27 <link rel="stylesheet" href="/static/mdbootstrap/css/mdb.min.css"> 27 <link rel="stylesheet" href="/static/mdbootstrap/css/mdb.min.css">
package-lock.json
@@ -40,9 +40,9 @@ @@ -40,9 +40,9 @@
40 } 40 }
41 }, 41 },
42 "mdbootstrap": { 42 "mdbootstrap": {
43 - "version": "4.9.0",  
44 - "resolved": "https://registry.npmjs.org/mdbootstrap/-/mdbootstrap-4.9.0.tgz",  
45 - "integrity": "sha512-6R3j5D9Qmp+Aa90FblOVAwVDSqpAICYW2dpNxh6uaVB9E9MCaBLdaTKLrXCB7xznReHEaA57pNABXgFoi2z7Rg==" 43 + "version": "4.10.0",
  44 + "resolved": "https://registry.npmjs.org/mdbootstrap/-/mdbootstrap-4.10.0.tgz",
  45 + "integrity": "sha512-jpDSrAv9BbqHGFCHf9iQts7dWAuJYT3VFmElLkKpD6cGJ5Pcjv5oiTvfKvFGjVsxWsjLtj7Y0Rh135EYejkaeg=="
46 }, 46 },
47 "mj-context-menu": { 47 "mj-context-menu": {
48 "version": "0.2.0", 48 "version": "0.2.0",
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 "@fortawesome/fontawesome-free": "^5.11.2", 5 "@fortawesome/fontawesome-free": "^5.11.2",
6 "codemirror": "^5.49.2", 6 "codemirror": "^5.49.2",
7 "mathjax": "^3", 7 "mathjax": "^3",
8 - "mdbootstrap": "^4.9.0" 8 + "mdbootstrap": "^4.10.0"
9 }, 9 },
10 "private": true 10 "private": true
11 } 11 }