Browse Source

refine markdown render logics

Add common templates markdown_template.html and
markdown_template.js.

Hoedow provides hoedown.js.
Marked provides marked.js.
Le Tan 8 years ago
parent
commit
d47dd92f59

+ 41 - 0
src/resources/hoedown.js

@@ -0,0 +1,41 @@
+var placeholder = document.getElementById('placeholder');
+
+var scrollToAnchor = function(anchor) {
+    var anc = document.getElementById(anchor);
+    if (anc != null) {
+        anc.scrollIntoView();
+    }
+};
+
+var updateHtml = function(html) {
+    placeholder.innerHTML = html;
+    var codes = document.getElementsByTagName('code');
+    for (var i = 0; i < codes.length; ++i) {
+        if (codes[i].parentElement.tagName.toLowerCase() == 'pre') {
+            hljs.highlightBlock(codes[i]);
+        }
+    }
+}
+
+var onWindowScroll = function() {
+    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset;
+    var eles = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
+
+    if (eles.length == 0) {
+        return;
+    }
+    var curIdx = 0;
+    var biaScrollTop = scrollTop + 50;
+    for (var i = 0; i < eles.length; ++i) {
+        if (biaScrollTop >= eles[i].offsetTop) {
+            curIdx = i;
+        } else {
+            break;
+        }
+    }
+
+    var curHeader = eles[curIdx].getAttribute("id");
+    if (curHeader != null) {
+        content.setHeader(curHeader);
+    }
+}

+ 19 - 0
src/resources/markdown_template.html

@@ -0,0 +1,19 @@
+<!doctype html>
+<html lang="en">
+<meta charset="utf-8">
+<head>
+    <style type="text/css">
+        <!-- BACKGROUND_PLACE_HOLDER -->
+    </style>
+    <link rel="stylesheet" type="text/css" href="CSS_PLACE_HOLDER">
+    <link rel="stylesheet" type="text/css" href="qrc:/utils/highlightjs/styles/default.css">
+    <script src="qrc:/resources/qwebchannel.js"></script>
+    <script src="qrc:/utils/highlightjs/highlight.pack.js"></script>
+    <!-- EXTRA_PLACE_HOLDER -->
+    <script src="JS_PLACE_HOLDER" defer></script>
+    <script src="qrc:/resources/markdown_template.js" defer></script>
+</head>
+<body>
+    <div id="placeholder"></div>
+</body>
+</html>

+ 96 - 0
src/resources/markdown_template.js

@@ -0,0 +1,96 @@
+var content;
+var keyState = 0;
+
+new QWebChannel(qt.webChannelTransport,
+    function(channel) {
+        content = channel.objects.content;
+        if (typeof updateHtml == "function") {
+            updateHtml(content.html);
+            content.htmlChanged.connect(updateHtml);
+        }
+        if (typeof updateText == "function") {
+            content.textChanged.connect(updateText);
+            content.updateText();
+        }
+        content.requestScrollToAnchor.connect(scrollToAnchor);
+    });
+
+window.onscroll = onWindowScroll;
+
+document.onkeydown = function(e) {
+    e = e || window.event;
+    var key;
+    var shift;
+    var ctrl;
+    if (e.which) {
+        key = e.which;
+    } else {
+        key = e.keyCode;
+    }
+    shift = !!e.shiftKey;
+    ctrl = !!e.ctrlKey;
+    switch (key) {
+    case 74: // J
+        window.scrollBy(0, 100);
+        keyState = 0;
+    break;
+
+    case 75: // K
+        window.scrollBy(0, -100);
+        keyState = 0;
+    break;
+
+    case 72: // H
+        window.scrollBy(-100, 0);
+        keyState = 0;
+    break;
+
+    case 76: // L
+        window.scrollBy(100, 0);
+        keyState = 0;
+    break;
+
+    case 71: // G
+        if (shift) {
+            var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset;
+            var scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
+            window.scrollTo(scrollLeft, scrollHeight);
+            keyState = 0;
+            break;
+        } else {
+            if (keyState == 0) {
+                keyState = 1;
+            } else if (keyState == 1) {
+                keyState = 0;
+                var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset;
+                window.scrollTo(scrollLeft, 0);
+            }
+            break;
+        }
+        return;
+
+    case 85: // U
+        keyState = 0;
+        if (ctrl) {
+            var clientHeight = document.documentElement.clientHeight;
+            window.scrollBy(0, -clientHeight);
+            break;
+        }
+        return;
+
+    case 68: // D
+        keyState = 0;
+        if (ctrl) {
+            var clientHeight = document.documentElement.clientHeight;
+            window.scrollBy(0, clientHeight);
+            break;
+        }
+        return;
+
+    default:
+        content.keyPressEvent(key);
+        keyState = 0;
+        return;
+    }
+    e.preventDefault();
+}

