Commit ef9f327f796b63a6873f4170d0b1db691c2fd71e
1 parent
d1410958
Exists in
master
and in
1 other branch
- another version not working...
Showing
15 changed files
with
304 additions
and
120 deletions
Show diff stats
config/logger-debug.yaml
| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | +title: Example | |
| 2 | +database: students.db | |
| 3 | + | |
| 4 | +# path prefix applied to the topics | |
| 5 | +path: ./demo | |
| 6 | + | |
| 7 | +# Representation of the edges of the dependency graph. | |
| 8 | +# Example: A depends on B and C | |
| 9 | +# A: | |
| 10 | +# name: Topic A | |
| 11 | +# deps: | |
| 12 | +# - B | |
| 13 | +# - C | |
| 14 | +topics: | |
| 15 | + | |
| 16 | + # topic without dependencies | |
| 17 | + math: | |
| 18 | + name: Matemática | |
| 19 | + | |
| 20 | + # topic with one dependency | |
| 21 | + solar_system: | |
| 22 | + name: Solar system | |
| 23 | + deps: | |
| 24 | + - math | ... | ... |
| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | +#!/usr/bin/env python3 | |
| 2 | + | |
| 3 | +from random import randint | |
| 4 | +import sys | |
| 5 | + | |
| 6 | +arg = sys.stdin.read() # read arguments | |
| 7 | + | |
| 8 | +a,b = (int(n) for n in arg.split(',')) | |
| 9 | + | |
| 10 | +q = ''' | |
| 11 | +type: checkbox | |
| 12 | +text: | | |
| 13 | + Indique quais das seguintes adições resultam em overflow quando se considera a adição de números com sinal (complemento para 2) em registos de 8 bits. | |
| 14 | + | |
| 15 | + Os números foram gerados aleatoriamente no intervalo de {0} a {1}. | |
| 16 | +options: | |
| 17 | +'''.format(a,b) | |
| 18 | + | |
| 19 | +correct = [] | |
| 20 | +for i in range(5): | |
| 21 | + x = randint(a, b) | |
| 22 | + y = randint(a, b) | |
| 23 | + q += '- "`{} + {}`"\n'.format(x, y) | |
| 24 | + correct.append(1 if x + y > 127 else -1) | |
| 25 | + | |
| 26 | +q += 'correct: ' + str(correct) | |
| 27 | + | |
| 28 | +print(q) | ... | ... |
| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | +- | |
| 2 | + ref: prime_numbers | |
| 3 | + type: radio | |
| 4 | + title: Números primos | |
| 5 | + text: Qual dos seguintes números é primo? | |
| 6 | + options: | |
| 7 | + - 13 | |
| 8 | + - 12 | |
| 9 | + - 14 | |
| 10 | + - 1, a **unidade** | |
| 11 | + | |
| 12 | +# # --------------------------------------------------------------------------- | |
| 13 | +# - | |
| 14 | +# ref: distributive_property | |
| 15 | +# type: radio | |
| 16 | +# title: Propriedade distributiva | |
| 17 | +# text: | | |
| 18 | +# Qual das seguintes opções usa a propriedade distributiva para calcular $9\times 2 - 2\times 3$? | |
| 19 | +# options: | |
| 20 | +# - $2\times(9 - 3)$ | |
| 21 | +# - $18 - 6 = 12$ | |
| 22 | +# - $2\times 9 - 2\times 3$ | |
| 23 | +# - $2\times(9-2\times 3)$ | |
| 24 | + | |
| 25 | +# # --------------------------------------------------------------------------- | |
| 26 | +# - | |
| 27 | +# ref: math-expressions | |
| 28 | +# type: checkbox | |
| 29 | +# title: Expressões matemáticas | |
| 30 | +# text: Quais das seguintes expressões são verdadeiras? | |
| 31 | +# options: | |
| 32 | +# - $1 > 0$ | |
| 33 | +# - $\sqrt{3} > \sqrt{2}$ | |
| 34 | +# - $e^{i\pi} + 1 = 0$ | |
| 35 | +# - $\frac{\partial f(x,y)}{\partial z} = 1$ | |
| 36 | +# - $-1 > 1$ | |
| 37 | +# # how many points for each checkmark (normalized afterwards): | |
| 38 | +# correct: [1, 1, 1, -1, -1] | |
| 39 | + | |
| 40 | +# # --------------------------------------------------------------------------- | |
| 41 | +# - | |
| 42 | +# ref: overflow | |
| 43 | +# type: generator | |
| 44 | +# script: generate-overflow.py | |
| 45 | +# # opcional | |
| 46 | +# arg: "11,120" | |
| 47 | +# # the script should print a question dict in yaml format. | ... | ... |
| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | +#!/usr/bin/env python3 | |
| 2 | + | |
| 3 | +import re | |
| 4 | +import sys | |
| 5 | + | |
| 6 | +s = sys.stdin.read() | |
| 7 | + | |
| 8 | +# set of words converted to lowercase | |
| 9 | +answer = set(re.findall(r'[\w]+', s.lower())) | |
| 10 | +answer.difference_update({'e', 'a', 'planeta', 'planetas'}) # ignore these | |
| 11 | + | |
| 12 | +# correct set of colors | |
| 13 | +planets = set(['mercúrio', 'vénus', 'terra']) | |
| 14 | + | |
| 15 | +correct = set.intersection(answer, planets) # os que acertei | |
| 16 | +wrong = set.difference(answer, planets) # os que errei | |
| 17 | +# allnames = set.union(answer, planets) | |
| 18 | + | |
| 19 | +grade = (len(correct) - len(wrong)) / len(planets) | |
| 20 | + | |
| 21 | +out = f'grade: {grade}' | |
| 22 | + | |
| 23 | +if grade < 1.0: | |
| 24 | + out += '\ncomments: A resposta correcta é `Mercúrio, Vénus e Terra`.' | |
| 25 | + | |
| 26 | +print(out) | |
| 27 | +exit(0) | |
| 0 | 28 | \ No newline at end of file | ... | ... |
419 KB
| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | + | |
| 2 | +# --------------------------------------------------------------------------- | |
| 3 | +- | |
| 4 | + ref: solar-system | |
| 5 | + type: radio | |
| 6 | + title: Sistema solar | |
| 7 | + text: Qual é o maior planeta do Sistema Solar? | |
| 8 | + options: | |
| 9 | + - Mercúrio | |
| 10 | + - Marte | |
| 11 | + - Júpiter | |
| 12 | + - Têm todos o mesmo tamanho | |
| 13 | + # opcional | |
| 14 | + correct: 2 | |
| 15 | + shuffle: False | |
| 16 | + discount: True | |
| 17 | + | |
| 18 | +# --------------------------------------------------------------------------- | |
| 19 | +- | |
| 20 | + ref: home-planet | |
| 21 | + type: text | |
| 22 | + title: Sistema solar | |
| 23 | + text: O nosso planeta chama-se planeta... | |
| 24 | + correct: ['Terra', 'terra'] | |
| 25 | + # opcional | |
| 26 | + answer: Não é Marte... | |
| 27 | + | |
| 28 | +# --------------------------------------------------------------------------- | |
| 29 | +- | |
| 30 | + ref: saturn | |
| 31 | + type: text-regex | |
| 32 | + title: Sistema solar | |
| 33 | + text: O planeta do nosso sistema solar conhecido por ter aneis chama-se planeta... | |
| 34 | + correct: !regex '[Ss]aturno' | |
| 35 | + | |
| 36 | +# --------------------------------------------------------------------------- | |
| 37 | +- | |
| 38 | + ref: first_3_planets | |
| 39 | + type: textarea | |
| 40 | + title: Sistema solar | |
| 41 | + text: Escreva o nome dos três planetas mais próximos do Sol. (Exemplo `A, B e C`) | |
| 42 | + correct: correct-first_3_planets.py | |
| 43 | + # opcional | |
| 44 | + lines: 3 | |
| 45 | + timeout: 5 | ... | ... |
| ... | ... | @@ -0,0 +1,93 @@ |
| 1 | +# QFactory is a class that can generate question instances, e.g. by shuffling | |
| 2 | +# options, running a script to generate the question, etc. | |
| 3 | +# | |
| 4 | +# To generate an instance of a question we use the method generate() where | |
| 5 | +# the argument is the reference of the question we wish to produce. | |
| 6 | +# | |
| 7 | +# Example: | |
| 8 | +# | |
| 9 | +# # read question from file | |
| 10 | +# qdict = tools.load_yaml(filename) | |
| 11 | +# qfactory = QFactory(qdict) | |
| 12 | +# question = qfactory.generate() | |
| 13 | +# | |
| 14 | +# # experiment answering one question and correct it | |
| 15 | +# question.updateAnswer('42') # insert answer | |
| 16 | +# grade = question.correct() # correct answer | |
| 17 | + | |
| 18 | +# An instance of an actual question is an object that inherits from Question() | |
| 19 | +# | |
| 20 | +# Question - base class inherited by other classes | |
| 21 | +# QuestionInformation - not a question, just a box with content | |
| 22 | +# QuestionRadio - single choice from a list of options | |
| 23 | +# QuestionCheckbox - multiple choice, equivalent to multiple true/false | |
| 24 | +# QuestionText - line of text compared to a list of acceptable answers | |
| 25 | +# QuestionTextRegex - line of text matched against a regular expression | |
| 26 | +# QuestionTextArea - corrected by an external program | |
| 27 | +# QuestionNumericInterval - line of text parsed as a float | |
| 28 | + | |
| 29 | +# base | |
| 30 | +from os import path | |
| 31 | +import logging | |
| 32 | + | |
| 33 | +# project | |
| 34 | +from tools import run_script | |
| 35 | +from questions import QuestionInformation, QuestionRadio, QuestionCheckbox, QuestionText, QuestionTextRegex, QuestionTextArea, QuestionNumericInterval | |
| 36 | + | |
| 37 | +# setup logger for this module | |
| 38 | +logger = logging.getLogger(__name__) | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | +# =========================================================================== | |
| 43 | +# Question Factory | |
| 44 | +# =========================================================================== | |
| 45 | +class QFactory(object): | |
| 46 | + # Depending on the type of question, a different question class will be | |
| 47 | + # instantiated. All these classes derive from the base class `Question`. | |
| 48 | + _types = { | |
| 49 | + 'radio' : QuestionRadio, | |
| 50 | + 'checkbox' : QuestionCheckbox, | |
| 51 | + 'text' : QuestionText, | |
| 52 | + 'text-regex': QuestionTextRegex, | |
| 53 | + 'numeric-interval': QuestionNumericInterval, | |
| 54 | + 'textarea' : QuestionTextArea, | |
| 55 | + # -- informative panels -- | |
| 56 | + 'information': QuestionInformation, 'info': QuestionInformation, | |
| 57 | + 'warning' : QuestionInformation, 'warn': QuestionInformation, | |
| 58 | + 'alert' : QuestionInformation, | |
| 59 | + 'success' : QuestionInformation, | |
| 60 | + } | |
| 61 | + | |
| 62 | + def __init__(self, question_dict): | |
| 63 | + self.question = question_dict | |
| 64 | + | |
| 65 | + # ----------------------------------------------------------------------- | |
| 66 | + # Given a ref returns an instance of a descendent of Question(), | |
| 67 | + # i.e. a question object (radio, checkbox, ...). | |
| 68 | + # ----------------------------------------------------------------------- | |
| 69 | + def generate(self): | |
| 70 | + logger.debug(f'Generating "{self.question["ref"]}"') | |
| 71 | + # Shallow copy so that script generated questions will not replace | |
| 72 | + # the original generators | |
| 73 | + q = self.question.copy() | |
| 74 | + | |
| 75 | + # If question is of generator type, an external program will be run | |
| 76 | + # which will print a valid question in yaml format to stdout. This | |
| 77 | + # output is then yaml parsed into a dictionary `q`. | |
| 78 | + if q['type'] == 'generator': | |
| 79 | + logger.debug(f' \_ Running script "{q["script"]}"...') | |
| 80 | + q.setdefault('arg', '') # optional arguments will be sent to stdin | |
| 81 | + script = path.join(q['path'], q['script']) | |
| 82 | + out = run_script(script=script, stdin=q['arg']) | |
| 83 | + q.update(out) | |
| 84 | + | |
| 85 | + # Finally we create an instance of Question() | |
| 86 | + try: | |
| 87 | + qinstance = self._types[q['type']](q) # instance with correct class | |
| 88 | + except KeyError as e: | |
| 89 | + logger.error(f'Failed to generate question "{q["ref"]}"') | |
| 90 | + raise e | |
| 91 | + else: | |
| 92 | + return qinstance | |
| 93 | + | ... | ... |
knowledge.py
| ... | ... | @@ -86,11 +86,11 @@ class StudentKnowledge(object): |
| 86 | 86 | # current_question: the current question to be presented |
| 87 | 87 | # ------------------------------------------------------------------------ |
| 88 | 88 | def init_topic(self, topic=''): |
| 89 | - # self.unlock_topics() # FIXME needed? | |
| 89 | + logger.debug(f'StudentKnowledge.init_topic({topic})') | |
| 90 | 90 | |
| 91 | 91 | if not topic: |
| 92 | 92 | topic = self.recommended_topic() |
| 93 | - | |
| 93 | + print(f'recommended {topic}') | |
| 94 | 94 | |
| 95 | 95 | self.current_topic = topic |
| 96 | 96 | logger.info(f'Topic set to "{topic}"') |
| ... | ... | @@ -134,9 +134,11 @@ class StudentKnowledge(object): |
| 134 | 134 | |
| 135 | 135 | # if answer is wrong, keep same question and add a similar one at the end |
| 136 | 136 | else: |
| 137 | + print('failed') | |
| 137 | 138 | factory = self.deps.node[self.current_topic]['factory'] |
| 138 | 139 | self.questions.append(factory[q['ref']].generate()) |
| 139 | 140 | |
| 141 | + | |
| 140 | 142 | # returns answered and corrected question |
| 141 | 143 | return q |
| 142 | 144 | |
| ... | ... | @@ -154,10 +156,9 @@ class StudentKnowledge(object): |
| 154 | 156 | return self.current_topic |
| 155 | 157 | |
| 156 | 158 | # ------------------------------------------------------------------------ |
| 157 | - # Return list of tuples (topic, level). | |
| 158 | - # Levels are in the interval [0, 1] or None if the topic is locked. | |
| 159 | + # Return list of {ref: 'xpto', name: 'long name', leve: 0.5} | |
| 160 | + # Levels are in the interval [0, 1] if unlocked or None if locked. | |
| 159 | 161 | # Topics unlocked but not yet done have level 0.0. |
| 160 | - # Example: [('topic_A', 0.9), ('topic_B', None), ...] | |
| 161 | 162 | # ------------------------------------------------------------------------ |
| 162 | 163 | def get_knowledge_state(self): |
| 163 | 164 | return [{ |
| ... | ... | @@ -166,15 +167,6 @@ class StudentKnowledge(object): |
| 166 | 167 | 'level': self.state[ref]['level'] if ref in self.state else None |
| 167 | 168 | } for ref in self.topic_sequence ] |
| 168 | 169 | |
| 169 | - # ts = [] | |
| 170 | - # for ref in self.topic_sequence: | |
| 171 | - # ts.append({ | |
| 172 | - # 'ref': ref, | |
| 173 | - # 'name': self.deps.nodes[ref]['name'], | |
| 174 | - # 'level': self.state[ref]['level'] if ref in self.state else None | |
| 175 | - # }) | |
| 176 | - # return ts | |
| 177 | - | |
| 178 | 170 | # ------------------------------------------------------------------------ |
| 179 | 171 | def get_topic_progress(self): |
| 180 | 172 | return len(self.finished_questions) / (1 + len(self.finished_questions) + len(self.questions)) | ... | ... |
learnapp.py
| ... | ... | @@ -15,7 +15,7 @@ import yaml |
| 15 | 15 | # this project |
| 16 | 16 | from models import Student, Answer, Topic, StudentTopic |
| 17 | 17 | from knowledge import StudentKnowledge |
| 18 | -from questionfactory import QFactory | |
| 18 | +from factory import QFactory | |
| 19 | 19 | from tools import load_yaml |
| 20 | 20 | |
| 21 | 21 | # setup logger for this module | ... | ... |
questionfactory.py
| ... | ... | @@ -1,93 +0,0 @@ |
| 1 | -# QFactory is a class that can generate question instances, e.g. by shuffling | |
| 2 | -# options, running a script to generate the question, etc. | |
| 3 | -# | |
| 4 | -# To generate an instance of a question we use the method generate() where | |
| 5 | -# the argument is the reference of the question we wish to produce. | |
| 6 | -# | |
| 7 | -# Example: | |
| 8 | -# | |
| 9 | -# # read question from file | |
| 10 | -# qdict = tools.load_yaml(filename) | |
| 11 | -# qfactory = QFactory(qdict) | |
| 12 | -# question = qfactory.generate() | |
| 13 | -# | |
| 14 | -# # experiment answering one question and correct it | |
| 15 | -# question.updateAnswer('42') # insert answer | |
| 16 | -# grade = question.correct() # correct answer | |
| 17 | - | |
| 18 | -# An instance of an actual question is an object that inherits from Question() | |
| 19 | -# | |
| 20 | -# Question - base class inherited by other classes | |
| 21 | -# QuestionInformation - not a question, just a box with content | |
| 22 | -# QuestionRadio - single choice from a list of options | |
| 23 | -# QuestionCheckbox - multiple choice, equivalent to multiple true/false | |
| 24 | -# QuestionText - line of text compared to a list of acceptable answers | |
| 25 | -# QuestionTextRegex - line of text matched against a regular expression | |
| 26 | -# QuestionTextArea - corrected by an external program | |
| 27 | -# QuestionNumericInterval - line of text parsed as a float | |
| 28 | - | |
| 29 | -# base | |
| 30 | -from os import path | |
| 31 | -import logging | |
| 32 | - | |
| 33 | -# project | |
| 34 | -from tools import run_script | |
| 35 | -from questions import QuestionInformation, QuestionRadio, QuestionCheckbox, QuestionText, QuestionTextRegex, QuestionTextArea, QuestionNumericInterval | |
| 36 | - | |
| 37 | -# setup logger for this module | |
| 38 | -logger = logging.getLogger(__name__) | |
| 39 | - | |
| 40 | - | |
| 41 | - | |
| 42 | -# =========================================================================== | |
| 43 | -# Question Factory | |
| 44 | -# =========================================================================== | |
| 45 | -class QFactory(object): | |
| 46 | - # Depending on the type of question, a different question class will be | |
| 47 | - # instantiated. All these classes derive from the base class `Question`. | |
| 48 | - _types = { | |
| 49 | - 'radio' : QuestionRadio, | |
| 50 | - 'checkbox' : QuestionCheckbox, | |
| 51 | - 'text' : QuestionText, | |
| 52 | - 'text-regex': QuestionTextRegex, | |
| 53 | - 'numeric-interval': QuestionNumericInterval, | |
| 54 | - 'textarea' : QuestionTextArea, | |
| 55 | - # -- informative panels -- | |
| 56 | - 'information': QuestionInformation, 'info': QuestionInformation, | |
| 57 | - 'warning' : QuestionInformation, 'warn': QuestionInformation, | |
| 58 | - 'alert' : QuestionInformation, | |
| 59 | - 'success' : QuestionInformation, | |
| 60 | - } | |
| 61 | - | |
| 62 | - def __init__(self, question_dict): | |
| 63 | - self.question = question_dict | |
| 64 | - | |
| 65 | - # ----------------------------------------------------------------------- | |
| 66 | - # Given a ref returns an instance of a descendent of Question(), | |
| 67 | - # i.e. a question object (radio, checkbox, ...). | |
| 68 | - # ----------------------------------------------------------------------- | |
| 69 | - def generate(self): | |
| 70 | - logger.debug(f'Generating "{self.question["ref"]}"') | |
| 71 | - # Shallow copy so that script generated questions will not replace | |
| 72 | - # the original generators | |
| 73 | - q = self.question.copy() | |
| 74 | - | |
| 75 | - # If question is of generator type, an external program will be run | |
| 76 | - # which will print a valid question in yaml format to stdout. This | |
| 77 | - # output is then yaml parsed into a dictionary `q`. | |
| 78 | - if q['type'] == 'generator': | |
| 79 | - logger.debug(f' \_ Running script "{q["script"]}"...') | |
| 80 | - q.setdefault('arg', '') # optional arguments will be sent to stdin | |
| 81 | - script = path.join(q['path'], q['script']) | |
| 82 | - out = run_script(script=script, stdin=q['arg']) | |
| 83 | - q.update(out) | |
| 84 | - | |
| 85 | - # Finally we create an instance of Question() | |
| 86 | - try: | |
| 87 | - qinstance = self._types[q['type']](q) # instance with correct class | |
| 88 | - except KeyError as e: | |
| 89 | - logger.error(f'Failed to generate question "{q["ref"]}"') | |
| 90 | - raise e | |
| 91 | - else: | |
| 92 | - return qinstance | |
| 93 | - |
serve.py
| ... | ... | @@ -135,7 +135,6 @@ class TopicHandler(BaseHandler): |
| 135 | 135 | self.render('topic.html', |
| 136 | 136 | uid=uid, |
| 137 | 137 | name=self.learn.get_student_name(uid), |
| 138 | - # title=self.learn.get_title() | |
| 139 | 138 | ) |
| 140 | 139 | |
| 141 | 140 | |
| ... | ... | @@ -175,7 +174,7 @@ class QuestionHandler(BaseHandler): |
| 175 | 174 | } |
| 176 | 175 | |
| 177 | 176 | def new_question(self, user): |
| 178 | - | |
| 177 | + logger.debug(f'new_question({user})') | |
| 179 | 178 | # state = self.learn.get_student_state(user) # [{ref, name, level},...] |
| 180 | 179 | # current_topic = self.learn.get_student_topic(user) # str |
| 181 | 180 | |
| ... | ... | @@ -192,6 +191,7 @@ class QuestionHandler(BaseHandler): |
| 192 | 191 | } |
| 193 | 192 | |
| 194 | 193 | def wrong_answer(self, user): |
| 194 | + logger.debug(f'wrong_answer({user})') | |
| 195 | 195 | progress = self.learn.get_student_progress(user) # in the current topic |
| 196 | 196 | return { |
| 197 | 197 | 'method': 'shake', |
| ... | ... | @@ -201,6 +201,8 @@ class QuestionHandler(BaseHandler): |
| 201 | 201 | } |
| 202 | 202 | |
| 203 | 203 | def finished_topic(self, user): |
| 204 | + logger.debug(f'finished_topic({user})') | |
| 205 | + | |
| 204 | 206 | # state = self.learn.get_student_state(user) # all topics |
| 205 | 207 | # current_topic = self.learn.get_student_topic(uid) |
| 206 | 208 | |
| ... | ... | @@ -214,7 +216,7 @@ class QuestionHandler(BaseHandler): |
| 214 | 216 | |
| 215 | 217 | @tornado.web.authenticated |
| 216 | 218 | def get(self): |
| 217 | - logging.debug('QuestionHandler.get') | |
| 219 | + logging.debug('QuestionHandler.get()') | |
| 218 | 220 | user = self.current_user |
| 219 | 221 | |
| 220 | 222 | question = self.learn.get_student_question(user) |
| ... | ... | @@ -232,9 +234,10 @@ class QuestionHandler(BaseHandler): |
| 232 | 234 | # handles answer posted |
| 233 | 235 | @tornado.web.authenticated |
| 234 | 236 | def post(self): |
| 235 | - logging.debug('QuestionHandler.post') | |
| 237 | + logging.debug('QuestionHandler.post()') | |
| 236 | 238 | user = self.current_user |
| 237 | 239 | |
| 240 | + print(self.get_body_arguments()) | |
| 238 | 241 | # if self.learn.get_student_question(user) is None: |
| 239 | 242 | |
| 240 | 243 | answer = self.get_body_argument('answer') | ... | ... |
templates/question-text.html
| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | {% block answer %} |
| 4 | 4 | <fieldset data-role="controlgroup"> |
| 5 | 5 | {% if question['answer'] %} |
| 6 | - <input type="text" class="form-control" id="answer" name="answer" value="{{ question['answer'][0] }}" autofocus> | |
| 6 | + <input type="text" class="form-control" id="answer" name="answer" value="{{ question['answer'] }}" autofocus> | |
| 7 | 7 | {% else %} |
| 8 | 8 | <input type="text" class="form-control" id="answer" name="answer" value="" autofocus> |
| 9 | 9 | {% end %} | ... | ... |
templates/topic.html
| ... | ... | @@ -82,13 +82,15 @@ |
| 82 | 82 | |
| 83 | 83 | <div id="notifications"></div> |
| 84 | 84 | |
| 85 | - <form action="/question" method="post" id="question_form" autocomplete="off"> | |
| 86 | - {% module xsrf_form_html() %} | |
| 85 | + <div id="content"> | |
| 86 | + <form action="/question" method="post" id="question_form" autocomplete="off"> | |
| 87 | + {% module xsrf_form_html() %} | |
| 87 | 88 | |
| 88 | - <div id="question_div"></div> | |
| 89 | + <div id="question_div"></div> | |
| 89 | 90 | |
| 90 | - </form> | |
| 91 | - <button class="btn btn-primary" id="submit" data-toggle="tooltip" data-placement="right" title="Shift-Enter">Continuar</button> | |
| 91 | + </form> | |
| 92 | + <button class="btn btn-primary" id="submit" data-toggle="tooltip" data-placement="right" title="Shift-Enter">Continuar</button> | |
| 93 | + </div> | |
| 92 | 94 | </div> |
| 93 | 95 | |
| 94 | 96 | <!-- ===================================================================== --> |
| ... | ... | @@ -153,8 +155,8 @@ |
| 153 | 155 | |
| 154 | 156 | case "finished_topic": |
| 155 | 157 | $('#topic_progress').css('width', '100%').attr('aria-valuenow', 100); |
| 156 | - $("#container").html('<img src="/static/trophy.png" alt="trophy" class="img-fluid mx-auto my-5 d-block" width="25%">'); | |
| 157 | - $("#container").animateCSS('tada'); | |
| 158 | + $("#content").html('<img src="/static/trophy.png" alt="trophy" class="img-fluid mx-auto my-5 d-block" width="25%">'); | |
| 159 | + $("#content").animateCSS('tada'); | |
| 158 | 160 | setTimeout(function(){ window.location.replace('/'); }, 2000); |
| 159 | 161 | break; |
| 160 | 162 | } | ... | ... |