Commit 9aeb5485618afee8d771f689cf68305cfc76af77
1 parent
dbdd58fe
Exists in
master
and in
1 other branch
- modified how post questions behave: wait feedback then move to next question.
not yet functional!
Showing
11 changed files
with
157 additions
and
112 deletions
Show diff stats
BUGS.md
| 1 | 1 | |
| 2 | 2 | # BUGS |
| 3 | 3 | |
| 4 | +- errar no ultimo topico nao mostra solucao? | |
| 4 | 5 | - nos topicos learn.yaml, qd falha acrescenta no fim. nao faz sentido. |
| 5 | 6 | - ocorreu uma vez o sqlalchemy dar mesg erro a indicar que as threads sao diferents quando se faz o get da primeira pergunta do topico. Muitas vezes nao mostar erro, mas a pagina da erro ou fica em branco... |
| 6 | 7 | ... | ... |
demo/solar_system/questions.yaml
| ... | ... | @@ -19,32 +19,32 @@ |
| 19 | 19 | shuffle: False |
| 20 | 20 | discount: True |
| 21 | 21 | |
| 22 | -# # --------------------------------------------------------------------------- | |
| 23 | -# - | |
| 24 | -# ref: home-planet | |
| 25 | -# type: text | |
| 26 | -# title: Sistema solar | |
| 27 | -# text: O nosso planeta chama-se planeta... | |
| 28 | -# correct: ['Terra', 'terra'] | |
| 29 | -# # opcional | |
| 30 | -# answer: Não é Marte... | |
| 22 | +# --------------------------------------------------------------------------- | |
| 23 | +- | |
| 24 | + ref: home-planet | |
| 25 | + type: text | |
| 26 | + title: Sistema solar | |
| 27 | + text: O nosso planeta chama-se planeta... | |
| 28 | + correct: ['Terra', 'terra'] | |
| 29 | + # opcional | |
| 30 | + answer: Não é Marte... | |
| 31 | 31 | |
| 32 | -# # --------------------------------------------------------------------------- | |
| 33 | -# - | |
| 34 | -# ref: saturn | |
| 35 | -# type: text-regex | |
| 36 | -# title: Sistema solar | |
| 37 | -# text: O planeta do sistema solar conhecido por ter aneis é o planeta... | |
| 38 | -# correct: !regex '[Ss]aturno' | |
| 32 | +# --------------------------------------------------------------------------- | |
| 33 | +- | |
| 34 | + ref: saturn | |
| 35 | + type: text-regex | |
| 36 | + title: Sistema solar | |
| 37 | + text: O planeta do sistema solar conhecido por ter aneis é o planeta... | |
| 38 | + correct: !regex '[Ss]aturno' | |
| 39 | 39 | |
| 40 | 40 | # --------------------------------------------------------------------------- |
| 41 | -# - ref: first_3_planets | |
| 42 | -# type: textarea | |
| 43 | -# title: Sistema solar | |
| 44 | -# text: Escreva o nome dos três planetas mais próximos do Sol. (Exemplo `A, B e C`) | |
| 45 | -# correct: correct-first_3_planets.py | |
| 46 | -# # correct: correct-timeout.py | |
| 47 | -# # opcional | |
| 48 | -# answer: Vulcano, Krypton, Plutão | |
| 49 | -# lines: 3 | |
| 50 | -# timeout: 50 | |
| 41 | +- ref: first_3_planets | |
| 42 | + type: textarea | |
| 43 | + title: Sistema solar | |
| 44 | + text: Escreva o nome dos três planetas mais próximos do Sol. (Exemplo `A, B e C`) | |
| 45 | + correct: correct-first_3_planets.py | |
| 46 | + # correct: correct-timeout.py | |
| 47 | + # opcional | |
| 48 | + answer: Vulcano, Krypton, Plutão | |
| 49 | + lines: 3 | |
| 50 | + timeout: 50 | ... | ... |
http-redirect.py
| ... | ... | @@ -16,7 +16,7 @@ from tornado import ioloop, web, httpserver |
| 16 | 16 | class WebRedirectApplication(web.Application): |
| 17 | 17 | def __init__(self, target='https://localhost'): |
| 18 | 18 | handlers = [ |
| 19 | - (r'/*', RootHandler), # redirect to https | |
| 19 | + (r'/', RootHandler), # redirect to https | |
| 20 | 20 | ] |
| 21 | 21 | super().__init__(handlers) |
| 22 | 22 | self.target = target |
| ... | ... | @@ -28,7 +28,7 @@ class RootHandler(web.RequestHandler): |
| 28 | 28 | SUPPORTED_METHODS = ['GET'] |
| 29 | 29 | |
| 30 | 30 | def get(self): |
| 31 | - print('Redirecting...') | |
| 31 | + # print('Redirecting...') | |
| 32 | 32 | self.redirect(self.application.target) |
| 33 | 33 | |
| 34 | 34 | ... | ... |
knowledge.py
| ... | ... | @@ -153,7 +153,7 @@ class StudentKnowledge(object): |
| 153 | 153 | if self.next_question() is None: |
| 154 | 154 | action = 'finished_topic' |
| 155 | 155 | else: |
| 156 | - action = 'new_question' # FIXME show comments | |
| 156 | + action = 'wrong' # FIXME show comments | |
| 157 | 157 | |
| 158 | 158 | else: |
| 159 | 159 | action = 'try_again' | ... | ... |
learnapp.py
| ... | ... | @@ -191,7 +191,7 @@ class LearnApp(object): |
| 191 | 191 | logger.warning(f'User "{uid}" tried to open nonexistent topic: "{topic}"') |
| 192 | 192 | raise e |
| 193 | 193 | else: |
| 194 | - logger.info(f'User "{uid}" started "{topic}"') | |
| 194 | + logger.info(f'User "{uid}" started topic "{topic}"') | |
| 195 | 195 | |
| 196 | 196 | # ------------------------------------------------------------------------ |
| 197 | 197 | # Fill db table 'Topic' with topics from the graph if not already there. | ... | ... |
questions.py
| ... | ... | @@ -363,11 +363,6 @@ class QuestionTextArea(Question): |
| 363 | 363 | |
| 364 | 364 | # =========================================================================== |
| 365 | 365 | class QuestionInformation(Question): |
| 366 | - '''An instance of QuestionInformation will always have the keys: | |
| 367 | - type (str) | |
| 368 | - text (str) | |
| 369 | - points (0.0) | |
| 370 | - ''' | |
| 371 | 366 | #------------------------------------------------------------------------ |
| 372 | 367 | def __init__(self, q): |
| 373 | 368 | super().__init__(q) | ... | ... |
serve.py
| ... | ... | @@ -44,7 +44,7 @@ class WebApplication(tornado.web.Application): |
| 44 | 44 | (r'/logout', LogoutHandler), |
| 45 | 45 | (r'/change_password', ChangePasswordHandler), |
| 46 | 46 | (r'/question', QuestionHandler), # renders each question |
| 47 | - (r'/topic/(.+)', TopicHandler), # page for exercising a topic | |
| 47 | + (r'/topic/(.+)', TopicHandler), # start a topic | |
| 48 | 48 | (r'/file/(.+)', FileHandler), # serve files, images, etc |
| 49 | 49 | (r'/', RootHandler), # show list of topics |
| 50 | 50 | ] |
| ... | ... | @@ -200,6 +200,8 @@ class FileHandler(BaseHandler): |
| 200 | 200 | # respond to AJAX to get a JSON question |
| 201 | 201 | # ---------------------------------------------------------------------------- |
| 202 | 202 | class QuestionHandler(BaseHandler): |
| 203 | + SUPPORTED_METHODS = ['GET', 'POST'] | |
| 204 | + | |
| 203 | 205 | templates = { |
| 204 | 206 | 'checkbox': 'question-checkbox.html', |
| 205 | 207 | 'radio': 'question-radio.html', |
| ... | ... | @@ -218,20 +220,20 @@ class QuestionHandler(BaseHandler): |
| 218 | 220 | def get(self): |
| 219 | 221 | logging.debug('QuestionHandler.get()') |
| 220 | 222 | user = self.current_user |
| 223 | + q = self.learn.get_current_question(user) | |
| 224 | + question_html = self.render_string(self.templates[q['type']], | |
| 225 | + question=q, md=md_to_html) | |
| 221 | 226 | |
| 222 | - question = self.learn.get_current_question(user) | |
| 223 | - | |
| 224 | - question_html = self.render_string(self.templates[question['type']], | |
| 225 | - question=question, md=md_to_html) | |
| 226 | - | |
| 227 | - self.write({ | |
| 227 | + response = { | |
| 228 | 228 | 'method': 'new_question', |
| 229 | 229 | 'params': { |
| 230 | + 'type': q['type'], | |
| 230 | 231 | 'question': tornado.escape.to_unicode(question_html), |
| 231 | 232 | 'progress': self.learn.get_student_progress(user), |
| 232 | - 'tries': question['tries'], | |
| 233 | + 'tries': q['tries'], | |
| 233 | 234 | }, |
| 234 | - }) | |
| 235 | + } | |
| 236 | + self.write(response) | |
| 235 | 237 | |
| 236 | 238 | # --- post answer, returns what to do next: shake, new_question, finished |
| 237 | 239 | @tornado.web.authenticated |
| ... | ... | @@ -253,57 +255,72 @@ class QuestionHandler(BaseHandler): |
| 253 | 255 | # and get corrected question |
| 254 | 256 | q, action = await self.learn.check_answer(user, answer) |
| 255 | 257 | |
| 256 | - # get next question (same, new or None) | |
| 257 | - question = self.learn.get_current_question(user) | |
| 258 | + print(action) | |
| 258 | 259 | |
| 259 | 260 | if action == 'try_again': |
| 260 | 261 | comments_html = self.render_string('comments.html', |
| 261 | - comments=question['comments'], md=md_to_html) | |
| 262 | - self.write({ | |
| 263 | - 'method': 'try_again', # FIXME js | |
| 262 | + comments=q['comments'], md=md_to_html) | |
| 263 | + | |
| 264 | + response = { | |
| 265 | + 'method': 'try_again', | |
| 264 | 266 | 'params': { |
| 265 | 267 | 'progress': self.learn.get_student_progress(user), |
| 266 | 268 | 'comments': tornado.escape.to_unicode(comments_html), # FIXME |
| 267 | - 'tries': question['tries'], | |
| 269 | + 'tries': q['tries'], | |
| 268 | 270 | } |
| 269 | - }) | |
| 270 | - | |
| 271 | - # if action == 'wrong': | |
| 272 | - # comments_html = self.render_string('comments.html', | |
| 273 | - # comments=question['comments'], md=md_to_html) | |
| 274 | - # template = self.templates[question['type']] | |
| 275 | - # question_html = self.render_string(template, question=question, md=md_to_html) | |
| 276 | - # self.write({ | |
| 277 | - # 'method': 'wrong', # FIXME js | |
| 278 | - # 'params': { | |
| 279 | - # 'question': tornado.escape.to_unicode(question_html), | |
| 280 | - # 'progress': self.learn.get_student_progress(user), | |
| 281 | - # 'comments': tornado.escape.to_unicode(comments_html), # FIXME | |
| 282 | - # 'tries': question['tries'], | |
| 283 | - # } | |
| 284 | - # }) | |
| 271 | + } | |
| 272 | + print(response) | |
| 273 | + self.write(response) | |
| 285 | 274 | |
| 286 | - elif action == 'new_question': # get next question in the topic | |
| 287 | - template = self.templates[question['type']] | |
| 288 | - question_html = self.render_string(template, | |
| 289 | - question=question, md=md_to_html) | |
| 290 | - self.write({ | |
| 291 | - 'method': 'new_question', | |
| 275 | + elif action == 'wrong': # no more tries | |
| 276 | + comments_html = self.render_string('comments.html', | |
| 277 | + comments=q['comments'], md=md_to_html) | |
| 278 | + solution_html = self.render_string('solution.html', | |
| 279 | + solution=q['solution'], md=md_to_html) | |
| 280 | + | |
| 281 | + # template = self.templates[question['type']] | |
| 282 | + # question_html = self.render_string(template, question=question, md=md_to_html) | |
| 283 | + response = { | |
| 284 | + 'method': 'wrong', # FIXME js | |
| 292 | 285 | 'params': { |
| 293 | - 'question': tornado.escape.to_unicode(question_html), | |
| 286 | + # 'question': tornado.escape.to_unicode(question_html), | |
| 294 | 287 | 'progress': self.learn.get_student_progress(user), |
| 295 | - 'tries': question['tries'], | |
| 288 | + 'comments': tornado.escape.to_unicode(comments_html), # FIXME | |
| 289 | + 'solution': tornado.escape.to_unicode(solution_html), # FIXME | |
| 290 | + 'tries': q['tries'], | |
| 296 | 291 | } |
| 297 | - }) | |
| 292 | + } | |
| 293 | + print(response) | |
| 294 | + self.write(response) | |
| 295 | + | |
| 296 | + elif action == 'new_question': # get next question in the topic | |
| 297 | + self.get() | |
| 298 | + # question = self.learn.get_current_question(user) | |
| 299 | + | |
| 300 | + # template = self.templates[question['type']] | |
| 301 | + # question_html = self.render_string(template, | |
| 302 | + # question=question, md=md_to_html) | |
| 303 | + # response = { | |
| 304 | + # 'method': 'new_question', | |
| 305 | + # 'params': { | |
| 306 | + # 'type': question['type'], | |
| 307 | + # 'question': tornado.escape.to_unicode(question_html), | |
| 308 | + # 'progress': self.learn.get_student_progress(user), | |
| 309 | + # 'tries': question['tries'], | |
| 310 | + # } | |
| 311 | + # } | |
| 312 | + # print(response) | |
| 313 | + # self.write(response) | |
| 298 | 314 | |
| 299 | 315 | elif action == 'finished_topic': # right answer, finished topic |
| 300 | 316 | finished_topic_html = self.render_string('finished_topic.html') |
| 301 | - self.write({ | |
| 317 | + response = { | |
| 302 | 318 | 'method': 'finished_topic', |
| 303 | 319 | 'params': { |
| 304 | 320 | 'question': tornado.escape.to_unicode(finished_topic_html) |
| 305 | 321 | } |
| 306 | - }) | |
| 322 | + } | |
| 323 | + self.write(response) | |
| 307 | 324 | |
| 308 | 325 | else: |
| 309 | 326 | logger.error(f'Unknown action {action}') | ... | ... |
static/js/topic.js
| ... | ... | @@ -8,56 +8,76 @@ $.fn.extend({ |
| 8 | 8 | }); |
| 9 | 9 | |
| 10 | 10 | |
| 11 | -function new_question(question, tries, progress) { | |
| 11 | +function new_question(type, question, tries, progress) { | |
| 12 | + console.log("new_question " + type); | |
| 13 | + | |
| 12 | 14 | $("#question_div").html(question); |
| 13 | 15 | $("#comments").html(""); |
| 16 | + $("#solution").html(""); | |
| 17 | + if (type == "info") { | |
| 18 | + $("#submit").html("Continuar"); | |
| 19 | + } | |
| 20 | + else { | |
| 21 | + $("#submit").html("Responder"); | |
| 22 | + } | |
| 23 | + $("#submit").off(); | |
| 24 | + $("#submit").click(postAnswer); | |
| 25 | + | |
| 14 | 26 | $("#tries").html(tries); |
| 15 | 27 | $('#topic_progress').css('width', (100*progress)+'%').attr('aria-valuenow', 100*progress); |
| 16 | 28 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,"question_div"]); |
| 29 | + | |
| 17 | 30 | $('#question_div').animateCSS('bounceInDown'); |
| 18 | 31 | |
| 19 | - // enable shift+enter to submit and tab to spaces conversion | |
| 20 | - $("input:text, input:radio, input:checkbox").keydown(function (e) { | |
| 21 | - if (e.keyCode == 13) { | |
| 22 | - e.preventDefault(); | |
| 23 | - if (e.shiftKey) postQuestion(); | |
| 24 | - return false; | |
| 25 | - }}); | |
| 32 | + // enable shift+enter to submit | |
| 33 | + // $("input:text, input:radio, input:checkbox").keydown(function (e) { | |
| 34 | + // if (e.keyCode == 13) { | |
| 35 | + // e.preventDefault(); | |
| 36 | + // if (e.shiftKey) postQuestion(); | |
| 37 | + // return false; | |
| 38 | + // }}); | |
| 26 | 39 | } |
| 27 | 40 | |
| 41 | + | |
| 42 | + | |
| 28 | 43 | // updates question according to the response given by the server |
| 29 | 44 | function updateQuestion(response){ |
| 45 | + console.log('updateQuestion '+response["method"]); | |
| 46 | + | |
| 47 | + var method = response["method"]; | |
| 48 | + var params = response["params"]; | |
| 49 | + | |
| 30 | 50 | |
| 31 | - switch (response["method"]) { | |
| 51 | + switch (method) { | |
| 32 | 52 | case "new_question": |
| 33 | - params = response["params"]; | |
| 34 | - new_question(params["question"], params["tries"], params["progress"]); | |
| 53 | + console.log(params["type"]); | |
| 54 | + new_question(params["type"], params["question"], params["tries"], params["progress"]); | |
| 35 | 55 | break; |
| 36 | 56 | |
| 37 | 57 | case "try_again": |
| 38 | - $('#topic_progress').css('width', (100*response["params"]["progress"])+'%').attr('aria-valuenow', 100*response["params"]["progress"]); | |
| 39 | 58 | $('#question_div').animateCSS('shake'); |
| 40 | - $('#comments').html(response['params']['comments']); | |
| 41 | - $("#tries").html(response["params"]["tries"]); | |
| 59 | + $('#topic_progress').css('width', (100*params["progress"])+'%').attr('aria-valuenow', 100*params["progress"]); | |
| 60 | + $("#tries").html(params["tries"]); | |
| 61 | + $('#comments').html(params['comments']); | |
| 42 | 62 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,"#comments"]); |
| 43 | 63 | break; |
| 44 | 64 | |
| 45 | - // case "wrong": | |
| 46 | - // $('#topic_progress').css('width', (100*response["params"]["progress"])+'%').attr('aria-valuenow', 100*response["params"]["progress"]); | |
| 47 | - // $('#question_div').animateCSS('shake'); | |
| 48 | - // $('#comments').html(response['params']['comments']); | |
| 49 | - // $("#tries").html(response["params"]["tries"]); | |
| 50 | - // MathJax.Hub.Queue(["Typeset",MathJax.Hub,"#comments"]); | |
| 51 | - | |
| 52 | - // // setTimeout(function(){ | |
| 53 | - // new_question(response["params"]["question"], response["params"]["tries"], response["params"]["progress"]); | |
| 54 | - // // }, 5000); | |
| 55 | - // break; | |
| 56 | - | |
| 57 | - | |
| 65 | + case "wrong": | |
| 66 | + $('#question_div').animateCSS('shake'); | |
| 67 | + $('#topic_progress').css('width', (100*params["progress"])+'%').attr('aria-valuenow', 100*params["progress"]); | |
| 68 | + $("#tries").html(params["tries"]); | |
| 69 | + $('#comments').html(params['comments']); | |
| 70 | + MathJax.Hub.Queue(["Typeset", MathJax.Hub, "#comments"]); | |
| 71 | + $('#solution').html(params['solution']); | |
| 72 | + MathJax.Hub.Queue(["Typeset", MathJax.Hub, "#solution"]); | |
| 73 | + $("fieldset").attr("disabled", "disabled"); | |
| 74 | + $("#submit").html("Continuar"); | |
| 75 | + $("#submit").off(); | |
| 76 | + $("#submit").click(getQuestion); | |
| 77 | + break; | |
| 58 | 78 | |
| 59 | 79 | case "finished_topic": |
| 60 | - $('#submit').css("visibility", "hidden"); | |
| 80 | + $('#submit').hide(); //css("visibility", "hidden"); | |
| 61 | 81 | $("#content").html(response["params"]["question"]); |
| 62 | 82 | $('#topic_progress').css('width', '100%').attr('aria-valuenow', 100); |
| 63 | 83 | $("#content").animateCSS('tada'); |
| ... | ... | @@ -68,6 +88,8 @@ function updateQuestion(response){ |
| 68 | 88 | |
| 69 | 89 | // Get current question |
| 70 | 90 | function getQuestion() { |
| 91 | + console.log("getQuestion"); | |
| 92 | + | |
| 71 | 93 | $.ajax({ |
| 72 | 94 | type: "GET", |
| 73 | 95 | url: "/question", |
| ... | ... | @@ -80,7 +102,9 @@ function getQuestion() { |
| 80 | 102 | // Send answer and receive a response. |
| 81 | 103 | // The response can be a new_question or a shake if the answer is wrong, which |
| 82 | 104 | // is then passed to updateQuestion() |
| 83 | -function postQuestion() { | |
| 105 | +function postAnswer() { | |
| 106 | + console.log("postAnswer"); | |
| 107 | + | |
| 84 | 108 | if (typeof editor === 'object') |
| 85 | 109 | editor.save(); |
| 86 | 110 | |
| ... | ... | @@ -94,7 +118,8 @@ function postQuestion() { |
| 94 | 118 | }); |
| 95 | 119 | } |
| 96 | 120 | |
| 121 | + | |
| 97 | 122 | $(document).ready(function() { |
| 98 | 123 | getQuestion(); |
| 99 | - $("#submit").click(postQuestion); | |
| 124 | + $("#submit").click(postAnswer); | |
| 100 | 125 | }); | ... | ... |
templates/comments.html
templates/topic.html
| ... | ... | @@ -79,13 +79,14 @@ |
| 79 | 79 | </form> |
| 80 | 80 | |
| 81 | 81 | <div id="comments"></div> |
| 82 | + <div id="solution"></div> | |
| 82 | 83 | |
| 83 | 84 | </div> |
| 84 | 85 | </div> |
| 85 | 86 | |
| 86 | 87 | <footer class="footer"> |
| 87 | 88 | <div class="container"> |
| 88 | - <button class="btn btn-primary btn-lg btn-block my-3" id="submit" data-toggle="tooltip" data-placement="right" title="Shift-Enter">Continuar</button> | |
| 89 | + <button class="btn btn-primary btn-lg btn-block my-3" id="submit" data-toggle="tooltip" data-placement="right" title="Shift-Enter">Responder</button> | |
| 89 | 90 | </div> |
| 90 | 91 | </footer> |
| 91 | 92 | ... | ... |