+ 154 - 0
src/resources/marked.js

@@ -0,0 +1,154 @@
+var placeholder = document.getElementById('placeholder');
+var renderer = new marked.Renderer();
+var toc = []; // Table of contents as a list
+var nameCounter = 0;
+
+renderer.heading = function(text, level) {
+    // Use number to avoid issues with Chinese
+    var escapedText = 'toc_' + nameCounter++;
+    toc.push({
+        level: level,
+        anchor: escapedText,
+        title: text
+    });
+    return '<h' + level + ' id="' + escapedText + '">' + text + '</h' + level + '>';
+};
+
+// Highlight.js to highlight code block
+marked.setOptions({
+    highlight: function(code) {
+        return hljs.highlightAuto(code).value;
+    }
+});
+
+var markdownToHtml = function(markdown, needToc) {
+    toc = [];
+    var html = marked(markdown, { renderer: renderer });
+    nameCounter = 0;
+    if (needToc) {
+        return html.replace(/<p>\[TOC\]<\/p>/ig, '<div class="vnote-toc"></div>');
+    } else {
+        return html;
+    }
+};
+
+// Handle wrong title levels, such as '#' followed by '###'
+var toPerfectToc = function(toc) {
+    var i;
+    var curLevel = 1;
+    var perfToc = [];
+    for (i in toc) {
+        var item = toc[i];
+        while (item.level > curLevel + 1) {
+            curLevel += 1;
+            var tmp = { level: curLevel,
+                        anchor: item.anchor,
+                        title: '[EMPTY]'
+                      };
+            perfToc.push(tmp);
+        }
+        perfToc.push(item);
+        curLevel = item.level;
+    }
+    return perfToc;
+};
+
+var itemToHtml = function(item) {
+    return '<a href="#' + item.anchor + '">' + item.title + '</a>';
+};
+
+// Turn a perfect toc to a tree using <ul>
+var tocToTree = function(toc) {
+    var i;
+    var front = '<li>';
+    var ending = ['</li>'];
+    var curLevel = 1;
+    for (i in toc) {
+        var item = toc[i];
+        if (item.level == curLevel) {
+            front += '</li>';
+            front += '<li>';
+            front += itemToHtml(item);
+        } else if (item.level > curLevel) {
+            // assert(item.level - curLevel == 1)
+            front += '<ul>';
+            ending.push('</ul>');
+            front += '<li>';
+            front += itemToHtml(item);
+            ending.push('</li>');
+            curLevel = item.level;
+        } else {
+            while (item.level < curLevel) {
+                var ele = ending.pop();
+                front += ele;
+                if (ele == '</ul>') {
+                    curLevel--;
+                }
+            }
+            front += '</li>';
+            front += '<li>';
+            front += itemToHtml(item);
+        }
+    }
+    while (ending.length > 0) {
+        front += ending.pop();
+    }
+    front = front.replace("<li></li>", "");
+    front = '<ul>' + front + '</ul>';
+    return front;
+};
+
+var handleToc = function(needToc) {
+    var tocTree = tocToTree(toPerfectToc(toc));
+    content.setToc(tocTree);
+
+    // Add it to html
+    if (needToc) {
+        var eles = document.getElementsByClassName('vnote-toc');
+        for (var i = 0; i < eles.length; ++i) {
+            eles[i].innerHTML = tocTree;
+        }
+    }
+};
+
+var mdHasTocSection = function(markdown) {
+    var n = markdown.search(/(\n|^)\[toc\]/i);
+    return n != -1;
+};
+
+var updateText = function(text) {
+    var needToc = mdHasTocSection(text);
+    var html = markdownToHtml(text, needToc);
+    placeholder.innerHTML = html;
+    handleToc(needToc);
+};
+
+var scrollToAnchor = function(anchor) {
+    var anc = document.getElementById(anchor);
+    if (anc != null) {
+        anc.scrollIntoView();
+    }
+};
+
+var onWindowScroll = function() {
+    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset;
+    var eles = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
+
+    if (eles.length == 0) {
+        return;
+    }
+    var curIdx = 0;
+    var biaScrollTop = scrollTop + 50;
+    for (var i = 0; i < eles.length; ++i) {
+        if (biaScrollTop >= eles[i].offsetTop) {
+            curIdx = i;
+        } else {
+            break;
+        }
+    }
+
+    var curHeader = eles[curIdx].getAttribute("id");
+    if (curHeader != null) {
+        content.setHeader(curHeader);
+    }
+}

