mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
InplacePreview: support online PlantUML in-place preview
This commit is contained in:
parent
3b2852aa67
commit
d66fd7c1c5
@ -6,6 +6,11 @@ var content;
|
|||||||
|
|
||||||
var VMermaidDivClass = 'mermaid-diagram';
|
var VMermaidDivClass = 'mermaid-diagram';
|
||||||
var VFlowchartDivClass = 'flowchart-diagram';
|
var VFlowchartDivClass = 'flowchart-diagram';
|
||||||
|
var VPlantUMLDivClass = 'plantuml-diagram';
|
||||||
|
|
||||||
|
if (typeof VPlantUMLServer == 'undefined') {
|
||||||
|
VPlantUMLServer = 'http://www.plantuml.com/plantuml';
|
||||||
|
}
|
||||||
|
|
||||||
new QWebChannel(qt.webChannelTransport,
|
new QWebChannel(qt.webChannelTransport,
|
||||||
function(channel) {
|
function(channel) {
|
||||||
@ -128,59 +133,12 @@ var previewDiagram = function(identifier, id, timeStamp, lang, text) {
|
|||||||
|
|
||||||
var div = null;
|
var div = null;
|
||||||
if (lang == 'flow' || lang == 'flowchart') {
|
if (lang == 'flow' || lang == 'flowchart') {
|
||||||
flowchartIdx++;
|
div = renderFlowchartOne(identifier, id, timeStamp, text);
|
||||||
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;
|
|
||||||
}
|
|
||||||
} else if (lang == 'mermaid') {
|
} else if (lang == 'mermaid') {
|
||||||
mermaidParserErr = false;
|
div = renderMermaidOne(identifier, id, timeStamp, text);
|
||||||
mermaidIdx++;
|
} else if (lang == 'puml') {
|
||||||
try {
|
renderPlantUMLOne(identifier, id, timeStamp, text);
|
||||||
// Do not increment mermaidIdx here.
|
return;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!div) {
|
if (!div) {
|
||||||
@ -188,9 +146,13 @@ var previewDiagram = function(identifier, id, timeStamp, lang, text) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Flowchart.js, we need to add addtitional height. Since Mermaid is not
|
// For Flowchart.js, we need to add addtitional height.
|
||||||
// supported now, we just add it simply here.
|
var dtiOpt = {};
|
||||||
domtoimage.toPng(div, { height: div.clientHeight + 30 }).then(function (dataUrl) {
|
if (lang == 'flow' || lang == 'flowchart') {
|
||||||
|
dtiOpt = { height: div.clientHeight + 30 };
|
||||||
|
}
|
||||||
|
|
||||||
|
domtoimage.toPng(div, dtiOpt).then(function (dataUrl) {
|
||||||
var png = dataUrl.substring(dataUrl.indexOf(',') + 1);
|
var png = dataUrl.substring(dataUrl.indexOf(',') + 1);
|
||||||
content.diagramResultReady(identifier, id, timeStamp, 'png', png);
|
content.diagramResultReady(identifier, id, timeStamp, 'png', png);
|
||||||
|
|
||||||
@ -203,3 +165,102 @@ var previewDiagram = function(identifier, id, timeStamp, lang, text) {
|
|||||||
delete div;
|
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);
|
||||||
|
}
|
||||||
|
@ -942,6 +942,11 @@ QString VUtils::generateMathJaxPreviewTemplate()
|
|||||||
" messageStyle: \"none\"});\n"
|
" messageStyle: \"none\"});\n"
|
||||||
"</script>\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);
|
templ.replace(HtmlHolder::c_extraHolder, extraFile);
|
||||||
|
|
||||||
return templ;
|
return templ;
|
||||||
|
@ -124,8 +124,7 @@ void VLivePreviewHelper::checkLang(const QString &p_lang,
|
|||||||
if (m_flowchartEnabled && (p_lang == "flow" || p_lang == "flowchart")) {
|
if (m_flowchartEnabled && (p_lang == "flow" || p_lang == "flowchart")) {
|
||||||
p_livePreview = p_inplacePreview = true;
|
p_livePreview = p_inplacePreview = true;
|
||||||
} else if (m_plantUMLMode != PlantUMLMode::DisablePlantUML && p_lang == "puml") {
|
} else if (m_plantUMLMode != PlantUMLMode::DisablePlantUML && p_lang == "puml") {
|
||||||
p_livePreview = true;
|
p_livePreview = p_inplacePreview = true;
|
||||||
p_inplacePreview = m_plantUMLMode == PlantUMLMode::LocalPlantUML;
|
|
||||||
} else if (m_graphvizEnabled && p_lang == "dot") {
|
} else if (m_graphvizEnabled && p_lang == "dot") {
|
||||||
p_livePreview = p_inplacePreview = true;
|
p_livePreview = p_inplacePreview = true;
|
||||||
} else if (m_mermaidEnabled && p_lang == "mermaid") {
|
} else if (m_mermaidEnabled && p_lang == "mermaid") {
|
||||||
@ -380,14 +379,12 @@ void VLivePreviewHelper::localAsyncResultReady(int p_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CodeBlockPreviewInfo &cb = m_codeBlocks[idx];
|
CodeBlockPreviewInfo &cb = m_codeBlocks[idx];
|
||||||
const QString &text = cb.codeBlock().m_text;
|
|
||||||
|
|
||||||
QSharedPointer<CodeBlockImageCacheEntry> entry(new CodeBlockImageCacheEntry(p_timeStamp,
|
QSharedPointer<CodeBlockImageCacheEntry> entry(new CodeBlockImageCacheEntry(p_timeStamp,
|
||||||
p_format,
|
p_format,
|
||||||
p_result,
|
p_result,
|
||||||
background,
|
background,
|
||||||
getScaleFactor(cb)));
|
getScaleFactor(cb)));
|
||||||
m_cache.insert(text, entry);
|
m_cache.insert(cb.codeBlock().m_text, entry);
|
||||||
|
|
||||||
cb.setImageData(p_format, p_result);
|
cb.setImageData(p_format, p_result);
|
||||||
cb.updateInplacePreview(m_editor, m_doc, entry->m_image, QString(), background);
|
cb.updateInplacePreview(m_editor, m_doc, entry->m_image, QString(), background);
|
||||||
@ -425,17 +422,25 @@ void VLivePreviewHelper::processForInplacePreview(int p_idx)
|
|||||||
m_timeStamp,
|
m_timeStamp,
|
||||||
"svg",
|
"svg",
|
||||||
VEditUtils::removeCodeBlockFence(vcb.m_text));
|
VEditUtils::removeCodeBlockFence(vcb.m_text));
|
||||||
} else if (vcb.m_lang == "puml" && m_plantUMLMode == PlantUMLMode::LocalPlantUML) {
|
} else if (vcb.m_lang == "puml") {
|
||||||
if (!m_plantUMLHelper) {
|
if (m_plantUMLMode == PlantUMLMode::LocalPlantUML) {
|
||||||
m_plantUMLHelper = new VPlantUMLHelper(this);
|
if (!m_plantUMLHelper) {
|
||||||
connect(m_plantUMLHelper, &VPlantUMLHelper::resultReady,
|
m_plantUMLHelper = new VPlantUMLHelper(this);
|
||||||
this, &VLivePreviewHelper::localAsyncResultReady);
|
connect(m_plantUMLHelper, &VPlantUMLHelper::resultReady,
|
||||||
}
|
this, &VLivePreviewHelper::localAsyncResultReady);
|
||||||
|
}
|
||||||
|
|
||||||
m_plantUMLHelper->processAsync(p_idx | LANG_PREFIX_PLANTUML | TYPE_INPLACE_PREVIEW,
|
m_plantUMLHelper->processAsync(p_idx | LANG_PREFIX_PLANTUML | TYPE_INPLACE_PREVIEW,
|
||||||
m_timeStamp,
|
m_timeStamp,
|
||||||
"svg",
|
"svg",
|
||||||
VEditUtils::removeCodeBlockFence(vcb.m_text));
|
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"
|
} else if (vcb.m_lang == "flow"
|
||||||
|| vcb.m_lang == "flowchart") {
|
|| vcb.m_lang == "flowchart") {
|
||||||
m_mathJaxHelper->previewDiagram(m_mathJaxID,
|
m_mathJaxHelper->previewDiagram(m_mathJaxID,
|
||||||
@ -497,16 +502,21 @@ void VLivePreviewHelper::mathjaxPreviewResultReady(int p_identitifer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CodeBlockPreviewInfo &cb = m_codeBlocks[p_id];
|
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,
|
QSharedPointer<CodeBlockImageCacheEntry> entry(new CodeBlockImageCacheEntry(p_timeStamp,
|
||||||
p_format,
|
p_format,
|
||||||
p_data,
|
p_data,
|
||||||
"",
|
background,
|
||||||
getScaleFactor(cb)));
|
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()) {
|
if (cb.inplacePreview()) {
|
||||||
entry->m_imageName = cb.inplacePreview()->m_name;
|
entry->m_imageName = cb.inplacePreview()->m_name;
|
||||||
|
@ -60,7 +60,13 @@ void VMathJaxPreviewHelper::doInit()
|
|||||||
TimeStamp p_timeStamp,
|
TimeStamp p_timeStamp,
|
||||||
const QString &p_format,
|
const QString &p_format,
|
||||||
const QString &p_data) {
|
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);
|
emit diagramPreviewResultReady(p_identifier, p_id, p_timeStamp, p_format, ba);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user