Commit bff14879306b6ad826a565933374eadf81bb5898

Authored by Miguel Barão
1 parent 6b619adb
Exists in master and in 1 other branch dev

- add support for courses.

- solution always shown.
- fixed image rendering: always left aligned as text.
- formulas are inserted with latex delimiters \(x\) and \[x\] for
  mathjax rendering.
1 1
2 # BUGS 2 # BUGS
3 3
  4 +- não suporta definition lists em markdown
4 - double click submits twice. 5 - double click submits twice.
5 - nao esta a seguir o max_tries definido no ficheiro de dependencias. 6 - nao esta a seguir o max_tries definido no ficheiro de dependencias.
6 - obter rankings por curso GET course=course_id 7 - obter rankings por curso GET course=course_id
aprendizations/learnapp.py
@@ -335,7 +335,7 @@ class LearnApp(object): @@ -335,7 +335,7 @@ class LearnApp(object):
335 default_shuffle_questions: bool = config.get('shuffle_questions', True) 335 default_shuffle_questions: bool = config.get('shuffle_questions', True)
336 default_choose: int = config.get('choose', 9999) 336 default_choose: int = config.get('choose', 9999)
337 default_forgetting_factor: float = config.get('forgetting_factor', 1.0) 337 default_forgetting_factor: float = config.get('forgetting_factor', 1.0)
338 - default_maxtries: int = config.get('max_tries', 3) 338 + default_maxtries: int = config.get('max_tries', 1)
339 default_append_wrong: bool = config.get('append_wrong', True) 339 default_append_wrong: bool = config.get('append_wrong', True)
340 default_min_level: float = config.get('min_level', 0.01) # to unlock 340 default_min_level: float = config.get('min_level', 0.01) # to unlock
341 341
aprendizations/templates/courses.html
1 {% autoescape %} 1 {% autoescape %}
2 -  
3 <!doctype html> 2 <!doctype html>
4 <html lang="pt-PT"> 3 <html lang="pt-PT">
5 -<head>  
6 - <title>{{appname}}</title>  
7 - <link rel="icon" href="/static/favicon.ico">  
8 -  
9 - <meta charset="utf-8">  
10 - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">  
11 - <meta name="author" content="Miguel Barão">  
12 -  
13 -<!-- Styles -->  
14 - <link rel="stylesheet" href="/static/mdbootstrap/css/bootstrap.min.css">  
15 - <link rel="stylesheet" href="/static/mdbootstrap/css/mdb.min.css">  
16 - <link rel="stylesheet" href="/static/css/maintopics.css">  
17 -  
18 -<!-- Scripts -->  
19 - <script defer src="/static/mdbootstrap/js/jquery-3.4.1.min.js"></script>  
20 - <script defer src="/static/mdbootstrap/js/popper.min.js"></script>  
21 - <script defer src="/static/mdbootstrap/js/bootstrap.min.js"></script>  
22 - <script defer src="/static/mdbootstrap/js/mdb.min.js"></script>  
23 - <script defer src="/static/fontawesome-free/js/all.min.js"></script>  
24 - <script defer src="/static/js/maintopics.js"></script>  
25 4
  5 +<head>
  6 + <title>{{appname}}</title>
  7 + <link rel="icon" href="/static/favicon.ico">
  8 + <meta charset="utf-8">
  9 + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  10 + <meta name="author" content="Miguel Barão">
  11 + <!-- Styles -->
  12 + <link rel="stylesheet" href="/static/mdbootstrap/css/bootstrap.min.css">
  13 + <link rel="stylesheet" href="/static/mdbootstrap/css/mdb.min.css">
  14 + <link rel="stylesheet" href="/static/css/maintopics.css">
  15 + <!-- Scripts -->
  16 + <script defer src="/static/mdbootstrap/js/jquery-3.4.1.min.js"></script>
  17 + <script defer src="/static/mdbootstrap/js/popper.min.js"></script>
  18 + <script defer src="/static/mdbootstrap/js/bootstrap.min.js"></script>
  19 + <script defer src="/static/mdbootstrap/js/mdb.min.js"></script>
  20 + <script defer src="/static/fontawesome-free/js/all.min.js"></script>
  21 + <script defer src="/static/js/maintopics.js"></script>
