Sotaro KARASAWA 8 лет назад
Родитель
Сommit
e49f6bebf2

+ 1 - 0
lib/models/config.js

@@ -233,6 +233,7 @@ module.exports = function(crowi) {
       },
       env: {
         PLANTUML_URI: env.PLANTUML_URI || null,
+        MATHJAX: env.MATHJAX || null,
       },
     };
 

+ 3 - 2
resource/js/crowi-form.js

@@ -63,8 +63,9 @@ $(function() {
 
   function renderPreview() {
     var content = $('#form-body').val();
-    var parsedHTML = crowiRenderer.render(content);
-    $('#preview-body').html(parsedHTML);
+    var previewBody = $('#preview-body');
+    var parsedHTML = crowiRenderer.render(content, previewBody.get(0));
+    previewBody.html(parsedHTML);
   }
 
   // for initialize preview

+ 6 - 4
resource/js/crowi.js

@@ -386,11 +386,12 @@ $(function() {
         var id = $(this).attr('id');
         var contentId = '#' + id + ' > script';
         var revisionBody = '#' + id + ' .revision-body';
+        var $revisionBody = $(revisionBody);
         var revisionPath = '#' + id + ' .revision-path';
 
         var markdown = Crowi.unescape($(contentId).html());
-        var parsedHTML = crowiRenderer.render(markdown);
-        $(revisionBody).html(parsedHTML);
+        var parsedHTML = crowiRenderer.render(markdown, $revisionBody.get(0));
+        $revisionBody.html(parsedHTML);
 
         $('.template-create-button', revisionBody).on('click', function() {
           var path = $(this).data('path');
@@ -435,8 +436,9 @@ $(function() {
     var $rawTextOriginal = $('#raw-text-original');
     if ($rawTextOriginal.length > 0) {
       var markdown = Crowi.unescape($('#raw-text-original').html());
-      var parsedHTML = crowiRenderer.render(markdown);
-      $('#revision-body-content').html(parsedHTML);
+      var revisionBody = $('#revision-body-content');
+      var parsedHTML = crowiRenderer.render(markdown, revisionBody.get(0));
+      revisionBody.html(parsedHTML);
 
 
       $('.template-create-button').on('click', function() {

+ 1 - 0
resource/js/util/Crowi.js

@@ -10,6 +10,7 @@ export default class Crowi {
     this.config = {};
     this.csrfToken = context.csrfToken;
 
+    this.window = window;
     this.location = window.location || {};
     this.document = window.document || {};
     this.localStorage = window.localStorage || {};

+ 11 - 9
resource/js/util/CrowiRenderer.js

@@ -6,6 +6,7 @@ import Linker        from './PreProcessor/Linker';
 import ImageExpander from './PreProcessor/ImageExpander';
 
 import Emoji         from './PostProcessor/Emoji';
+import Mathjax       from './PostProcessor/Mathjax';
 
 import Tsv2Table from './LangProcessor/Tsv2Table';
 import Template from './LangProcessor/Template';
@@ -24,6 +25,7 @@ export default class CrowiRenderer {
     ];
     this.postProcessors = [
       new Emoji(crowi),
+      new Mathjax(crowi),
     ];
 
     this.langProcessors = {
@@ -37,22 +39,22 @@ export default class CrowiRenderer {
     this.codeRenderer = this.codeRenderer.bind(this);
   }
 
-  preProcess(markdown) {
+  preProcess(markdown, dom) {
     for (let i = 0; i < this.preProcessors.length; i++) {
       if (!this.preProcessors[i].process) {
         continue;
       }
-      markdown = this.preProcessors[i].process(markdown);
+      markdown = this.preProcessors[i].process(markdown, dom);
     }
     return markdown;
   }
 
-  postProcess(html) {
+  postProcess(html, dom) {
     for (let i = 0; i < this.postProcessors.length; i++) {
       if (!this.postProcessors[i].process) {
         continue;
       }
-      html = this.postProcessors[i].process(html);
+      html = this.postProcessors[i].process(html, dom);
     }
 
     return html;
@@ -91,7 +93,7 @@ export default class CrowiRenderer {
 
   }
 
-  parseMarkdown(markdown) {
+  parseMarkdown(markdown, dom) {
     let parsed = '';
 
     const markedRenderer = new marked.Renderer();
@@ -128,12 +130,12 @@ export default class CrowiRenderer {
     return parsed;
   }
 
-  render(markdown) {
+  render(markdown, dom) {
     let html = '';
 
-    markdown = this.preProcess(markdown);
-    html = this.parseMarkdown(markdown);
-    html = this.postProcess(html);
+    markdown = this.preProcess(markdown, dom);
+    html = this.parseMarkdown(markdown, dom);
+    html = this.postProcess(html, dom);
 
     return html;
   }

+ 66 - 0
resource/js/util/PostProcessor/Mathjax.js

@@ -0,0 +1,66 @@
+
+export default class Mathjax {
+
+  constructor(crowi) {
+    this.crowi = crowi;
+    this.defaultUrl = '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?skipStartupTypeset=true';
+
+    this.mathJaxConfigured = false;
+
+    const config = crowi.getConfig();
+
+    if (config.env.MATHJAX) {
+      this.mathJaxConfigured = true;
+
+      if (crowi.window.MathJax) {
+        return ;
+      }
+
+      const document = crowi.document;
+      const head = document.getElementsByTagName('head')[0];
+
+      const mathJaxConfig= document.createElement('script');
+      mathJaxConfig.type = 'text/x-mathjax-config';
+      mathJaxConfig.text = `MathJax.Hub.Config({
+      extensions: ["tex2jax.js"],
+      jax: ["input/TeX", "output/SVG"],
+      tex2jax: {
+        inlineMath: [ ['$','$'], ["\\(","\\)"] ],
+        displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
+        processEscapes: true
+      },
+      showMathMenu: false,
+      showMathMenuMSIE: false,
+      showProcessingMessages: false,
+      messageStyle: "none",
+      skipStartupTypeset: true
+    });`;
+      head.appendChild(mathJaxConfig);
+
+      const script = document.createElement('script');
+      script.type = 'text/javascript';
+      script.src = this.defaultUrl;
+
+      head.appendChild(script);
+    }
+
+    this.process = this.process.bind(this);
+  }
+
+  process(html, dom) {
+    if (!this.mathJaxConfigured) {
+      return html;
+    }
+
+    const intervalId = setInterval(() => {
+      if (this.crowi.window.MathJax) {
+        const MathJax = this.crowi.window.MathJax;
+
+        MathJax.Hub.Queue(["Typeset", MathJax.Hub, dom.id]);
+        clearInterval(intervalId);
+      }
+    }, 100);
+
+    return html;
+  }
+}