+ 0 - 2
src/resources/post_template.html

@@ -1,2 +0,0 @@
-</body>
-</html>

+ 0 - 145
src/resources/pre_template.html

@@ -1,145 +0,0 @@
-<!doctype html>
-<html lang="en">
-<meta charset="utf-8">
-<head>
-  <style type="text/css">
-    <!-- BACKGROUND_PLACE_HOLDER -->
-  </style>
-  <link rel="stylesheet" type="text/css" href="CSS_PLACE_HOLDER">
-  <link rel="stylesheet" type="text/css" href="qrc:/utils/highlightjs/styles/default.css">
-  <script src="qrc:/resources/qwebchannel.js"></script>
-  <script src="qrc:/utils/highlightjs/highlight.pack.js"></script>
-</head>
-<body>
-  <div id="placeholder"></div>
-  <script>
-  'use strict';
-  var placeholder = document.getElementById('placeholder');
-  var content;
-  var keyState = 0;
-
-  var scrollToAnchor = function(anchor) {
-      document.getElementById(anchor).scrollIntoView();
-  };
-
-  var updateHtml = function(html) {
-      placeholder.innerHTML = html;
-
-      var codes = document.getElementsByTagName('code');
-      for (var i = 0; i < codes.length; ++i) {
-          if (codes[i].parentElement.tagName.toLowerCase() == 'pre') {
-              hljs.highlightBlock(codes[i]);
-          }
-      }
-  }
-
-  new QWebChannel(qt.webChannelTransport,
-    function(channel) {
-      content = channel.objects.content;
-      updateHtml(content.html);
-      content.htmlChanged.connect(updateHtml);
-      content.requestScrollToAnchor.connect(scrollToAnchor);
-    }
-  );
-
-  window.onscroll = function() {
-    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset;
-    var eles = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
-
-    if (eles.length == 0) {
-        return;
-    }
-    var curIdx = 0;
-    var biaScrollTop = scrollTop + 50;
-    for (var i = 0; i < eles.length; ++i) {
-        if (biaScrollTop >= eles[i].offsetTop) {
-            curIdx = i;
-        } else {
-            break;
-        }
-    }
-
-    var curHeader = eles[curIdx].getAttribute("id");
-    if (curHeader != null) {
-        content.setHeader(curHeader);
-    }
-  }
-
-    document.onkeydown = function(e) {
-        e = e || window.event;
-        var key;
-        var shift;
-        var ctrl;
-        if (e.which) {
-            key = e.which;
-        } else {
-            key = e.keyCode;
-        }
-        shift = !!e.shiftKey;
-        ctrl = !!e.ctrlKey;
-        switch (key) {
-            case 74: // J
-                window.scrollBy(0, 100);
-                keyState = 0;
-                break;
-
-            case 75: // K
-                window.scrollBy(0, -100);
-                keyState = 0;
-                break;
-
-            case 72: // H
-                window.scrollBy(-100, 0);
-                keyState = 0;
-                break;
-
-            case 76: // L
-                window.scrollBy(100, 0);
-                keyState = 0;
-                break;
-
-            case 71: // G
-                if (shift) {
-                    var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset;
-                    var scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
-                    window.scrollTo(scrollLeft, scrollHeight);
-                    keyState = 0;
-                    break;
-                } else {
-                    if (keyState == 0) {
-                        keyState = 1;
-                    } else if (keyState == 1) {
-                        keyState = 0;
-                        var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset;
-                        window.scrollTo(scrollLeft, 0);
-                    }
-                    break;
-                }
-                return;
-
-            case 85: // U
-                keyState = 0;
-                if (ctrl) {
-                    var clientHeight = document.documentElement.clientHeight;
-                    window.scrollBy(0, -clientHeight);
-                    break;
-                }
-                return;
-
-            case 68: // D
-                keyState = 0;
-                if (ctrl) {
-                    var clientHeight = document.documentElement.clientHeight;
-                    window.scrollBy(0, clientHeight);
-                    break;
-                }
-                return;
-
-            default:
-                content.keyPressEvent(key);
-                keyState = 0;
-                return;
-        }
-        e.preventDefault();
-    }
-  </script>