26 </head> 22 </head>
27 -<!-- ===================================================================== -->  
28 -<body>  
29 -<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-primary">  
30 - <img src="/static/logo_horizontal.png" height="48" width="120" class="navbar-brand" alt="UEvora">  
31 - <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">  
32 - <span class="navbar-toggler-icon"></span>  
33 - </button>  
34 -  
35 - <div class="collapse navbar-collapse" id="navbarText">  
36 - <div class="navbar-nav mr-auto">  
37 - <a class="nav-item nav-link active" href="#">Cursos <span class="sr-only">(actual)</span></a>  
38 - <a class="nav-item nav-link disabled" href="#">Tópicos</a>  
39 - <a class="nav-item nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Classificação</a>  
40 - </div>  
41 23
42 - <ul class="navbar-nav">  
43 - <li class="nav-item dropdown">  
44 - <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">  
45 - <i class="fas fa-user-graduate" aria-hidden="true"></i>  
46 - <span id="name">{{ escape(name) }}</span>  
47 - <span class="caret"></span>  
48 - </a>  
49 - <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">  
50 - <a class="dropdown-item" data-toggle="modal" data-target="#password_modal">Mudar Password</a>  
51 - <div class="dropdown-divider"></div>  
52 - <a class="dropdown-item" href="/logout">Sair</a> 24 +<body>
  25 + <!-- ===== navbar ==================================================== -->
  26 + <nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-primary">
  27 + <img src="/static/logo_horizontal.png" height="48" width="120" class="navbar-brand" alt="UEvora">
  28 + <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
  29 + <span class="navbar-toggler-icon"></span>
  30 + </button>
  31 + <div class="collapse navbar-collapse" id="navbarText">
  32 + <div class="navbar-nav mr-auto">
  33 + <a class="nav-item nav-link active" href="#">Cursos <span class="sr-only">(actual)</span></a>
  34 + <a class="nav-item nav-link disabled" href="#">Tópicos</a>
  35 + <a class="nav-item nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Classificação</a>
  36 + </div>
  37 + <ul class="navbar-nav">
  38 + <li class="nav-item dropdown">
  39 + <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
  40 + <i class="fas fa-user-graduate" aria-hidden="true"></i>
  41 + <span id="name">{{ escape(name) }}</span>
  42 + <span class="caret"></span>
  43 + </a>
  44 + <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
  45 + <a class="dropdown-item" data-toggle="modal" data-target="#password_modal">Mudar Password</a>
  46 + <div class="dropdown-divider"></div>
  47 + <a class="dropdown-item" href="/logout">Sair</a>
  48 + </div>
  49 + </li>
  50 + </ul>
53 </div> 51 </div>
54 - </li>  
55 - </ul>  
56 - </div>  
57 -</nav>  
58 -<!-- ===================================================================== -->  
59 -<div class="container">  
60 -  
61 - <div id="notifications"></div>  
62 -  
63 - {% for k,v in courses.items() %}  
64 -  
65 - <a href="/course/{{k}}" class="card text-dark mb-3" style="width: 18rem;">  
66 - <div class="card-body">  
67 - <h6 class="card-title">{{ v['title'] }}</h6>  
68 - </div>  
69 - </a>  
70 -  
71 - {% end %} <!-- for -->  
72 -  
73 -  
74 -<!-- === Change Password Modal =========================================== -->  
75 -<div id="password_modal" class="modal fade" tabindex="-1" role="dialog">  
76 - <div class="modal-dialog" role="document">  
77 - <div class="modal-content">  
78 -<!-- header -->  
79 - <div class="modal-header">  
80 - <h5 class="modal-title">Alterar Password</h5>  
81 - </div>  
82 -<!-- body -->  
83 - <div class="modal-body">  
84 - <div class="control-group">  
85 - <label for="new_password" class="control-label">Introduza a nova password:</label>  
86 - <div class="controls">  
87 - <input type="password" id="new_password" name="new_password" autocomplete="new-password"> 52 + </nav>
  53 + <!-- ===== page ====================================================== -->
  54 + <div class="container">
  55 + <div id="notifications"></div>
  56 + <div class="row">
  57 + {% for k,v in courses.items() %}
  58 + <div class="card-deck col-3">
  59 + <a href="/course/{{k}}" class="card mb-3">
  60 + <!-- text-dark mb-3" style="width: 18rem;" -->
  61 + <div class="card-body">
  62 + <h6 class="card-title">{{ v['title'] }}</h6>
  63 + <p class="card-text">{{ v.get('description', '') }}</p>
  64 + </div>
  65 + </a>
