diff --git a/src/resources/mathjax_preview.js b/src/resources/mathjax_preview.js
index a765fbcb..2830b505 100644
--- a/src/resources/mathjax_preview.js
+++ b/src/resources/mathjax_preview.js
@@ -6,6 +6,11 @@ var content;
var VMermaidDivClass = 'mermaid-diagram';
var VFlowchartDivClass = 'flowchart-diagram';
+var VPlantUMLDivClass = 'plantuml-diagram';
+
+if (typeof VPlantUMLServer == 'undefined') {
+ VPlantUMLServer = 'http://www.plantuml.com/plantuml';
+}
new QWebChannel(qt.webChannelTransport,
function(channel) {
@@ -128,59 +133,12 @@ var previewDiagram = function(identifier, id, timeStamp, lang, text) {
var div = null;
if (lang == 'flow' || lang == 'flowchart') {
- flowchartIdx++;
- try {
- var graph = flowchart.parse(text);
- } catch (err) {
- content.setLog("err: " + err);
- content.diagramResultReady(identifier, id, timeStamp, 'png', '');
- return;
- }
-
- if (typeof graph == "undefined") {
- content.diagramResultReady(identifier, id, timeStamp, 'png', '');
- return;
- }
-
- div = document.createElement('div');
- div.id = 'flowchart-diagram-' + flowchartIdx;
- div.classList.add(VFlowchartDivClass);
-
- contentDiv.appendChild(div);
-
- // Draw on it after adding it to page.
- try {
- graph.drawSVG(div.id);
- } catch (err) {
- content.setLog("err: " + err);
- contentDiv.removeChild(div);
- delete div;
- content.diagramResultReady(identifier, id, timeStamp, 'png', '');
- return;
- }
+ div = renderFlowchartOne(identifier, id, timeStamp, text);
} else if (lang == 'mermaid') {
- mermaidParserErr = false;
- mermaidIdx++;
- try {
- // Do not increment mermaidIdx here.
- var graph = mermaidAPI.render('mermaid-diagram-' + mermaidIdx,
- text,
- function(){});
- } catch (err) {
- content.setLog("err: " + err);
- content.diagramResultReady(identifier, id, timeStamp, 'png', '');
- return;
- }
-
- if (mermaidParserErr || typeof graph == "undefined") {
- content.diagramResultReady(identifier, id, timeStamp, 'png', '');
- return;
- }
-
- div = document.createElement('div');
- div.classList.add(VMermaidDivClass);
- div.innerHTML = graph;
- contentDiv.appendChild(div);
+ div = renderMermaidOne(identifier, id, timeStamp, text);
+ } else if (lang == 'puml') {
+ renderPlantUMLOne(identifier, id, timeStamp, text);
+ return;
}
if (!div) {
@@ -188,9 +146,13 @@ var previewDiagram = function(identifier, id, timeStamp, lang, text) {
return;
}
- // For Flowchart.js, we need to add addtitional height. Since Mermaid is not
- // supported now, we just add it simply here.
- domtoimage.toPng(div, { height: div.clientHeight + 30 }).then(function (dataUrl) {
+ // For Flowchart.js, we need to add addtitional height.
+ var dtiOpt = {};
+ if (lang == 'flow' || lang == 'flowchart') {
+ dtiOpt = { height: div.clientHeight + 30 };
+ }
+
+ domtoimage.toPng(div, dtiOpt).then(function (dataUrl) {
var png = dataUrl.substring(dataUrl.indexOf(',') + 1);
content.diagramResultReady(identifier, id, timeStamp, 'png', png);
@@ -203,3 +165,102 @@ var previewDiagram = function(identifier, id, timeStamp, lang, text) {
delete div;
});
};
+
+var renderMermaidOne = function(identifier, id, timeStamp, text) {
+ mermaidParserErr = false;
+ mermaidIdx++;
+ try {
+ // Do not increment mermaidIdx here.
+ var graph = mermaidAPI.render('mermaid-diagram-' + mermaidIdx,
+ text,
+ function(){});
+ } catch (err) {
+ content.setLog("err: " + err);
+ return null;
+ }
+
+ if (mermaidParserErr || typeof graph == "undefined") {
+ return null;
+ }
+
+ var div = document.createElement('div');
+ div.classList.add(VMermaidDivClass);
+ div.innerHTML = graph;
+ contentDiv.appendChild(div);
+ return div;
+};
+
+var renderFlowchartOne = function(identifier, id, timeStamp, text) {
+ flowchartIdx++;
+ try {
+ var graph = flowchart.parse(text);
+ } catch (err) {
+ content.setLog("err: " + err);
+ return null;
+ }
+
+ if (typeof graph == "undefined") {
+ return null;
+ }
+
+ var div = document.createElement('div');
+ div.id = 'flowchart-diagram-' + flowchartIdx;
+ div.classList.add(VFlowchartDivClass);
+
+ contentDiv.appendChild(div);
+
+ // Draw on it after adding it to page.
+ try {
+ graph.drawSVG(div.id);
+ } catch (err) {
+ content.setLog("err: " + err);
+ contentDiv.removeChild(div);
+ delete div;
+ return null;
+ }
+
+ return div;
+};
+
+var renderPlantUMLOne = function(identifier, id, timeStamp, text) {
+ var format = 'svg';
+ var s = unescape(encodeURIComponent(text));
+ var arr = [];
+ for (var i = 0; i < s.length; i++) {
+ arr.push(s.charCodeAt(i));
+ }
+
+ var compressor = new Zopfli.RawDeflate(arr);
+ var compressed = compressor.compress();
+ var url = VPlantUMLServer + "/" + format + "/" + encode64_(compressed);
+
+ if (format == 'png') {
+ httpGet(url, 'blob', function(resp) {
+ var blob = resp;
+ var reader = new FileReader();
+ reader.onload = function () {
+ var dataUrl = reader.result;
+ var png = dataUrl.substring(dataUrl.indexOf(',') + 1);
+ content.diagramResultReady(identifier, id, timeStamp, 'png', png);
+ };
+
+ reader.readAsDataURL(blob);
+ });
+ } else if (format == 'svg') {
+ httpGet(url, 'text', function(resp) {
+ content.diagramResultReady(identifier, id, timeStamp, 'svg', resp);
+ });
+ }
+};
+
+var httpGet = function(url, type, callback) {
+ var xmlHttp = new XMLHttpRequest();
+ xmlHttp.open("GET", url);
+ xmlHttp.responseType = type;
+
+ xmlHttp.onload = function() {
+ callback(xmlHttp.response);
+ };
+
+ xmlHttp.send(null);
+}
diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp
index fcc1764d..1ddd9083 100644
--- a/src/utils/vutils.cpp
+++ b/src/utils/vutils.cpp
@@ -942,6 +942,11 @@ QString VUtils::generateMathJaxPreviewTemplate()
" messageStyle: \"none\"});\n"
"\n";
+ // PlantUML.
+ extraFile += "\n" +
+ "\n" +
+ "\n";
+
templ.replace(HtmlHolder::c_extraHolder, extraFile);
return templ;
diff --git a/src/vlivepreviewhelper.cpp b/src/vlivepreviewhelper.cpp
index 522c4b82..e4525e99 100644
--- a/src/vlivepreviewhelper.cpp
+++ b/src/vlivepreviewhelper.cpp
@@ -124,8 +124,7 @@ void VLivePreviewHelper::checkLang(const QString &p_lang,
if (m_flowchartEnabled && (p_lang == "flow" || p_lang == "flowchart")) {
p_livePreview = p_inplacePreview = true;
} else if (m_plantUMLMode != PlantUMLMode::DisablePlantUML && p_lang == "puml") {
- p_livePreview = true;
- p_inplacePreview = m_plantUMLMode == PlantUMLMode::LocalPlantUML;
+ p_livePreview = p_inplacePreview = true;
} else if (m_graphvizEnabled && p_lang == "dot") {
p_livePreview = p_inplacePreview = true;
} else if (m_mermaidEnabled && p_lang == "mermaid") {
@@ -380,14 +379,12 @@ void VLivePreviewHelper::localAsyncResultReady(int p_id,
}
CodeBlockPreviewInfo &cb = m_codeBlocks[idx];
- const QString &text = cb.codeBlock().m_text;
-
QSharedPointer entry(new CodeBlockImageCacheEntry(p_timeStamp,
p_format,
p_result,
background,
getScaleFactor(cb)));
- m_cache.insert(text, entry);
+ m_cache.insert(cb.codeBlock().m_text, entry);
cb.setImageData(p_format, p_result);
cb.updateInplacePreview(m_editor, m_doc, entry->m_image, QString(), background);
@@ -425,17 +422,25 @@ void VLivePreviewHelper::processForInplacePreview(int p_idx)
m_timeStamp,
"svg",
VEditUtils::removeCodeBlockFence(vcb.m_text));
- } else if (vcb.m_lang == "puml" && m_plantUMLMode == PlantUMLMode::LocalPlantUML) {
- if (!m_plantUMLHelper) {
- m_plantUMLHelper = new VPlantUMLHelper(this);
- connect(m_plantUMLHelper, &VPlantUMLHelper::resultReady,
- this, &VLivePreviewHelper::localAsyncResultReady);
- }
+ } else if (vcb.m_lang == "puml") {
+ if (m_plantUMLMode == PlantUMLMode::LocalPlantUML) {
+ if (!m_plantUMLHelper) {
+ m_plantUMLHelper = new VPlantUMLHelper(this);
+ connect(m_plantUMLHelper, &VPlantUMLHelper::resultReady,
+ this, &VLivePreviewHelper::localAsyncResultReady);
+ }
- m_plantUMLHelper->processAsync(p_idx | LANG_PREFIX_PLANTUML | TYPE_INPLACE_PREVIEW,
- m_timeStamp,
- "svg",
- VEditUtils::removeCodeBlockFence(vcb.m_text));
+ m_plantUMLHelper->processAsync(p_idx | LANG_PREFIX_PLANTUML | TYPE_INPLACE_PREVIEW,
+ m_timeStamp,
+ "svg",
+ VEditUtils::removeCodeBlockFence(vcb.m_text));
+ } else {
+ m_mathJaxHelper->previewDiagram(m_mathJaxID,
+ p_idx,
+ m_timeStamp,
+ vcb.m_lang,
+ VEditUtils::removeCodeBlockFence(vcb.m_text));
+ }
} else if (vcb.m_lang == "flow"
|| vcb.m_lang == "flowchart") {
m_mathJaxHelper->previewDiagram(m_mathJaxID,
@@ -497,16 +502,21 @@ void VLivePreviewHelper::mathjaxPreviewResultReady(int p_identitifer,
}
CodeBlockPreviewInfo &cb = m_codeBlocks[p_id];
- const QString &text = cb.codeBlock().m_text;
+ const VCodeBlock &vcb = cb.codeBlock();
+
+ QString background;
+ if (vcb.m_lang == "puml") {
+ background = g_config->getEditorPreviewImageBg();
+ }
QSharedPointer entry(new CodeBlockImageCacheEntry(p_timeStamp,
p_format,
p_data,
- "",
+ background,
getScaleFactor(cb)));
- m_cache.insert(text, entry);
+ m_cache.insert(vcb.m_text, entry);
- cb.updateInplacePreview(m_editor, m_doc, entry->m_image);
+ cb.updateInplacePreview(m_editor, m_doc, entry->m_image, QString(), background);
if (cb.inplacePreview()) {
entry->m_imageName = cb.inplacePreview()->m_name;
diff --git a/src/vmathjaxpreviewhelper.cpp b/src/vmathjaxpreviewhelper.cpp
index 62c741bf..127a4827 100644
--- a/src/vmathjaxpreviewhelper.cpp
+++ b/src/vmathjaxpreviewhelper.cpp
@@ -60,7 +60,13 @@ void VMathJaxPreviewHelper::doInit()
TimeStamp p_timeStamp,
const QString &p_format,
const QString &p_data) {
- QByteArray ba = QByteArray::fromBase64(p_data.toUtf8());
+ QByteArray ba;
+ if (p_format == "png") {
+ ba = QByteArray::fromBase64(p_data.toUtf8());
+ } else {
+ ba = p_data.toUtf8();
+ }
+
emit diagramPreviewResultReady(p_identifier, p_id, p_timeStamp, p_format, ba);
});