+ 0 - 267
src/resources/template.html

@@ -1,267 +0,0 @@
-<!doctype html>
-<html lang="en">
-<meta charset="utf-8">
-<head>
-  <style type="text/css">
-    <!-- BACKGROUND_PLACE_HOLDER -->
-  </style>
-  <link rel="stylesheet" type="text/css" href="CSS_PLACE_HOLDER">
-  <link rel="stylesheet" type="text/css" href="qrc:/utils/highlightjs/styles/default.css">
-  <script src="qrc:/utils/marked/marked.min.js"></script>
-  <script src="qrc:/resources/qwebchannel.js"></script>
-  <script src="qrc:/utils/highlightjs/highlight.pack.js"></script>
-</head>
-<body>
-  <div id="placeholder"></div>
-  <script>
-  'use strict';
-
-  var placeholder = document.getElementById('placeholder');
-  var renderer = new marked.Renderer();
-  var toc = []; // Table of contents as a list
-  var content; // Channel variable with content
-  var nameCounter = 0;
-  var keyState = 0;
-
-  renderer.heading = function (text, level) {
-      // Use number to avoid issues with Chinese
-      var escapedText = 'toc_' + nameCounter++;
-      toc.push({
-        level: level,
-        anchor: escapedText,
-        title: text
-      });
-	  return '<h' + level + ' id="' +
-             escapedText + '">' +
-			 text + '</h' + level + '>';
-  };
-
-  // Highlight.js to highlight code block
-  marked.setOptions({
-    highlight: function (code) {
-      return hljs.highlightAuto(code).value;
-    }
-  });
-
-  var markdownToHtml = function (markdown, needToc) {
-      toc = [];
-      var html = marked(markdown, { renderer: renderer });
-      nameCounter = 0;
-      if (needToc) {
-          return html.replace(/<p>\[TOC\]<\/p>/ig, '<div class="vnote-toc"></div>');
-      } else {
-          return html;
-      }
-  };
-
-  // Handle wrong title levels, such as '#' followed by '###'
-  var toPerfectToc = function (toc) {
-      var i;
-      var curLevel = 1;
-      var perfToc = [];
-      for (i in toc) {
-          var item = toc[i];
-          while (item.level > curLevel + 1) {
-              curLevel += 1;
-              var tmp = { level: curLevel,
-                          anchor: item.anchor,
-                          title: '[EMPTY]'
-              };
-              perfToc.push(tmp);
-          }
-          perfToc.push(item);
-          curLevel = item.level;
-      }
-      return perfToc;
-  };
-
-  var itemToHtml = function (item) {
-      return '<a href="#' + item.anchor + '">' + item.title + '</a>';
-  };
-
-  // Turn a perfect toc to a tree using <ul>
-  var tocToTree = function (toc) {
-      var i;
-      var front = '<li>';
-      var ending = ['</li>'];
-      var curLevel = 1;
-      for (i in toc) {
-          var item = toc[i];
-          if (item.level == curLevel) {
-              front += '</li>';
-              front += '<li>';
-              front += itemToHtml(item);
-          } else if (item.level > curLevel) {
-              // assert(item.level - curLevel == 1)
-              front += '<ul>';
-              ending.push('</ul>');
-              front += '<li>';
-              front += itemToHtml(item);
-              ending.push('</li>');
-              curLevel = item.level;
-          } else {
-              while (item.level < curLevel) {
-                  var ele = ending.pop();
-                  front += ele;
-                  if (ele == '</ul>') {
-                      curLevel--;
-                  }
-              }
-              front += '</li>';
-              front += '<li>';
-              front += itemToHtml(item);
-          }
-      }
-      while (ending.length > 0) {
-          front += ending.pop();
-      }
-      front = front.replace("<li></li>", "");
-      front = '<ul>' + front + '</ul>';
-      return front;
-  };
-
-  var handleToc = function(needToc) {
-      var tocTree = tocToTree(toPerfectToc(toc));
-      content.setToc(tocTree);
-
-      // Add it to html
-      if (needToc) {
-          var eles = document.getElementsByClassName('vnote-toc');
-          for (var i = 0; i < eles.length; ++i) {
-              eles[i].innerHTML = tocTree;
-          }
-      }
-  };
-
-  var mdHasTocSection = function(markdown) {
-      var n = markdown.search(/(\n|^)\[toc\]/i);
-      return n != -1;
-  };
-
-  var updateText = function(text) {
-      var needToc = mdHasTocSection(text);
-      var html = markdownToHtml(text, needToc);
-      placeholder.innerHTML = html;
-
-      handleToc(needToc);
-  };
-
-  var scrollToAnchor = function(anchor) {
-      document.getElementById(anchor).scrollIntoView();
-  };
-
-  new QWebChannel(qt.webChannelTransport,
-    function(channel) {
-      content = channel.objects.content;
-      updateText(content.text);
-      content.textChanged.connect(updateText);
-      content.requestScrollToAnchor.connect(scrollToAnchor);
-    }
-  );
-
-  window.onscroll = function() {
-    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset;
-    var eles = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
-
-    if (eles.length == 0) {
-        return;
-    }
-    var curIdx = 0;
-    var biaScrollTop = scrollTop + 50;
-    for (var i = 0; i < eles.length; ++i) {
-        if (biaScrollTop >= eles[i].offsetTop) {
-            curIdx = i;
-        } else {
-            break;
-        }
-    }
-
-    var curHeader = eles[curIdx].getAttribute("id");
-    if (curHeader != null) {
-        content.setHeader(curHeader);
-    }
-  }
-
-    document.onkeydown = function(e) {
-        e = e || window.event;
-        var key;
-        var shift;
-        var ctrl;
-        if (e.which) {
-            key = e.which;
-        } else {
-            key = e.keyCode;
-        }
-        shift = !!e.shiftKey;
-        ctrl = !!e.ctrlKey;
-        switch (key) {
-            case 74: // J
-                window.scrollBy(0, 100);
-                keyState = 0;
-                break;
-
-            case 75: // K
-                window.scrollBy(0, -100);
-                keyState = 0;
-                break;
-
-            case 72: // H
-                window.scrollBy(-100, 0);
-                keyState = 0;
-                break;
-
-            case 76: // L
-                window.scrollBy(100, 0);
-                keyState = 0;
-                break;
-
-            case 71: // G
-                if (shift) {
-                    var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset;
-                    var scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
-                    window.scrollTo(scrollLeft, scrollHeight);
-                    keyState = 0;
-                    break;
-                } else {
-                    if (keyState == 0) {
-                        keyState = 1;
-                    } else if (keyState == 1) {
-                        keyState = 0;
-                        var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset;
-                        window.scrollTo(scrollLeft, 0);
-                    }
-                    break;
-                }
-                return;
-
-            case 85: // U
-                keyState = 0;
-                if (ctrl) {
-                    var clientHeight = document.documentElement.clientHeight;
-                    window.scrollBy(0, -clientHeight);
-                    break;
-                }
-                return;
-
-            case 68: // D
-                keyState = 0;
-                if (ctrl) {
-                    var clientHeight = document.documentElement.clientHeight;
-                    window.scrollBy(0, clientHeight);
-                    break;
-                }
-                return;
-
-            default:
-                content.keyPressEvent(key);
-                keyState = 0;
-                return;
-        }
-        e.preventDefault();
-    }
-  </script>
-</body>
-</html>
-
-
-