88 </div> 66 </div>
  67 + {% end %}
89 </div> 68 </div>
90 - </div>  
91 -<!-- footer -->  
92 - <div class="modal-footer">  
93 - <button type="button" class="btn btn-default" data-dismiss="modal">Cancelar</button>  
94 - <button id="change_password" type="button" class="btn btn-danger" data-dismiss="modal">Alterar</button>  
95 - </div>  
96 -  
97 - </div><!-- /.modal-content -->  
98 - </div><!-- /.modal-dialog -->  
99 -</div><!-- /.modal -->  
100 - 69 + </div>
  70 + <!-- for -->
  71 + <!-- === Change Password Modal =========================================== -->
  72 + <div id="password_modal" class="modal fade" tabindex="-1" role="dialog">
  73 + <div class="modal-dialog" role="document">
  74 + <div class="modal-content">
  75 + <!-- header -->
  76 + <div class="modal-header">
  77 + <h5 class="modal-title">Alterar Password</h5>
  78 + </div>
  79 + <!-- body -->
  80 + <div class="modal-body">
  81 + <div class="control-group">
  82 + <label for="new_password" class="control-label">Introduza a nova password:</label>
  83 + <div class="controls">
  84 + <input type="password" id="new_password" name="new_password" autocomplete="new-password">
  85 + </div>
  86 + </div>
  87 + </div>
  88 + <!-- footer -->
  89 + <div class="modal-footer">
  90 + <button type="button" class="btn btn-default" data-dismiss="modal">Cancelar</button>
  91 + <button id="change_password" type="button" class="btn btn-danger" data-dismiss="modal">Alterar</button>
  92 + </div>
  93 + </div><!-- /.modal-content -->
  94 + </div><!-- /.modal-dialog -->
  95 + </div><!-- /.modal -->
101 </body> 96 </body>
102 -</html> 97 +
  98 +</html>
103 \ No newline at end of file 99 \ No newline at end of file
aprendizations/templates/solution.html
1 {% autoescape %} 1 {% autoescape %}
2 2
3 {% if solution %} 3 {% if solution %}
4 -<div class="card"> 4 +<div class="card mt-3">
5 <div class="card-body"> 5 <div class="card-body">
6 {{ md(solution) }} 6 {{ md(solution) }}
7 </div> 7 </div>
aprendizations/templates/topic.html
1 <!DOCTYPE html> 1 <!DOCTYPE html>
2 <html> 2 <html>
  3 +
3 <head> 4 <head>
4 <title>{{appname}}</title> 5 <title>{{appname}}</title>
5 <link rel="icon" href="/static/favicon.ico"> 6 <link rel="icon" href="/static/favicon.ico">
6 -  
7 <meta charset="utf-8"> 7 <meta charset="utf-8">
8 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 8 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
9 <meta name="author" content="Miguel Barão"> 9 <meta name="author" content="Miguel Barão">
10 -  
11 -<!-- MathJax3 -->  
12 - <script>  
13 - MathJax = {  
14 - tex: {  
15 - inlineMath: [['$$$', '$$$'], ['\\(', '\\)']]  
16 - },  
17 - svg: {  
18 - fontCache: 'global'  
19 - }  
20 - };  
21 - </script>  
22 - <script async type="text/javascript" id="MathJax-script" src="/static/mathjax/es5/tex-svg.js"></script>  
23 -  
24 -<!-- Styles --> 10 + <!-- MathJax3 -->
  11 + <script>
  12 + MathJax = {
  13 + tex: {
  14 + inlineMath: [
  15 + ['$$$', '$$$'],
  16 + ['\\(', '\\)']
  17 + ]
  18 + },
  19 + svg: {
  20 + fontCache: 'global'
  21 + }
  22 + };
  23 + </script>
  24 + <script async type="text/javascript" id="MathJax-script" src="/static/mathjax/es5/tex-svg.js"></script>
  25 + <!-- Styles -->
