InplacePreview: support online PlantUML in-place preview

This commit is contained in:
Le Tan 2018-09-12 20:36:00 +08:00
parent 3b2852aa67
commit d66fd7c1c5
4 changed files with 157 additions and 75 deletions

View File

@ -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,69 +133,26 @@ 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', '');
div = renderMermaidOne(identifier, id, timeStamp, text);
} else if (lang == 'puml') {
renderPlantUMLOne(identifier, id, timeStamp, text);
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);
}
if (!div) {
content.diagramResultReady(identifier, id, timeStamp, 'png', '');
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);
}

View File

@ -942,6 +942,11 @@ QString VUtils::generateMathJaxPreviewTemplate()
" messageStyle: \"none\"});\n"
"</script>\n";
// PlantUML.
extraFile += "<script type=\"text/javascript\" src=\"" + VNote::c_plantUMLJsFile + "\"></script>\n" +
"<script type=\"text/javascript\" src=\"" + VNote::c_plantUMLZopfliJsFile + "\"></script>\n" +
"<script>var VPlantUMLServer = '" + g_config->getPlantUMLServer() + "';</script>\n";
templ.replace(HtmlHolder::c_extraHolder, extraFile);
return templ;

View File

@ -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<CodeBlockImageCacheEntry> 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,7 +422,8 @@ void VLivePreviewHelper::processForInplacePreview(int p_idx)
m_timeStamp,
"svg",
VEditUtils::removeCodeBlockFence(vcb.m_text));
} else if (vcb.m_lang == "puml" && m_plantUMLMode == PlantUMLMode::LocalPlantUML) {
} else if (vcb.m_lang == "puml") {
if (m_plantUMLMode == PlantUMLMode::LocalPlantUML) {
if (!m_plantUMLHelper) {
m_plantUMLHelper = new VPlantUMLHelper(this);
connect(m_plantUMLHelper, &VPlantUMLHelper::resultReady,
@ -436,6 +434,13 @@ void VLivePreviewHelper::processForInplacePreview(int p_idx)
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<CodeBlockImageCacheEntry> 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;

View File

@ -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);
});