+ 0 - 3
src/resources/vnote.ini

@@ -1,8 +1,5 @@
 [global]
 welcome_page_path=:/resources/welcome.html
-template_path=:/resources/template.html
-pre_template_path=:/resources/pre_template.html
-post_template_path=:/resources/post_template.html
 template_css_url=qrc:/resources/markdown.css
 current_notebook=0
 tab_stop_width=4

+ 0 - 3
src/vconfigmanager.cpp

@@ -43,9 +43,6 @@ void VConfigManager::initialize()
     baseEditPalette = QTextEdit().palette();
 
     welcomePagePath = getConfigFromSettings("global", "welcome_page_path").toString();
-    templatePath = getConfigFromSettings("global", "template_path").toString();
-    preTemplatePath = getConfigFromSettings("global", "pre_template_path").toString();
-    postTemplatePath = getConfigFromSettings("global", "post_template_path").toString();
     templateCssUrl = getConfigFromSettings("global", "template_css_url").toString();
     curNotebookIndex = getConfigFromSettings("global", "current_notebook").toInt();
 

+ 0 - 23
src/vconfigmanager.h

@@ -51,8 +51,6 @@ public:
 
     inline QString getWelcomePagePath() const;
 
-    inline QString getTemplatePath() const;
-
     inline QString getTemplateCssUrl() const;
 
     inline QFont getBaseEditFont() const;