25 <link rel="stylesheet" href="/static/mdbootstrap/css/bootstrap.min.css"> 26 <link rel="stylesheet" href="/static/mdbootstrap/css/bootstrap.min.css">
26 <link rel="stylesheet" href="/static/mdbootstrap/css/mdb.min.css"> 27 <link rel="stylesheet" href="/static/mdbootstrap/css/mdb.min.css">
27 <link rel="stylesheet" href="/static/codemirror/lib/codemirror.css"> 28 <link rel="stylesheet" href="/static/codemirror/lib/codemirror.css">
28 <link rel="stylesheet" href="/static/css/animate.min.css"> 29 <link rel="stylesheet" href="/static/css/animate.min.css">
29 <link rel="stylesheet" href="/static/css/github.css"> 30 <link rel="stylesheet" href="/static/css/github.css">
30 <link rel="stylesheet" href="/static/css/topic.css"> 31 <link rel="stylesheet" href="/static/css/topic.css">
31 -  
32 -<!-- Scripts --> 32 + <!-- Scripts -->
33 <script defer src="/static/mdbootstrap/js/jquery-3.4.1.min.js"></script> 33 <script defer src="/static/mdbootstrap/js/jquery-3.4.1.min.js"></script>
34 <script defer src="/static/mdbootstrap/js/popper.min.js"></script> 34 <script defer src="/static/mdbootstrap/js/popper.min.js"></script>
35 <script defer src="/static/mdbootstrap/js/bootstrap.min.js"></script> 35 <script defer src="/static/mdbootstrap/js/bootstrap.min.js"></script>
@@ -37,77 +37,67 @@ @@ -37,77 +37,67 @@
37 <script defer src="/static/fontawesome-free/js/all.min.js"></script> 37 <script defer src="/static/fontawesome-free/js/all.min.js"></script>
38 <script defer src="/static/codemirror/lib/codemirror.js"></script> 38 <script defer src="/static/codemirror/lib/codemirror.js"></script>
39 <script defer src="/static/js/topic.js"></script> 39 <script defer src="/static/js/topic.js"></script>
40 -  
41 </head> 40 </head>
42 <!-- ===================================================================== --> 41 <!-- ===================================================================== -->
43 -<body>  
44 -<!-- Navbar -->  
45 -<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-primary">  
46 - <img src="/static/logo_horizontal.png" height="48" width="120" class="navbar-brand" alt="UEvora">  
47 - <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">  
48 - <span class="navbar-toggler-icon"></span>  
49 - </button>  
50 42
51 - <div class="collapse navbar-collapse" id="navbarText">  
52 - <div class="navbar-nav mr-auto">  
53 - <a class="nav-item nav-link" href="/courses">Cursos</a>  
54 - <a class="nav-item nav-link active" href="/course/{{course_id}}">Tópicos <span class="sr-only">(actual)</span></a>  
55 - <a class="nav-item nav-link" href="/rankings?course={{course_id}}">Classificação</a> 43 +<body>
  44 + <!-- Navbar -->
  45 + <nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-primary">
  46 + <img src="/static/logo_horizontal.png" height="48" width="120" class="navbar-brand" alt="UEvora">
  47 + <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
  48 + <span class="navbar-toggler-icon"></span>
  49 + </button>
  50 + <div class="collapse navbar-collapse" id="navbarText">
  51 + <div class="navbar-nav mr-auto">
  52 + <a class="nav-item nav-link" href="/courses">Cursos</a>
  53 + <a class="nav-item nav-link active" href="/course/{{course_id}}">Tópicos <span class="sr-only">(actual)</span></a>
  54 + <a class="nav-item nav-link" href="/rankings?course={{course_id}}">Classificação</a>
  55 + </div>
  56 + <ul class="navbar-nav">
  57 + <li class="nav-item dropdown">
  58 + <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
  59 + <i class="fas fa-user-graduate" aria-hidden="true"></i>
  60 + <span id="name">{{ escape(name) }}</span>
  61 + <span class="caret"></span>
  62 + </a>
  63 + <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
  64 + <a class="dropdown-item" href="/logout">Sair</a>
  65 + </div>
  66 + </li>
  67 + </ul>
