implement drawio support

Signed-off-by: Ys Liu <seanly@opsbox.dev>
pull/873/head
Seanly Liu 2023-07-01 23:20:10 +08:00 committed by Ys Liu
parent 9ea4b9e80a
commit ebb5bdb14b
6 changed files with 307 additions and 58 deletions

View File

@ -367,6 +367,7 @@ gfm_task = GFM task
attachment = attachment
json_to_table = Json converted to table
template = template
draw = draw
close_preview = disable preview
modify_history = modify history
sidebar = sidebar

View File

@ -367,6 +367,7 @@ gfm_task = GFM 任务列表
attachment = 附件
json_to_table = Json转换为表格
template = 模板
draw = 画图
close_preview = 关闭实时预览
modify_history = 修改历史
sidebar = 边栏

View File

@ -3950,9 +3950,12 @@
}
return "<svg class='mindmap' style='width:100%;min-height=150px;height:"+custom_height+"px;' id='mindmap-"+ map_id +"'>"+code+"</svg>";
}
if (lang === "drawio") {
var svgCode = decodeURIComponent(escape(window.atob(code)))
return "<div class=\"svg\" style=\"overflow: auto; padding: 10px;\">" + svgCode + "</div>"
}
else
{
return marked.Renderer.prototype.code.apply(this, arguments);
}
};
@ -4029,7 +4032,6 @@
html += "<li class=\"directory-item\"><a class=\"directory-item-link directory-item-link-" + level + "\" href=\"#" + id + "\" level=\"" + level + "\">" + text + "</a></li>";
lastLevel = level;
}
console.log(html);
var tocContainer = container.find(".markdown-toc");

View File