@@ -68,9 +66,6 @@ public:
     inline MarkdownConverterType getMdConverterType() const;
     inline void setMarkdownConverterType(MarkdownConverterType type);
 
-    inline QString getPreTemplatePath() const;
-    inline QString getPostTemplatePath() const;
-
     inline int getTabStopWidth() const;
     inline void setTabStopWidth(int tabStopWidth);
     inline bool getIsExpandTab() const;
@@ -137,9 +132,6 @@ private:
     QPalette mdEditPalette;
     QVector<HighlightingStyle> mdHighlightingStyles;
     QString welcomePagePath;
-    QString templatePath;
-    QString preTemplatePath;
-    QString postTemplatePath;
     QString templateCssUrl;
     int curNotebookIndex;
 
@@ -212,11 +204,6 @@ inline QString VConfigManager::getWelcomePagePath() const
     return welcomePagePath;
 }
 
-inline QString VConfigManager::getTemplatePath() const
-{
-    return templatePath;
-}
-
 inline QString VConfigManager::getTemplateCssUrl() const
 {
     return templateCssUrl;
@@ -266,16 +253,6 @@ inline MarkdownConverterType VConfigManager::getMdConverterType() const
     return mdConverterType;
 }
 
-inline QString VConfigManager::getPreTemplatePath() const
-{
-    return preTemplatePath;
-}
-
-inline QString VConfigManager::getPostTemplatePath() const
-{
-    return postTemplatePath;
-}
-
 inline void VConfigManager::setMarkdownConverterType(MarkdownConverterType type)
 {
     if (mdConverterType == type) {

+ 5 - 19
src/vdocument.cpp

@@ -1,29 +1,15 @@
 #include "vdocument.h"
+#include "vfile.h"
 #include <QDebug>
 
-VDocument::VDocument(QObject *parent) : QObject(parent)
+VDocument::VDocument(const VFile *v_file, QObject *p_parent)
+    : QObject(p_parent), m_file(v_file)
 {
-
-}
-
-VDocument::VDocument(const QString &text, QObject *parent)
-    : QObject(parent)
-{
-    m_text = text;
-}
-
-void VDocument::setText(const QString &text)
-{
-    if (text == m_text) {
-        return;
-    }
-    m_text = text;
-    emit textChanged(m_text);
 }
 
-QString VDocument::getText()
+void VDocument::updateText()
 {
-    return m_text;
+    emit textChanged(m_file->getContent());
 }
 
 void VDocument::setToc(const QString &toc)

+ 11 - 5
src/vdocument.h

@@ -4,6 +4,8 @@
 #include <QObject>
 #include <QString>
 
+class VFile;
+
 class VDocument : public QObject
 {
     Q_OBJECT
@@ -12,10 +14,7 @@ class VDocument : public QObject
     Q_PROPERTY(QString html MEMBER m_html NOTIFY htmlChanged)
 
 public:
-    explicit VDocument(QObject *parent = 0);
-    VDocument(const QString &text, QObject *parent = 0);
-    void setText(const QString &text);
-    QString getText();
+    VDocument(const VFile *p_file, QObject *p_parent = 0);
     QString getToc();
     void scrollToAnchor(const QString &anchor);
     void setHtml(const QString &html);
@@ -26,6 +25,7 @@ public slots:
     void setHeader(const QString &anchor);
     void setLog(const QString &p_log);
     void keyPressEvent(int p_key);
+    void updateText();
 
 signals:
     void textChanged(const QString &text);
@@ -37,10 +37,16 @@ signals:
     void keyPressed(int p_key);
 
 private:
-    QString m_text;
     QString m_toc;
     QString m_header;
+
+    // m_text does NOT contain actual content.
+    QString m_text;
+
+    // When using Hoedown, m_html will contain the html content.
     QString m_html;
+
+    const VFile *m_file;
 };
 
 #endif // VDOCUMENT_H

+ 25 - 10
src/vedittab.cpp

@@ -21,7 +21,7 @@
 extern VConfigManager vconfig;
 
 VEditTab::VEditTab(VFile *p_file, OpenFileMode p_mode, QWidget *p_parent)
-    : QStackedWidget(p_parent), m_file(p_file), isEditMode(false),
+    : QStackedWidget(p_parent), m_file(p_file), isEditMode(false), document(p_file, this),
       mdConverterType(vconfig.getMdConverterType()), m_fileModified(false),
       m_editArea(NULL)
 {
@@ -109,7 +109,7 @@ void VEditTab::showFileReadMode()
         break;
     case DocType::Markdown:
         if (mdConverterType == MarkdownConverterType::Marked) {
-            document.setText(m_file->getContent());
+            document.updateText();
             updateTocFromHtml(document.getToc());
         } else {
             previewByConverter();
@@ -140,7 +140,7 @@ void VEditTab::scrollPreviewToHeader(int p_outlineIndex)
 void VEditTab::previewByConverter()
 {
     VMarkdownConverter mdConverter;
-    QString &content = m_file->getContent();
+    const QString &content = m_file->getContent();
     QString html = mdConverter.generateHtml(content, vconfig.getMarkdownExtensions());
     QRegularExpression tocExp("<p>\\[TOC\\]<\\/p>", QRegularExpression::CaseInsensitiveOption);
     QString toc = mdConverter.generateToc(content, vconfig.getMarkdownExtensions());
@@ -259,6 +259,9 @@ bool VEditTab::saveFile()
 
 void VEditTab::setupMarkdownPreview()
 {
+    const QString jsHolder("JS_PLACE_HOLDER");
+    const QString extraHolder("<!-- EXTRA_PLACE_HOLDER -->");
+
     webPreviewer = new QWebEngineView(this);
     VPreviewPage *page = new VPreviewPage(this);
     webPreviewer->setPage(page);
@@ -273,14 +276,26 @@ void VEditTab::setupMarkdownPreview()
             this, &VEditTab::handleWebKeyPressed);
     page->setWebChannel(channel);
 
-    if (mdConverterType == MarkdownConverterType::Marked) {
-        webPreviewer->setHtml(VNote::templateHtml,
-                              QUrl::fromLocalFile(m_file->retriveBasePath() + QDir::separator()));
-    } else {
-        webPreviewer->setHtml(VNote::preTemplateHtml + VNote::postTemplateHtml,
-                              QUrl::fromLocalFile(m_file->retriveBasePath() + QDir::separator()));
-    }
+    QString jsFile, extraFile;
+    switch (mdConverterType) {
+    case MarkdownConverterType::Marked:
+        jsFile = "qrc" + VNote::c_markedJsFile;
+        extraFile = "<script src=\"qrc" + VNote::c_markedExtraFile + "\"></script>";
+        break;
+
+    case MarkdownConverterType::Hoedown:
+        jsFile = "qrc" + VNote::c_hoedownJsFile;
+        break;
 
+    default:
+        Q_ASSERT(false);
+    }
+    QString htmlTemplate = VNote::s_markdownTemplate;
+    htmlTemplate.replace(jsHolder, jsFile);
+    if (!extraFile.isEmpty()) {
+        htmlTemplate.replace(extraHolder, extraFile);
+    }
+    webPreviewer->setHtml(htmlTemplate, QUrl::fromLocalFile(m_file->retriveBasePath() + QDir::separator()));
     addWidget(webPreviewer);
 }
 

+ 2 - 2
src/vfile.h

@@ -25,7 +25,7 @@ public:
     inline VDirectory *getDirectory();
     inline const VDirectory *getDirectory() const;
     inline DocType getDocType() const;
-    inline QString &getContent();
+    inline const QString &getContent() const;
     inline void setContent(const QString &p_content);
     inline VNotebook *getNotebook();
     inline QString getNotebookName() const;
@@ -78,7 +78,7 @@ inline DocType VFile::getDocType() const
     return m_docType;
 }
 
-inline QString &VFile::getContent()
+inline const QString &VFile::getContent() const
 {
     return m_content;
 }

+ 1 - 1
src/vmdedit.cpp

@@ -85,7 +85,7 @@ void VMdEdit::saveFile()
 
 void VMdEdit::reloadFile()
 {
-    QString &content = m_file->getContent();
+    const QString &content = m_file->getContent();
     Q_ASSERT(content.indexOf(QChar::ObjectReplacementCharacter) == -1);
     setPlainText(content);
     setModified(false);

+ 10 - 15
src/vnote.cpp

@@ -10,9 +10,10 @@
 
 extern VConfigManager vconfig;
 
-QString VNote::templateHtml;
-QString VNote::preTemplateHtml;
-QString VNote::postTemplateHtml;
+QString VNote::s_markdownTemplate;
+const QString VNote::c_hoedownJsFile = ":/resources/hoedown.js";
+const QString VNote::c_markedJsFile = ":/resources/marked.js";
+const QString VNote::c_markedExtraFile = ":/utils/marked/marked.min.js";
 
 VNote::VNote(QObject *parent)
     : QObject(parent), m_mainWindow(dynamic_cast<VMainWindow *>(parent))
@@ -83,14 +84,15 @@ QString VNote::getColorFromPalette(const QString &p_name) const
 
 void VNote::initTemplate()
 {
-    if (templateHtml.isEmpty() || preTemplateHtml.isEmpty()
-        || postTemplateHtml.isEmpty()) {
+    if (s_markdownTemplate.isEmpty()) {
         updateTemplate();
     }
 }
 
 void VNote::updateTemplate()
 {
+    const QString c_markdownTemplatePath(":/resources/markdown_template.html");
+
     // Get background color
     QString rgb;
     const QString &curRenderBg = vconfig.getCurRenderBackgroundColor();
@@ -109,19 +111,12 @@ void VNote::updateTemplate()
     }
     QString styleHolder("<!-- BACKGROUND_PLACE_HOLDER -->");
     QString cssHolder("CSS_PLACE_HOLDER");
-    templateHtml = VUtils::readFileFromDisk(vconfig.getTemplatePath());
-    templateHtml.replace(cssHolder, vconfig.getTemplateCssUrl());
-    if (!cssStyle.isEmpty()) {
-        templateHtml.replace(styleHolder, cssStyle);
-    }
 
-    preTemplateHtml = VUtils::readFileFromDisk(vconfig.getPreTemplatePath());
-    preTemplateHtml.replace(cssHolder, vconfig.getTemplateCssUrl());
+    s_markdownTemplate = VUtils::readFileFromDisk(c_markdownTemplatePath);
+    s_markdownTemplate.replace(cssHolder, vconfig.getTemplateCssUrl());
     if (!cssStyle.isEmpty()) {
-        preTemplateHtml.replace(styleHolder, cssStyle);
+        s_markdownTemplate.replace(styleHolder, cssStyle);
     }
-
-    postTemplateHtml = VUtils::readFileFromDisk(vconfig.getPostTemplatePath());
 }
 
 const QVector<VNotebook *> &VNote::getNotebooks() const

+ 4 - 6
src/vnote.h

@@ -25,12 +25,10 @@ public:
 
     void initTemplate();
 
-    // Used by Marked
-    static QString templateHtml;
-
-    // Used by other markdown converter
-    static QString preTemplateHtml;
-    static QString postTemplateHtml;
+    static QString s_markdownTemplate;
+    static const QString c_hoedownJsFile;
+    static const QString c_markedJsFile;
+    static const QString c_markedExtraFile;
 
     inline const QVector<QPair<QString, QString> > &getPalette() const;
     void initPalette(QPalette palette);

+ 4 - 3
src/vnote.qrc

@@ -2,11 +2,8 @@
     <qresource prefix="/">
         <file>resources/welcome.html</file>
         <file>resources/qwebchannel.js</file>
-        <file>resources/template.html</file>
         <file>resources/markdown.css</file>
         <file>utils/marked/marked.min.js</file>
-        <file>resources/post_template.html</file>
-        <file>resources/pre_template.html</file>
         <file>utils/highlightjs/highlight.pack.js</file>
         <file>utils/highlightjs/styles/androidstudio.css</file>
         <file>utils/highlightjs/styles/atom-one-dark.css</file>
@@ -85,5 +82,9 @@
         <file>resources/icons/find_replace.svg</file>
         <file>resources/icons/search_wrap.svg</file>
         <file>resources/icons/settings.svg</file>
+        <file>resources/markdown_template.html</file>
+        <file>resources/markdown_template.js</file>
+        <file>resources/hoedown.js</file>
+        <file>resources/marked.js</file>
     </qresource>
 </RCC>