56 </div> 68 </div>
57 -  
58 - <ul class="navbar-nav">  
59 - <li class="nav-item dropdown">  
60 - <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">  
61 - <i class="fas fa-user-graduate" aria-hidden="true"></i>  
62 - <span id="name">{{ escape(name) }}</span>  
63 - <span class="caret"></span>  
64 - </a>  
65 - <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">  
66 - <a class="dropdown-item" href="/logout">Sair</a>  
67 - </div>  
68 - </li>  
69 - </ul>  
70 - </div>  
71 -</nav>  
72 -  
73 -<!-- ===================================================================== -->  
74 -<div class="progress">  
75 - <div class="progress-bar bg-primary" id="topic_progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width: 1em;width: 0%"></div>  
76 -</div>  
77 -  
78 -<!-- ===================================================================== -->  
79 -<!-- main panel with questions -->  
80 -<div class="container" id="container">  
81 -  
82 - <div id="notifications"></div>  
83 -  
84 - <div class="my-5" id="content">  
85 - <form action="/question" method="post" id="question_form" autocomplete="off">  
86 - {% module xsrf_form_html() %}  
87 - <div id="question_div"></div>  
88 - </form>  
89 -  
90 - <div id="comments"></div> 69 + </nav>
  70 + <!-- ===================================================================== -->
  71 + <div class="progress">
  72 + <div class="progress-bar bg-primary" id="topic_progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width: 1em;width: 0%"></div>
91 </div> 73 </div>
92 -  
93 - <div id="wrong" style="display: none">  
94 - <div class="alert alert-danger">  
95 - <h4><i class="fas fa-thumbs-down fa-3x"></i> Não acertou, mas também se aprende com os erros...</h4>  
96 - <div id="solution_wrong"></div> 74 + <!-- ===================================================================== -->
  75 + <!-- main panel with questions -->
  76 + <div class="container" id="container">
  77 + <div id="notifications"></div>
  78 + <div class="my-5" id="content">
  79 + <form action="/question" method="post" id="question_form" autocomplete="off">
  80 + {% module xsrf_form_html() %}
  81 + <div id="question_div"></div>
  82 + </form>
  83 + <div id="comments"></div>
97 </div> 84 </div>
98 - </div>  
99 -  
100 - <div id="right" style="display: none">  
101 - <div class="alert alert-success">  
102 - <h4><i class="fas fa-thumbs-up fa-3x"></i> Muito bem!</h4>  
103 - <div id="solution_right"></div> 85 + <div id="wrong" style="display: none">
  86 + <div class="alert alert-danger">
  87 + <h4><i class="fas fa-thumbs-down fa-3x"></i> Não acertou, mas também se aprende com os erros...</h4>
  88 + <div id="solution_wrong"></div>
  89 + </div>
  90 + </div>
  91 + <div id="right" style="display: none">
  92 + <div class="alert alert-success">
  93 + <h4><i class="fas fa-thumbs-up fa-3x"></i> Muito bem!</h4>
  94 + <div id="solution_right"></div>
  95 + </div>
104 </div> 96 </div>
  97 + <!-- reponder / continuar -->
  98 + <a class="btn btn-primary btn-lg btn-block my-5" id="submit" data-toggle="tooltip" data-placement="right" href="#solution"></a>
  99 + <!-- title="Shift-Enter" -->
105 </div> 100 </div>
106 -  
107 - <!-- reponder / continuar -->  
108 - <a class="btn btn-primary btn-lg btn-block my-5" id="submit" data-toggle="tooltip" data-placement="right" href="#solution"></a>  
109 - <!-- title="Shift-Enter" -->  
110 -</div>  
111 -  
112 </body> 101 </body>
113 -</html> 102 +
  103 +</html>
