Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

KaTeX + Marked JS works on initial WebView load(), but not on subsequent edits of source code.



  • I paired down the example code that demonstrates the problem but it occupies a complex directory structure, so I thought it best to just included it using a public github repository:

    https://github.com/enjoysmath/Marked-KaTeX-example-cpp

    After cloning, you just open up the .pro file in QtCreator, and build/run/debug it.


    This is the result I would like on editing the TextEdit on the left:

    0b3fdc24-1db7-4d72-b3c8-271eb347591f-image.png

    That is, the LaTeX gets rendered properly, using KaTeX (and not MathJax!! - it's too slow).

    This is what it does on subsequent edits (after intial load):

    d8bf7f34-0246-4610-97ce-9dcf799b8719-image.png

    That is, the LaTeX is no longer rendered.


    This is index.html which is very relevant to my issues. I also tried the "Auto-render extension" method from KaTeX's documentation.

    <!doctype html>
    <html lang="en">
    <meta charset="utf-8">
    <head>
      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css" integrity="sha384-R4558gYOUz8mP9YWpZJjofhk+zx0AS11p36HnD2ZKj/6JR5z27gSSULCNHIRReVs" crossorigin="anonymous">
      <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.js" integrity="sha384-z1fJDqw8ZApjGO3/unPWUPsIymfsJmyrDVWC8Tv/a1HeOtGmkwNd/7xUS0Xcnvsx" crossorigin="anonymous"></script>
      <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/contrib/auto-render.min.js" integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous"></script>
    
      <link rel="stylesheet" type="text/css" href="3rdparty/markdown.css">
      <script src="3rdparty/marked.js"></script>
      <script src="qrc:/qtwebchannel/qwebchannel.js"></script>
    </head>
    <body>
      <div id="placeholder"></div>
      <script>
      'use strict';
    
      var placeholder = document.getElementById('placeholder');
    
      var updateText = function(text) {
          placeholder.innerHTML = marked(text);
      }
    
      new QWebChannel(qt.webChannelTransport,
        function(channel) {
          var content = channel.objects.content;
          updateText(content.text);
          content.textChanged.connect(updateText);
        }
      );
      </script>
      <script>
          document.addEventListener("DOMContentLoaded", function() {
              renderMathInElement(document.body, {
                // customised options
                // • auto-render specific keys, e.g.:
                delimiters: [
                    {left: '$$', right: '$$', display: true},
                    {left: '$', right: '$', display: false},
                    {left: '\\(', right: '\\)', display: false},
                    {left: '\[', right: '\]', display: true}
                ],
                // • rendering keys, e.g.:
                throwOnError : false
              });
          });
      </script>
    </body>
    </html>
    

    So I've tried doing additional things such as calling .repaint() etc on the view object every edit. Should I simply replace the widget every edit? That seems like the worst idea in the world!!!

    Thank you for your expertise.



  • Found a solution: index.html needs to be changed to the following rearrangement of the above code:

    <!doctype html>
    <html lang="en">
    <meta charset="utf-8">
    <head>
      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css" integrity="sha384-R4558gYOUz8mP9YWpZJjofhk+zx0AS11p36HnD2ZKj/6JR5z27gSSULCNHIRReVs" crossorigin="anonymous">
      <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.js" integrity="sha384-z1fJDqw8ZApjGO3/unPWUPsIymfsJmyrDVWC8Tv/a1HeOtGmkwNd/7xUS0Xcnvsx" crossorigin="anonymous"></script>
      <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/contrib/auto-render.min.js" integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous"></script>
    
      <link rel="stylesheet" type="text/css" href="3rdparty/markdown.css">
      <script src="3rdparty/marked.js"></script>
      <script src="qrc:/qtwebchannel/qwebchannel.js"></script>
    </head>
    <body>
      <div id="placeholder"></div>
      <script>
      'use strict';
    
      document.addEventListener("DOMContentLoaded", function() {
          var placeholder = document.getElementById('placeholder');
    
          var renderMath = function() {
            renderMathInElement(document.body, {
              // customised options
              // • auto-render specific keys, e.g.:
              delimiters: [
                  {left: '$$', right: '$$', display: true},
                  {left: '$', right: '$', display: false},
                  {left: '\\(', right: '\\)', display: false},
                  {left: '\[', right: '\]', display: true}
              ],
              // • rendering keys, e.g.:
              throwOnError : false
            });
          }
    
          var updateText = function(text) {
              placeholder.innerHTML = marked(text);
              renderMath();
          }
    
          new QWebChannel(qt.webChannelTransport,
            function(channel) {
              var content = channel.objects.content;
              updateText(content.text);
              content.textChanged.connect(updateText);
            }
          );
       });
      </script>
    </body>
    </html>
    

    That is we need to call KaTeX after marked() and do so in the same update function. I had to put everything into a document-on-load since for some reason that was needed, but now I'm thinking maybe not. It depends on how KaTeX behaves.



  • Found a solution: index.html needs to be changed to the following rearrangement of the above code:

    <!doctype html>
    <html lang="en">
    <meta charset="utf-8">
    <head>
      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css" integrity="sha384-R4558gYOUz8mP9YWpZJjofhk+zx0AS11p36HnD2ZKj/6JR5z27gSSULCNHIRReVs" crossorigin="anonymous">
      <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.js" integrity="sha384-z1fJDqw8ZApjGO3/unPWUPsIymfsJmyrDVWC8Tv/a1HeOtGmkwNd/7xUS0Xcnvsx" crossorigin="anonymous"></script>
      <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/contrib/auto-render.min.js" integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous"></script>
    
      <link rel="stylesheet" type="text/css" href="3rdparty/markdown.css">
      <script src="3rdparty/marked.js"></script>
      <script src="qrc:/qtwebchannel/qwebchannel.js"></script>
    </head>
    <body>
      <div id="placeholder"></div>
      <script>
      'use strict';
    
      document.addEventListener("DOMContentLoaded", function() {
          var placeholder = document.getElementById('placeholder');
    
          var renderMath = function() {
            renderMathInElement(document.body, {
              // customised options
              // • auto-render specific keys, e.g.:
              delimiters: [
                  {left: '$$', right: '$$', display: true},
                  {left: '$', right: '$', display: false},
                  {left: '\\(', right: '\\)', display: false},
                  {left: '\[', right: '\]', display: true}
              ],
              // • rendering keys, e.g.:
              throwOnError : false
            });
          }
    
          var updateText = function(text) {
              placeholder.innerHTML = marked(text);
              renderMath();
          }
    
          new QWebChannel(qt.webChannelTransport,
            function(channel) {
              var content = channel.objects.content;
              updateText(content.text);
              content.textChanged.connect(updateText);
            }
          );
       });
      </script>
    </body>
    </html>
    

    That is we need to call KaTeX after marked() and do so in the same update function. I had to put everything into a document-on-load since for some reason that was needed, but now I'm thinking maybe not. It depends on how KaTeX behaves.


Log in to reply