@ -3,6 +3,150 @@ $(function () {
js : window.katex.js,
css : window.katex.css
};
var drawio = new Object()
drawio.processMarkers = function (from, to) {
var _this = this
var found = null
var foundStart = 0
var cm = window.editor.cm;
cm.doc.getAllMarks().forEach(mk => {
if (mk.__kind) {
mk.clear()
}
})
cm.eachLine(from, to, function (ln) {
const line = ln.lineNo()
if (ln.text.startsWith('```drawio')) {
found = 'drawio'
foundStart = line
} else if (ln.text === '```' && found) {
switch (found) {
// -> DRAWIO
case 'drawio': {
if (line - foundStart !== 2) {
return
}
_this.addMarker({
kind: 'drawio',
from: { line: foundStart, ch: 3 },
to: { line: foundStart, ch: 10 },
text: 'drawio',
action: (function (start, end) {
return function (ev) {
cm.doc.setSelection({ line: start, ch: 0 }, { line: end, ch: 3 })
try {
// save state data
const raw = cm.doc.getLine(end - 1)
window.sessionStorage.setItem("drawio", raw);
_this.show()
} catch (err) {
console.log(err)
}
}
})(foundStart, line)
})
if (ln.height > 0) {
cm.foldCode(foundStart)
}
break;
}
}
found = null
}
})
}
drawio.addMarker = function ({ kind, from, to, text, action }) {
const markerElm = document.createElement('span')
markerElm.appendChild(document.createTextNode(text))
markerElm.className = 'CodeMirror-buttonmarker'
markerElm.addEventListener('click', action)
var cm = window.editor.cm;
cm.markText(from, to, { replacedWith: markerElm, __kind: kind })
}
drawio.show = function () {
const drawUrl = 'https://embed.diagrams.net/?embed=1&libraries=1&proto=json&spin=1&saveAndExit=1&noSaveBtn=1&noExitBtn=0';
this.div = document.createElement('div');
this.div.id = 'diagram';
this.gXml = '';
this.div.innerHTML = '';
this.iframe = document.createElement('iframe');
this.iframe.setAttribute('frameborder', '0');
this.iframe.style.zIndex = 9999;
this.iframe.style.width = "100%";
this.iframe.style.height = "100%";
this.iframe.style.position = "absolute";
this.iframe.style.top = window.scrollY + "px";
binded = this.postMessage.bind(this);
window.addEventListener("message", binded, false);
this.iframe.setAttribute('src', drawUrl);
document.body.appendChild(this.iframe);
}
drawio.postMessage = function (evt) {
if (evt.data.length < 1) return
var msg = JSON.parse(evt.data)
var svg = '';
switch (msg.event) {
case "configure":
this.iframe.contentWindow.postMessage(
JSON.stringify({
action: "configure",
config: {
defaultFonts: ["Humor Sans", "Helvetica", "Times New Roman"],
},
}),
"*"
);
break;
case "init":
code = window.sessionStorage.getItem("drawio")
svg = decodeURIComponent(escape(window.atob(code)))
this.iframe.contentWindow.postMessage(
JSON.stringify({ action: "load", autosave: 1, xml: svg }),
"*"
);
break;
case "autosave":
window.sessionStorage.setItem("drawio", svg);
break;
case "save":
this.iframe.contentWindow.postMessage(
JSON.stringify({
action: "export",
format: "xmlsvg",
xml: msg.xml,
spin: "Updating page",
}),
"*"
);
break;
case "export":
svgData = msg.data.substring(msg.data.indexOf(',') + 1);
// clean event bind
window.removeEventListener("message", this.binded);
document.body.removeChild(this.iframe);
// write back svg data
var cm = window.editor.cm;
cm.doc.replaceSelection('```drawio\n' + svgData + '\n```', 'start')
// clean state data
window.sessionStorage.setItem("drawio", '');
break;
case "exit":
window.removeEventListener("message", this.binded);
document.body.removeChild(this.iframe);
break;
}
}
window.editormdLocales = {
'zh-CN': {
@ -81,8 +225,10 @@ $(function () {
highlightStyle: window.highlightStyle ? window.highlightStyle : "github",
tex:true,
saveHTMLToTextarea: true,
codeFold: true,
onload: function() {
this.registerHelper()
this.hideToolbar();
var keyMap = {
"Ctrl-S": function(cm) {
@ -111,15 +257,89 @@ $(function () {
}
}
});
window.isLoad = true;
this.tableEditor = TableEditor.initTableEditor(this.cm)
},
onchange: function () {
/**
*
*
* 1. processMarkers
* 2.
* 3.
* 4.
*/
var cm = window.editor.cm;
drawio.processMarkers(cm.firstLine(), cm.lastLine() + 1)
resetEditorChanged(true);
}
});
editormd.fn.registerHelper = function () {
const maxDepth = 100
const codeBlockStartMatch = /^`{3}[a-zA-Z0-9]+$/
const codeBlockEndMatch = /^`{3}$/
editormd.$CodeMirror.registerHelper('fold', 'markdown', function (cm, start) {
const firstLine = cm.getLine(start.line)
const lastLineNo = cm.lastLine()
let end
function isHeader(lineNo) {
const tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0))
return tokentype && /\bheader\b/.test(tokentype)
}
function headerLevel(lineNo, line, nextLine) {
let match = line && line.match(/^#+/)
if (match && isHeader(lineNo)) return match[0].length
match = nextLine && nextLine.match(/^[=-]+\s*$/)
if (match && isHeader(lineNo + 1)) return nextLine[0] === '=' ? 1 : 2
return maxDepth
}
// -> CODE BLOCK
if (codeBlockStartMatch.test(cm.getLine(start.line))) {
end = start.line
let nextNextLine = cm.getLine(end + 1)
while (end < lastLineNo) {
if (codeBlockEndMatch.test(nextNextLine)) {
end++
break
}
end++
nextNextLine = cm.getLine(end + 1)
}
} else {
// -> HEADER
let nextLine = cm.getLine(start.line + 1)
const level = headerLevel(start.line, firstLine, nextLine)
if (level === maxDepth) return undefined
end = start.line
let nextNextLine = cm.getLine(end + 2)
while (end < lastLineNo) {
if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break
++end
nextLine = nextNextLine
nextNextLine = cm.getLine(end + 2)
}
}
return {
from: CodeMirror.Pos(start.line, firstLine.length),
to: CodeMirror.Pos(end, cm.getLine(end).length)
}
})
}
function insertToMarkdown(body) {
window.isLoad = true;
window.editor.insertValue(body);
@ -138,20 +358,20 @@ $(function () {
*
*/
$("#editormd-tools").on("click", "a[class!='disabled']", function () {
var name = $(this).find("i").attr("name");
if (name === "attachment") {
$("#uploadAttachModal").modal("show");
} else if (name === "history") {
window.documentHistory();
} else if (name === "save") {
var name = $(this).find("i").attr("name");
if (name === "attachment") {
$("#uploadAttachModal").modal("show");
} else if (name === "history") {
window.documentHistory();
} else if (name === "save") {
saveDocument(false);
} else if (name === "template") {
$("#documentTemplateModal").modal("show");
} else if (name === "template") {
$("#documentTemplateModal").modal("show");
} else if(name === "save-template"){
$("#saveTemplateModal").modal("show");
$("#saveTemplateModal").modal("show");
} else if(name === 'json'){
$("#convertJsonToTableModal").modal("show");
} else if (name === "sidebar") {
$("#convertJsonToTableModal").modal("show");
} else if (name === "sidebar") {
$("#manualCategory").toggle(0, "swing", function () {
var $then = $("#manualEditorContainer");
var left = parseInt($then.css("left"));
@ -163,7 +383,7 @@ $(function () {
}
window.editor.resize();
});
} else if (name === "release") {
} else if (name === "release") {
if (Object.prototype.toString.call(window.documentCategory) === '[object Array]' && window.documentCategory.length > 0) {
if ($("#markdown-save").hasClass('change')) {
var confirm_result = confirm(editormdLocales[lang].contentUnsaved);
@ -177,31 +397,46 @@ $(function () {
} else {
layer.msg(editormdLocales[lang].noDocNeedPublish)
}
} else if (name === "tasks") {
// 插入 GFM 任务列表
var cm = window.editor.cm;
var selection = cm.getSelection();
} else if (name === "tasks") {
// 插入 GFM 任务列表
var cm = window.editor.cm;
var selection = cm.getSelection();
var cursor = cm.getCursor();
if (selection === "") {
cm.setCursor(cursor.line, 0);
cm.replaceSelection("- [x] " + selection);
cm.setCursor(cursor.line, cursor.ch + 6);
} else {
var selectionText = selection.split("\n");
if (selection === "") {
cm.setCursor(cursor.line, 0);
cm.replaceSelection("- [x] " + selection);
cm.setCursor(cursor.line, cursor.ch + 6);
} else {
var selectionText = selection.split("\n");
for (var i = 0, len = selectionText.length; i < len; i++) {
selectionText[i] = (selectionText[i] === "") ? "" : "- [x] " + selectionText[i];
}
cm.replaceSelection(selectionText.join("\n"));
}
} else {
var action = window.editor.toolbarHandlers[name];
for (var i = 0, len = selectionText.length; i < len; i++) {
selectionText[i] = (selectionText[i] === "") ? "" : "- [x] " + selectionText[i];
}
cm.replaceSelection(selectionText.join("\n"));
}
} else if (name === "drawio") {
/**
* TODO:
*
* 1.
* 2.
*/
window.sessionStorage.setItem("drawio", '');
if (!!action && action !== "undefined") {
$.proxy(action, window.editor)();
window.editor.focus();
}
}
var cm = window.editor.cm;
const selStartLine = cm.getCursor('from').line
const selEndLine = cm.getCursor('to').line + 1
drawio.processMarkers(selStartLine, selEndLine)
drawio.show()
} else {
var action = window.editor.toolbarHandlers[name];
if (!!action && action !== "undefined") {
$.proxy(action, window.editor)();
window.editor.focus();
}
}
}) ;
/***
@ -321,7 +556,7 @@ $(function () {
}
});
}
/**
*
@ -496,8 +731,8 @@ $(function () {
},
url : window.template.listUrl,
data: {"identify":window.book.identify},
type: "POST",
dataType: "html",
type: "POST",
dataType: "html",
success: function ($res) {
$("#displayCustomsTemplateList").html($res);
},
@ -567,9 +802,9 @@ $(function () {
type: "get",
success : function ($res) {
if ($res.errcode !== 0){
layer.msg($res.message);
return;
}
layer.msg($res.message);
return;
}
window.isLoad = true;
window.editor.clear();
window.editor.insertValue($res.data.template_content);
@ -606,30 +841,30 @@ $(function () {
});
$("#btnInsertTable").on("click",function () {
var content = $("#jsonContent").val();
var content = $("#jsonContent").val();
if(content !== "") {
try {
var jsonObj = $.parseJSON(content);
try {
var jsonObj = $.parseJSON(content);
var data = foreachJson(jsonObj,"");
var table = "| " + window.editormdLocales[window.lang].paramName
+ " | " + window.editormdLocales[window.lang].paramType
+ " | " + window.editormdLocales[window.lang].example
+ " | " + window.editormdLocales[window.lang].remark
+ " |\n| ------------ | ------------ | ------------ | ------------ |\n";
var table = "| " + window.editormdLocales[window.lang].paramName
+ " | " + window.editormdLocales[window.lang].paramType
+ " | " + window.editormdLocales[window.lang].example
+ " | " + window.editormdLocales[window.lang].remark
+ " |\n| ------------ | ------------ | ------------ | ------------ |\n";
$.each(data,function (i,item) {
table += "|" + item.key + "|" + item.type + "|" + item.value +"| |\n";
});
});
insertToMarkdown(table);
}catch (e) {
showError("Json 格式错误:" + e.toString(),"#json-error-message");
return;
}
}
$("#convertJsonToTableModal").modal("hide");
return;
}
}
$("#convertJsonToTableModal").modal("hide");
});
$("#convertJsonToTableModal").on("hidden.bs.modal",function () {
$("#jsonContent").val("");
}).on("shown.bs.modal",function () {
$("#jsonContent").focus();
});
});
});

View File

@ -51,6 +51,15 @@
display: none;
}
}
.svg {
display: inline-block;
position: relative;
width: 100%;
height: 100%;
vertical-align: middle;
overflow: auto;
}
</style>
</head>
<body>

View File

@ -101,6 +101,7 @@
<a href="javascript:;" data-toggle="tooltip" data-title="{{i18n .Lang "doc.gfm_task"}}"><i class="fa fa-tasks item" name="tasks" aria-hidden="true"></i></a>
<a href="javascript:;" data-toggle="tooltip" data-title="{{i18n .Lang "doc.attachment"}}"><i class="fa fa-paperclip item" aria-hidden="true" name="attachment"></i></a>
<a href="javascript:;" data-toggle="tooltip" data-title="{{i18n .Lang "doc.json_to_table"}}"><i class="fa fa-wrench item" aria-hidden="true" name="json"></i></a>
<a href="javascript:;" data-toggle="tooltip" data-title="{{i18n .Lang "doc.draw"}}"><i class="fa fa-paint-brush item" aria-hidden="true" name="drawio"></i></a>
<a href="javascript:;" data-toggle="tooltip" data-title="{{i18n .Lang "doc.template"}}"><i class="fa fa-tachometer last" name="template"></i></a>
</div>
@ -450,7 +451,7 @@
<script src="{{cdnjs "/static/bootstrap/js/bootstrap.min.js"}}"></script>
<script src="{{cdnjs "/static/webuploader/webuploader.min.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/jstree/3.3.4/jstree.min.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/editor.md/editormd.min.js" "version"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/editor.md/editormd.js" "version"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/layer/layer.js"}}" type="text/javascript" ></script>
<script src="{{cdnjs "/static/js/jquery.form.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/js/array.js" "version"}}" type="text/javascript"></script>