114 \ No newline at end of file 104 \ No newline at end of file
aprendizations/tools.py
@@ -21,8 +21,12 @@ logger = logging.getLogger(__name__) @@ -21,8 +21,12 @@ logger = logging.getLogger(__name__)
21 21
22 # ------------------------------------------------------------------------- 22 # -------------------------------------------------------------------------
23 # Markdown to HTML renderer with support for LaTeX equations 23 # Markdown to HTML renderer with support for LaTeX equations
24 -# Inline math: $x$  
25 -# Block math: $$x$$ or \begin{equation}x\end{equation} 24 +# -------------------------------------------------------------------------
  25 +
  26 +
  27 +# -------------------------------------------------------------------------
  28 +# Block math:
  29 +# $$x$$ or \begin{equation}x\end{equation}
26 # ------------------------------------------------------------------------- 30 # -------------------------------------------------------------------------
27 class MathBlockGrammar(mistune.BlockGrammar): 31 class MathBlockGrammar(mistune.BlockGrammar):
28 block_math = re.compile(r'^\$\$(.*?)\$\$', re.DOTALL) 32 block_math = re.compile(r'^\$\$(.*?)\$\$', re.DOTALL)
@@ -47,6 +51,7 @@ class MathBlockLexer(mistune.BlockLexer): @@ -47,6 +51,7 @@ class MathBlockLexer(mistune.BlockLexer):
47 }) 51 })
48 52
49 def parse_latex_environment(self, m): 53 def parse_latex_environment(self, m):
  54 + r'''Parse an environment \begin{name}text\end{name}'''
50 self.tokens.append({ 55 self.tokens.append({
51 'type': 'latex_environment', 56 'type': 'latex_environment',
52 'name': m.group(1), 57 'name': m.group(1),
@@ -54,6 +59,9 @@ class MathBlockLexer(mistune.BlockLexer): @@ -54,6 +59,9 @@ class MathBlockLexer(mistune.BlockLexer):
54 }) 59 })
55 60
56 61
  62 +# -------------------------------------------------------------------------
  63 +# Inline math: $x$
  64 +# -------------------------------------------------------------------------
57 class MathInlineGrammar(mistune.InlineGrammar): 65 class MathInlineGrammar(mistune.InlineGrammar):
58 math = re.compile(r'^\$(.+?)\$', re.DOTALL) 66 math = re.compile(r'^\$(.+?)\$', re.DOTALL)
59 block_math = re.compile(r'^\$\$(.+?)\$\$', re.DOTALL) 67 block_math = re.compile(r'^\$\$(.+?)\$\$', re.DOTALL)
@@ -108,18 +116,19 @@ class HighlightRenderer(mistune.Renderer): @@ -108,18 +116,19 @@ class HighlightRenderer(mistune.Renderer):
108 def image(self, src, title, alt): 116 def image(self, src, title, alt):
109 alt = mistune.escape(alt, quote=True) 117 alt = mistune.escape(alt, quote=True)
110 title = mistune.escape(title or '', quote=True) 118 title = mistune.escape(title or '', quote=True)
111 - return f'<img src="/file/{src}" class="img-fluid mx-auto d-block" ' \ 119 + return f'<img src="/file/{src}" ' \
112 f'alt="{alt}" title="{title}">' 120 f'alt="{alt}" title="{title}">'
  121 + # class="img-fluid mx-auto d-block"
113 122
114 # Pass math through unaltered - mathjax does the rendering in the browser 123 # Pass math through unaltered - mathjax does the rendering in the browser
115 def block_math(self, text): 124 def block_math(self, text):
116 - return fr'$$ {text} $$' 125 + return fr'\[ {text} \]'
117 126
118 def latex_environment(self, name, text): 127 def latex_environment(self, name, text):
119 return fr'\begin{{{name}}} {text} \end{{{name}}}' 128 return fr'\begin{{{name}}} {text} \end{{{name}}}'
120 129
121 def inline_math(self, text): 130 def inline_math(self, text):
122 - return fr'$$$ {text} $$$' 131 + return fr'\( {text} \)'
123 132
124 133
125 # hard_wrap=True to insert <br> on newline 134 # hard_wrap=True to insert <br> on newline