Commit cd56848f1c40fdd4c91399b1ed666fe11436c8da
1 parent
526721fd
Exists in
master
and in
1 other branch
- review is working.
- fixed markdown rendering in questions.
Showing
20 changed files
with
172 additions
and
98 deletions
Show diff stats
BUGS.md
| 1 | 1 | |
| 2 | 2 | # BUGS |
| 3 | 3 | |
| 4 | +- markdown no teste nao funciona | |
| 4 | 5 | - numeracao das perguntas do teste esta a contar com paineis informativos... |
| 5 | 6 | - servir imagens das perguntas |
| 6 | -- review de um teste nao funciona (hardcoded...) | |
| 7 | -- testar opcao --allow-all | |
| 8 | 7 | - como alterar configuracao para mostrar logs de debug? |
| 9 | 8 | - hints nao funciona |
| 10 | 9 | - uniformizar question.py com a de aprendizations... |
| ... | ... | @@ -14,6 +13,14 @@ |
| 14 | 13 | |
| 15 | 14 | # TODO |
| 16 | 15 | |
| 16 | +- mathjax-node: | |
| 17 | + sudo pkg install node npm | |
| 18 | + npm install mathjax-node mathjax-node-cli # pacotes em ~/node_modules | |
| 19 | + node_modules/mathjax-node-cli/bin/tex2svg '\sqrt{x}' | |
| 20 | + usar isto para gerar svg que passa a fazer parte do texto da pergunta (markdown suporta tags svg?) | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 17 | 24 | - Gerar pdf's com todos os testes no final (pdfkit). |
| 18 | 25 | - manter registo dos unfocus durante o teste e de qual a pergunta visivel nesse momento |
| 19 | 26 | |
| ... | ... | @@ -31,6 +38,7 @@ |
| 31 | 38 | |
| 32 | 39 | # FIXED |
| 33 | 40 | |
| 41 | +- review de um teste nao funciona (hardcoded...) | |
| 34 | 42 | - testar SSL |
| 35 | 43 | - text-numeric não está a gerar a pergunta. faltam templates? |
| 36 | 44 | - testar perguntas warning/warn | ... | ... |
demo/questions/questions-tutorial.yaml
| ... | ... | @@ -2,19 +2,41 @@ |
| 2 | 2 | ref: tut-information |
| 3 | 3 | type: information |
| 4 | 4 | title: information (ou info) |
| 5 | - text: Texto informativo. Não conta para avaliação. | |
| 5 | + text: | | |
| 6 | + Texto informativo. Não conta para avaliação. | |
| 7 | + | |
| 8 | + $$ p(x) = \frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{(x-\mu)^2}{2\sigma^2}} $$ | |
| 6 | 9 | # --------------------------------------------------------------------------- |
| 7 | 10 | - |
| 8 | 11 | ref: tut-success |
| 9 | 12 | type: success |
| 10 | 13 | title: success |
| 11 | - text: Texto de positivo (sucesso). Não conta para avaliação. | |
| 14 | + text: | | |
| 15 | + Texto de positivo (sucesso). Não conta para avaliação. | |
| 16 | + | |
| 17 | + ```C | |
| 18 | + int main() { | |
| 19 | + printf("Hello world!"); | |
| 20 | + return 0; // comentario | |
| 21 | + } | |
| 22 | + ``` | |
| 23 | + | |
| 24 | + Inline `code`. | |
| 25 | + | |
| 12 | 26 | # --------------------------------------------------------------------------- |
| 13 | 27 | - |
| 14 | 28 | ref: tut-warning |
| 15 | 29 | type: warning |
| 16 | 30 | title: warning (ou warn) |
| 17 | - text: Texto de aviso. Não conta para avaliação. | |
| 31 | + text: | | |
| 32 | + Texto de aviso. Não conta para avaliação. | |
| 33 | + | |
| 34 | + Left | Center | Right | |
| 35 | + -----------------|:-------------:|----------: | |
| 36 | + $\sin(x^2)$ | *hello* | $1600.00 | |
| 37 | + $\frac{1}{2\pi}$ | **world** | $12.50 | |
| 38 | + $\sqrt{\pi}$ | `code` | $1.99 | |
| 39 | + | |
| 18 | 40 | # ---------------------------------------------------------------------------- |
| 19 | 41 | - |
| 20 | 42 | ref: tut-alert |
| ... | ... | @@ -48,7 +70,7 @@ |
| 48 | 70 | - Opção 3 (sim) |
| 49 | 71 | correct: [1,-1,-1,1] |
| 50 | 72 | # opcionais e valores por defeito |
| 51 | - shuffle: True | |
| 73 | + shuffle: True | |
| 52 | 74 | # ---------------------------------------------------------------------------- |
| 53 | 75 | - |
| 54 | 76 | ref: tut-text |
| ... | ... | @@ -82,8 +104,8 @@ |
| 82 | 104 | type: textarea |
| 83 | 105 | title: textarea |
| 84 | 106 | text: | |
| 85 | - Resposta num bloco de texto que pode ser usado para introduzir código. | |
| 86 | - A resposta é avaliada por um programa externo. | |
| 107 | + Resposta num bloco de texto que pode ser usado para introduzir código. | |
| 108 | + A resposta é avaliada por um programa externo. | |
| 87 | 109 | O programa externo, recebe a resposta no stdin e devolve a classificação no stdout. |
| 88 | 110 | Neste exemplo, o programa de avaliação verifica se a resposta contém as três palavras red, green e blue. |
| 89 | 111 | correct: correct/correct-question.py | ... | ... |
demo/questions/questions.yaml
| ... | ... | @@ -70,7 +70,7 @@ |
| 70 | 70 | # --------------------------------------------------------------------------- |
| 71 | 71 | - |
| 72 | 72 | ref: fractions |
| 73 | - type: text-numeric | |
| 73 | + type: numeric-interval | |
| 74 | 74 | text: Quanto é 1/4? |
| 75 | 75 | correct: [0.249, 0.251] |
| 76 | 76 | # --------------------------------------------------------------------------- | ... | ... |
serve.py
| ... | ... | @@ -163,7 +163,7 @@ class TestHandler(BaseHandler): |
| 163 | 163 | |
| 164 | 164 | # --- REVIEW ------------------------------------------------------------- |
| 165 | 165 | class ReviewHandler(BaseHandler): |
| 166 | - templates = { | |
| 166 | + _templates = { | |
| 167 | 167 | 'radio': 'review-question-radio.html', |
| 168 | 168 | 'checkbox': 'review-question-checkbox.html', |
| 169 | 169 | 'text': 'review-question-text.html', |
| ... | ... | @@ -181,12 +181,13 @@ class ReviewHandler(BaseHandler): |
| 181 | 181 | |
| 182 | 182 | @tornado.web.authenticated |
| 183 | 183 | def get(self): |
| 184 | - test_id=45 # FIXME | |
| 185 | - | |
| 186 | 184 | uid = self.current_user |
| 187 | 185 | if uid != '0': |
| 188 | 186 | self.redirect('/') # FIXME 404 not found? |
| 189 | 187 | |
| 188 | + test_id = self.get_query_argument('test_id', None) | |
| 189 | + # FIXME if test_id does not exist... | |
| 190 | + | |
| 190 | 191 | fname = self.testapp.get_json_filename_of_test(test_id) |
| 191 | 192 | try: |
| 192 | 193 | f = open(path.expanduser(fname)) |
| ... | ... | @@ -197,7 +198,7 @@ class ReviewHandler(BaseHandler): |
| 197 | 198 | else: |
| 198 | 199 | with f: |
| 199 | 200 | t = json.load(f) |
| 200 | - self.render('review.html', t=t, md=md_to_html_review, templ=self.templates) | |
| 201 | + self.render('review.html', t=t, md=md_to_html_review, templ=self._templates) | |
| 201 | 202 | |
| 202 | 203 | |
| 203 | 204 | # @cherrypy.expose | ... | ... |
templates/grade.html
| ... | ... | @@ -16,7 +16,7 @@ |
| 16 | 16 | <!-- ===================================================================== --> |
| 17 | 17 | <body> |
| 18 | 18 | |
| 19 | -<nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark"> | |
| 19 | +<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-dark"> | |
| 20 | 20 | <a class="navbar-brand" href="#">{{t['title']}}</a> |
| 21 | 21 | <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation"> |
| 22 | 22 | <span class="navbar-toggler-icon"></span> | ... | ... |
templates/question-alert.html
templates/question-checkbox.html
| ... | ... | @@ -4,13 +4,12 @@ |
| 4 | 4 | {% block answer %} |
| 5 | 5 | <fieldset data-role="controlgroup"> |
| 6 | 6 | <div class="list-group"> |
| 7 | - {% for n, opt in enumerate(question['options']) %} | |
| 7 | + {% for n, opt in enumerate(q['options']) %} | |
| 8 | 8 | <a class="list-group-item"> |
| 9 | 9 | <input type="checkbox" id="{{i}}:{{n}}" name="{{i}}" value="{{n}}"> |
| 10 | - <label for="{{n}}">{{ md(opt, question['ref'], question['files']) }}</label> | |
| 10 | + <label for="{{n}}">{{ md(opt, q['ref'], q['files']) }}</label> | |
| 11 | 11 | </a> |
| 12 | 12 | {% end %} |
| 13 | 13 | </div> |
| 14 | 14 | </fieldset> |
| 15 | -<input type="hidden" name="question_ref" value="{{ question['ref'] }}"> | |
| 16 | 15 | {% end %} |
| 17 | 16 | \ No newline at end of file | ... | ... |
templates/question-information.html
| ... | ... | @@ -3,10 +3,10 @@ |
| 3 | 3 | |
| 4 | 4 | <div class="alert alert-info border-info" role="alert"> |
| 5 | 5 | <h3> |
| 6 | - {{ question['title'] }} | |
| 6 | + {{ q['title'] }} | |
| 7 | 7 | </h3> |
| 8 | 8 | |
| 9 | 9 | <div id="text"> |
| 10 | - {{ md(question['text']) }} | |
| 10 | + {{ md(q['text'], q) }} | |
| 11 | 11 | </div> |
| 12 | 12 | </div> |
| 13 | 13 | \ No newline at end of file | ... | ... |
templates/question-radio.html
| ... | ... | @@ -4,10 +4,10 @@ |
| 4 | 4 | {% block answer %} |
| 5 | 5 | <fieldset data-role="controlgroup"> |
| 6 | 6 | <div class="list-group"> |
| 7 | - {% for n, opt in enumerate(question['options']) %} | |
| 7 | + {% for n, opt in enumerate(q['options']) %} | |
| 8 | 8 | <a class="list-group-item"> |
| 9 | 9 | <input type="radio" id="{{i}}:{{n}}" name="{{i}}" value="{{n}}"> |
| 10 | - <label for="{{n}}">{{ md(opt, question['ref'], question['files']) }}</label> | |
| 10 | + <label for="{{n}}">{{ md(opt, q['ref'], q['files']) }}</label> | |
| 11 | 11 | </a> |
| 12 | 12 | {% end %} |
| 13 | 13 | </div> | ... | ... |
templates/question-success.html
templates/question-textarea.html
| 1 | 1 | {% extends "question.html" %} |
| 2 | 2 | |
| 3 | 3 | {% block answer %} |
| 4 | - | |
| 5 | -<textarea class="form-control" rows="{{ question['lines'] }}" name="{{i}}">{{ question['answer'] or '' }}</textarea><br /> | |
| 6 | -<input type="hidden" name="question_ref" value="{{ question['ref'] }}"> | |
| 7 | - | |
| 4 | +<textarea class="form-control" rows="{{q['lines']}}" name="{{i}}">{{q['answer'] or ''}}</textarea><br /> | |
| 8 | 5 | {% end %} | ... | ... |
templates/question-warning.html
templates/question.html
| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | {% block question %} |
| 4 | 4 | <div class="card border-dark mb-3"> |
| 5 | 5 | <h5 class="card-header text-white bg-dark"> |
| 6 | - {{ i+1 }}. {{ question['title'] }} | |
| 6 | + {{ i+1 }}. {{ q['title'] }} | |
| 7 | 7 | <div class="pull-right"> |
| 8 | 8 | <small>Classificar </small> |
| 9 | 9 | <input type="checkbox" class="question_disabler" data-size="mini" name="answered-{{i}}" id="answered-{{i}}" checked=""> |
| ... | ... | @@ -11,14 +11,14 @@ |
| 11 | 11 | </h5> |
| 12 | 12 | <div class="card-body"> |
| 13 | 13 | <div id="text"> |
| 14 | - {{ question['text'] }} | |
| 14 | + {{ md(q['text'], md) }} | |
| 15 | 15 | </div> |
| 16 | 16 | |
| 17 | 17 | {% block answer %}{% end %} |
| 18 | 18 | |
| 19 | 19 | <p class="text-right"> |
| 20 | 20 | <small> |
| 21 | - (Cotação: {{ round(question['points'], 2) }} pontos) | |
| 21 | + (Cotação: {{ round(q['points'], 2) }} pontos) | |
| 22 | 22 | </small> |
| 23 | 23 | </p> |
| 24 | 24 | ... | ... |
templates/review-question-checkbox.html
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | {% if q['correct'][n] > 0 %} |
| 12 | 12 | <div class="text-right text-success"> |
| 13 | 13 | <i class="fa fa-check" aria-hidden="true"></i> |
| 14 | - </div> | |
| 14 | + </div> | |
| 15 | 15 | {% else %} |
| 16 | 16 | <div class="text-right text-danger"> |
| 17 | 17 | <i class="fa fa-close" aria-hidden="true"></i> |
| ... | ... | @@ -19,9 +19,8 @@ |
| 19 | 19 | {% end %} |
| 20 | 20 | {% else %} |
| 21 | 21 | {{ md('<i class="fa fa-square-o" aria-hidden="true"></i> ' + opt, q) }} |
| 22 | - | |
| 23 | 22 | {% if q['correct'][n] > 0 %} |
| 24 | - <div class="text-right text-info"> | |
| 23 | + <div class="text-right text-danger"> | |
| 25 | 24 | <i class="fa fa-close" aria-hidden="true"></i> |
| 26 | 25 | </div> |
| 27 | 26 | {% elif q['correct'][n] < 0 %} | ... | ... |
templates/review-question-text.html
templates/review-question.html
| ... | ... | @@ -16,16 +16,16 @@ |
| 16 | 16 | </h5> |
| 17 | 17 | |
| 18 | 18 | <div class="card-body"> |
| 19 | - <div id="text"> | |
| 19 | + <p id="text"> | |
| 20 | 20 | {{ q['text'] }} |
| 21 | - </div> | |
| 21 | + </p> | |
| 22 | 22 | |
| 23 | 23 | {% block answer %}{% end %} |
| 24 | 24 | |
| 25 | 25 | {% if t['show_points'] %} |
| 26 | 26 | <p class="text-right"> |
| 27 | 27 | <small> |
| 28 | - (Cotação: {{ q['points'] }}) | |
| 28 | + (Cotação: {{ round(q['points'], 2) }}) | |
| 29 | 29 | </small> |
| 30 | 30 | </p> |
| 31 | 31 | {% end %} |
| ... | ... | @@ -43,14 +43,14 @@ |
| 43 | 43 | {% elif q['grade'] > 0.49 %} |
| 44 | 44 | <p class="text-warning"> |
| 45 | 45 | <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> |
| 46 | - {{ round(q['grade'] * q['points'], 2) }} | |
| 46 | + {{ round(q['grade'] * q['points'], 2) }} | |
| 47 | 47 | pontos<br> |
| 48 | 48 | {{ q['comments'] }} |
| 49 | 49 | </p> |
| 50 | 50 | {% else %} |
| 51 | 51 | <p class="text-danger"> |
| 52 | 52 | <i class="fa fa-thumbs-o-down" aria-hidden="true"></i> |
| 53 | - {{ round(q['grade'] * q['points'], 2) }} | |
| 53 | + {{ round(q['grade'] * q['points'], 2) }} | |
| 54 | 54 | pontos<br> |
| 55 | 55 | {{ q['comments'] }} |
| 56 | 56 | </p> | ... | ... |
templates/review.html
| ... | ... | @@ -27,32 +27,53 @@ |
| 27 | 27 | </head> |
| 28 | 28 | <!-- ===================================================================== --> |
| 29 | 29 | <body> |
| 30 | -<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-primary"> | |
| 30 | +<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-dark"> | |
| 31 | 31 | <a class="navbar-brand" href="#">Revisão de prova</a> |
| 32 | 32 | </nav> |
| 33 | 33 | <!-- ===================================================================== --> |
| 34 | 34 | <div class="container"> |
| 35 | - <div class="jumbotron"> | |
| 36 | - <big> | |
| 37 | - <dl class="dl-horizontal"> | |
| 38 | - <dt>Prova:</dt><dd>{{t['title']}}</dd> | |
| 39 | - <dt>Nome:</dt><dd>{{t['student']['name']}}</dd> | |
| 40 | - <dt>Número:</dt><dd>{{t['student']['number']}}</dd> | |
| 41 | - <dt>Início:</dt><dd>{{t['start_time'][:19]}}</dd> | |
| 42 | - <dt>Fim:</dt><dd>{{t['finish_time'][:19]}}</dd> | |
| 43 | - <dt>Nota:</dt> | |
| 44 | - <dd> | |
| 45 | - <span class="label label-primary">{{ t['grade'] }}</span> valores | |
| 46 | - {% if t['state'] == 'QUIT' %} | |
| 47 | - (DESISTÊNCIA) | |
| 48 | - {% end %} | |
| 49 | - </dd> | |
| 50 | - {% if t['comment'] != '' %} | |
| 51 | - <dt>Comentário:</dt><dd>{{ t['comment'] }}</dd> | |
| 52 | - {% end %} | |
| 53 | - </dl> | |
| 54 | - </big> | |
| 55 | - </div> | |
| 35 | + <div class="jumbotron"> | |
| 36 | + <h1 class="display-5">{{ t['title'] }}</h1> | |
| 37 | + {{ t.get('duration', '') }} | |
| 38 | + <hr> | |
| 39 | + | |
| 40 | + <h3> | |
| 41 | + <div class="row"> | |
| 42 | + <!-- <label for="nome" class="col-sm-1">Nome:</label> --> | |
| 43 | + <div class="col-sm-8" id="nome">{{t['student']['name']}}</div> | |
| 44 | + <label for="nome" class="col-sm-1">Nº.</label> | |
| 45 | + <div class="col-sm-3" id="numero">{{t['student']['number']}}</div> | |
| 46 | + </div> | |
| 47 | + </h3> | |
| 48 | + | |
| 49 | + <h5> | |
| 50 | + <div class="row"> | |
| 51 | + <label for="inicio" class="col-sm-2">Início:</label> | |
| 52 | + <div class="col-sm-10" id="inicio">{{t['start_time'][:19]}}</div> | |
| 53 | + </div> | |
| 54 | + <div class="row"> | |
| 55 | + <label for="fim" class="col-sm-2">Fim:</label> | |
| 56 | + <div class="col-sm-10" id="fim">{{t['finish_time'][:19]}}</div> | |
| 57 | + </div> | |
| 58 | + </h5> | |
| 59 | + <h3> | |
| 60 | + <div class="row"> | |
| 61 | + <label for="nota" class="col-sm-2">Nota:</label> | |
| 62 | + <div class="col-sm-10" id="nota"> | |
| 63 | + <span class="badge badge-primary">{{ t['grade'] }}</span> valores | |
| 64 | + {% if t['state'] == 'QUIT' %} | |
| 65 | + (DESISTÊNCIA) | |
| 66 | + {% end %} | |
| 67 | + </div> | |
| 68 | + </div> | |
| 69 | + {% if t['comment'] != '' %} | |
| 70 | + <div class="row"> | |
| 71 | + <label for="comentario" class="col-sm-2">Comentário:</label> | |
| 72 | + <div class="col-sm-10" id="comentario">{{ t['comment'] }}</div> | |
| 73 | + </div> | |
| 74 | + {% end %} | |
| 75 | + </h3> | |
| 76 | + </div> | |
| 56 | 77 | |
| 57 | 78 | {% for i, q in enumerate(t['questions']) %} |
| 58 | 79 | {% module Template(templ[q['type']], i=i, q=q, md=md, t=t) %} | ... | ... |
templates/test.html
| ... | ... | @@ -61,17 +61,28 @@ |
| 61 | 61 | </span> |
| 62 | 62 | </div> |
| 63 | 63 | </nav> |
| 64 | -<!-- ===================================================================== --> | |
| 65 | 64 | <div class="container"> |
| 66 | 65 | |
| 67 | 66 | <div class="jumbotron"> |
| 68 | 67 | <h1 class="display-5">{{ t['title'] }}</h1> |
| 69 | 68 | {{ t.get('duration', '') }} |
| 69 | + <hr> | |
| 70 | + | |
| 71 | + <h5> | |
| 72 | + <div class="row"> | |
| 73 | + <label for="inicio" class="col-sm-2">Início:</label> | |
| 74 | + <div class="col-sm-10" id="inicio">{{ str(t['start_time'].time())[:8]}}</div> | |
| 75 | + </div> | |
| 76 | + <div class="row"> | |
| 77 | + <label for="duracao" class="col-sm-2">Duração:</label> | |
| 78 | + <div class="col-sm-10" id="duracao">{{ t.get('duration', chr(8734)) }}</div> | |
| 79 | + </div> | |
| 80 | + </h5> | |
| 70 | 81 | </div> |
| 71 | 82 | |
| 72 | 83 | <form action="/test" method="post" id="test" autocomplete="off"> |
| 73 | 84 | {% for i, q in enumerate(t['questions']) %} |
| 74 | - {% module Template(templ[q['type']], i=i, question=q, md=md) %} | |
| 85 | + {% module Template(templ[q['type']], i=i, q=q, md=md) %} | |
| 75 | 86 | {% end %} |
| 76 | 87 | |
| 77 | 88 | <div class="form-row"> |
| ... | ... | @@ -84,47 +95,51 @@ |
| 84 | 95 | </div> |
| 85 | 96 | </form> |
| 86 | 97 | <hr> |
| 98 | +</div> <!-- container --> | |
| 87 | 99 | |
| 88 | - <!-- Modal de confirmacao submissao --> | |
| 89 | - <div class="modal fade" id="confirmar" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> | |
| 90 | - <div class="modal-dialog" role="document"> | |
| 91 | - <div class="modal-content"> | |
| 92 | - <div class="modal-header"> | |
| 93 | - <h4 class="modal-title">Deseja submeter o teste?</h4> | |
| 94 | - </div> | |
| 95 | - <div class="modal-body"> | |
| 96 | - O teste será enviado para classificação e já não poderá voltar atrás. | |
| 97 | - Antes de submeter, veja se respondeu a todas as questões e desactive as que não pretende classificar. | |
| 98 | - </div> | |
| 99 | - <div class="modal-footer"> | |
| 100 | - <button type="button" class="btn btn-danger btn-lg" data-dismiss="modal">Oops, NÃO!!!</button> | |
| 101 | - <button form="test" type="submit" class="btn btn-success btn-lg">Sim, submeter...</button> | |
| 102 | - </div> | |
| 103 | - </div> | |
| 100 | +<!-- ===================================================================== --> | |
| 101 | + | |
| 102 | +<!-- Modal de confirmacao submissao --> | |
| 103 | +<div class="modal fade" id="confirmar" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> | |
| 104 | + <div class="modal-dialog" role="document"> | |
| 105 | + <div class="modal-content"> | |
| 106 | + <div class="modal-header"> | |
| 107 | + <h4 class="modal-title">Deseja submeter o teste?</h4> | |
| 108 | + </div> | |
| 109 | + <div class="modal-body"> | |
| 110 | + O teste será enviado para classificação e já não poderá voltar atrás. | |
| 111 | + Antes de submeter, veja se respondeu a todas as questões e desactive as que não pretende classificar. | |
| 112 | + </div> | |
| 113 | + <div class="modal-footer"> | |
| 114 | + <button type="button" class="btn btn-danger btn-lg" data-dismiss="modal">Oops, NÃO!!!</button> | |
| 115 | + <button form="test" type="submit" class="btn btn-success btn-lg">Sim, submeter...</button> | |
| 104 | 116 | </div> |
| 105 | 117 | </div> |
| 118 | + </div> | |
| 119 | +</div> | |
| 106 | 120 | |
| 107 | - <!-- Modal de confirmacao sair --> | |
| 108 | - <div class="modal fade" id="sair" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> | |
| 109 | - <div class="modal-dialog" role="document"> | |
| 110 | - <div class="modal-content"> | |
| 111 | - <div class="modal-header"> | |
| 112 | - <h4 class="modal-title">Deseja desistir?</h4> | |
| 113 | - </div> | |
| 114 | - <div class="modal-body"> | |
| 115 | - Se desistir, será registada a desistência da prova e terá uma classificação de 0 valores. | |
| 116 | - </div> | |
| 117 | - <div class="modal-footer"> | |
| 118 | - <button type="button" class="btn btn-danger btn-lg" data-dismiss="modal">Não!</button> | |
| 119 | - <a href="/giveup" class="btn btn-success btn-lg" role="button">Sim, desisto</a> | |
| 120 | - </div> | |
| 121 | - </div> | |
| 121 | +<!-- Modal de confirmacao sair --> | |
| 122 | +<div class="modal fade" id="sair" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> | |
| 123 | + <div class="modal-dialog" role="document"> | |
| 124 | + <div class="modal-content"> | |
| 125 | + <div class="modal-header"> | |
| 126 | + <h4 class="modal-title">Deseja desistir?</h4> | |
| 127 | + </div> | |
| 128 | + <div class="modal-body"> | |
| 129 | + Se desistir, será registada a desistência da prova e terá uma classificação de 0 valores. | |
| 130 | + </div> | |
| 131 | + <div class="modal-footer"> | |
| 132 | + <button type="button" class="btn btn-danger btn-lg" data-dismiss="modal">Não!</button> | |
| 133 | + <a href="/giveup" class="btn btn-success btn-lg" role="button">Sim, desisto</a> | |
| 122 | 134 | </div> |
| 123 | 135 | </div> |
| 124 | - | |
| 136 | + </div> | |
| 125 | 137 | </div> |
| 126 | 138 | |
| 127 | 139 | |
| 140 | + | |
| 141 | +<!-- ===================================================================== --> | |
| 142 | + | |
| 128 | 143 | <!-- Scripts --> |
| 129 | 144 | <script src="/static/js/jquery.min.js"></script> |
| 130 | 145 | <script src="/static/popper/umd/popper.min.js"></script> | ... | ... |
test.py
| ... | ... | @@ -145,6 +145,7 @@ class TestFactory(dict): |
| 145 | 145 | test = [] |
| 146 | 146 | total_points = 0.0 |
| 147 | 147 | |
| 148 | + n = 1 | |
| 148 | 149 | for qq in self['questions']: |
| 149 | 150 | # generate Question() selected randomly from list of references |
| 150 | 151 | qref = random.choice(qq['ref']) |
| ... | ... | @@ -160,6 +161,8 @@ class TestFactory(dict): |
| 160 | 161 | q['points'] = qq.get('points', 0.0) |
| 161 | 162 | else: |
| 162 | 163 | q['points'] = qq.get('points', 1.0) |
| 164 | + q['number'] = n | |
| 165 | + n += 1 | |
| 163 | 166 | |
| 164 | 167 | total_points += q['points'] |
| 165 | 168 | test.append(q) | ... | ... |
tools.py
| ... | ... | @@ -58,6 +58,7 @@ def run_script(script, stdin='', timeout=5): |
| 58 | 58 | else: |
| 59 | 59 | return output |
| 60 | 60 | |
| 61 | +# --------------------------------------------------------------------------- | |
| 61 | 62 | def md_to_html(text, ref=None, files={}): |
| 62 | 63 | if ref is not None: |
| 63 | 64 | # given q['ref'] and q['files'] replaces references to files by a |
| ... | ... | @@ -72,6 +73,7 @@ def md_to_html(text, ref=None, files={}): |
| 72 | 73 | 'markdown.extensions.sane_lists' |
| 73 | 74 | ]) |
| 74 | 75 | |
| 76 | +# --------------------------------------------------------------------------- | |
| 75 | 77 | def md_to_html_review(text, q): |
| 76 | 78 | for k,f in q['files'].items(): |
| 77 | 79 | text = text.replace(k, '/absfile?name={}'.format(q['files'][k])) | ... | ... |