[WIP] Support Diagram (#529)

* feat: basic use of mermaid

* feat: add flowchart dep

* feat: handle flowchart render error

* feat: edit sequence diagram

* feat: support vega-lite

* fix: #534

* feat: basic use of mermaid

* feat: add flowchart dep

* feat: handle flowchart render error

* feat: edit sequence diagram

* feat: support vega-lite

* feat: copy paste and import and export of diagram

* finish

* fix: #537

* update: dependence
This commit is contained in:
Ran Luo 2018-11-01 22:42:34 +08:00 committed by GitHub
parent f43504b2d0
commit 55092ff15d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 4678 additions and 411 deletions

View File

@ -1,5 +1,5 @@
test/unit/coverage/** test/unit/coverage/**
test/unit/*.js test/unit/*.js
test/e2e/*.js test/e2e/*.js
src/muya/lib/assets/symbolIcon/index.js
src/renderer/assets/symbolIcon/index.js src/renderer/assets/symbolIcon/index.js
src/muya/lib/assets/libs/*.js

1596
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -136,18 +136,25 @@
"dompurify": "^1.0.8", "dompurify": "^1.0.8",
"element-ui": "^2.4.7", "element-ui": "^2.4.7",
"file-icons-js": "^1.0.3", "file-icons-js": "^1.0.3",
"flowchart.js": "^1.11.3",
"fs-extra": "^7.0.0", "fs-extra": "^7.0.0",
"fuzzaldrin": "^2.1.0", "fuzzaldrin": "^2.1.0",
"github-markdown-css": "^2.10.0", "github-markdown-css": "^2.10.0",
"html-tags": "^2.0.0", "html-tags": "^2.0.0",
"katex": "^0.10.0-rc.1", "katex": "^0.10.0",
"markdown-toc": "^1.2.0", "markdown-toc": "^1.2.0",
"mermaid": "^8.0.0-rc.8",
"popper.js": "^1.14.4", "popper.js": "^1.14.4",
"prismjs2": "^1.15.0", "prismjs2": "^1.15.0",
"snabbdom": "^0.7.2", "snabbdom": "^0.7.2",
"snabbdom-to-html": "^5.1.1", "snabbdom-to-html": "^5.1.1",
"snapsvg": "^0.5.1",
"turndown": "^5.0.1", "turndown": "^5.0.1",
"turndown-plugin-gfm": "^1.0.2", "turndown-plugin-gfm": "^1.0.2",
"underscore": "^1.9.1",
"vega": "^4.3.0",
"vega-embed": "^3.21.1",
"vega-lite": "^3.0.0-rc8",
"vue": "^2.5.17", "vue": "^2.5.17",
"vue-electron": "^1.0.6", "vue-electron": "^1.0.6",
"vuex": "^3.0.1" "vuex": "^3.0.1"
@ -170,12 +177,12 @@
"css-loader": "^1.0.0", "css-loader": "^1.0.0",
"del": "^3.0.0", "del": "^3.0.0",
"devtron": "^1.4.0", "devtron": "^1.4.0",
"electron": "^3.0.5", "electron": "^3.0.7",
"electron-builder": "^20.28.4", "electron-builder": "^20.29.0",
"electron-debug": "^2.0.0", "electron-debug": "^2.0.0",
"electron-devtools-installer": "^2.2.4", "electron-devtools-installer": "^2.2.4",
"electron-updater": "^3.1.2", "electron-updater": "^3.1.6",
"electron-window-state": "^5.0.1", "electron-window-state": "^5.0.2",
"eslint": "^4.19.1", "eslint": "^4.19.1",
"eslint-config-standard": "^11.0.0", "eslint-config-standard": "^11.0.0",
"eslint-friendly-formatter": "^4.0.1", "eslint-friendly-formatter": "^4.0.1",

View File

@ -80,7 +80,7 @@ let viewMenu = {
}] }]
} }
if (process.env.NODE_ENV !== 'production' || process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'development') {
// add devtool when development // add devtool when development
viewMenu.submenu.push({ viewMenu.submenu.push({
label: 'Toggle Developer Tools', label: 'Toggle Developer Tools',

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1540911659576" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2485" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M597.333 85.333c-47.128 0-85.333 38.205-85.333 85.334 0 7.805 0.704 15.483 2.667 22.666L424 266.667C412.03 260.269 398.521 256 384 256c-28.074 0-52.448 13.742-68 34.667l-62.667-13.334c-9.47-36.808-42.902-64-82.666-64-47.129 0-85.334 38.205-85.334 85.334 0 47.128 38.205 85.333 85.334 85.333 30.093 0 56.807-15.136 72-38.667l57.333 12c7.457 39.52 42.312 69.334 84 69.334 47.128 0 85.333-38.205 85.333-85.334 0-7.805-0.703-15.483-2.666-22.666l90.666-72c11.837 6.213 25.704 9.333 40 9.333 13.884 0 27.081-3.451 38.667-9.333L772 360c-2.259 7.663-4 15.605-4 24 0 47.128 38.205 85.333 85.333 85.333 47.129 0 85.334-38.205 85.334-85.333s-38.205-85.333-85.334-85.333c-13.883 0-27.08 3.45-38.666 9.333l-136-113.333c2.259-7.663 4-15.606 4-24 0-47.129-38.205-85.334-85.334-85.334zM512 512v426.667h170.667V512H512z m213.333 128v298.667H896V640H725.333z m-640 42.667v256H256v-256H85.333z m213.334 42.666v213.334h170.666V725.333H298.667z" p-id="2486"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1540728996967" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2678" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M460.196316 192.395705l-97.49618 97.49618L162.792167 289.891885c-7.100597 0-13.245353 2.594376-18.434106 7.783293s-7.783293 11.333509-7.783293 18.434106l0 313.790167c-15.839729 16.385854-28.538794 38.506911-38.097195 66.36301s-14.337601 58.443145-14.337601 91.76114c0 50.79626 10.241261 94.082372 30.723619 129.858335s45.197792 53.663945 74.146302 53.663945c26.217398 0 49.021152-15.020461 68.411098-45.06122 19.389946-30.040759 30.996599-67.455258 34.820123-112.243498l106.508457 0 0 157.304718c0 14.201029 5.188916 26.490542 15.566585 36.868211 10.377669 10.377833 22.667182 15.566585 36.868375 15.566585l104.869757 0c14.747317 0 27.173238-5.188916 37.277927-15.566585 10.104689-10.377669 15.157033-22.667182 15.157033-36.868211l0-157.304718 106.508457 0c3.82336 44.788076 15.430013 82.202575 34.820123 112.243498 19.389946 30.040759 42.1937 45.06122 68.411098 45.06122 28.948347 0 53.663945-17.887982 74.146302-53.663945s30.723619-79.062075 30.723619-129.858335-10.241261-94.082536-30.723619-129.858335-45.197792-53.663781-74.146302-53.663781c-26.217398 0-49.021152 15.020461-68.411098 45.06122-19.39011 30.040759-30.996763 67.455258-34.820123 112.243498l-106.508457 0L608.489249 604.501321c0-14.747317-5.052344-27.173238-15.157033-37.277927-10.104689-10.104689-22.53061-15.157033-37.277927-15.157033L503.619 552.06636 503.619 432.449286l98.315449-98.315449c4.915772-4.915772 7.373577-10.787385 7.373577-17.614838s-2.457968-12.699065-7.373577-17.614838l-106.508457-106.508457c-4.915772-4.915772-10.787385-7.373577-17.614838-7.373577S465.112089 187.479933 460.196316 192.395705zM398.749243 604.501321l0 157.304718-106.508457 0c-3.82336-44.78824-15.430013-82.202739-34.820123-112.243498-19.389946-30.040759-42.1937-45.06122-68.411098-45.06122L189.009565 342.326846l172.871303 0 89.303172 89.303172 0 120.436506c-14.201193 0-26.490542 5.052344-36.868375 15.157033C403.938159 577.328082 398.749243 589.754003 398.749243 604.501321z" p-id="2679"></path></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1540728845770" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="677" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M85.333333 213.333333h341.333334V85.333333h85.333333v853.333334h-85.333333v-170.666667H256v-128h170.666667v-85.333333H170.666667v-128h256V341.333333H85.333333V213.333333m512 0h128v128h-128V213.333333m0 213.333334h213.333334v128h-213.333334v-128m0 213.333333h341.333334v128h-341.333334v-128z" fill="" p-id="678"></path></svg>

After

Width:  |  Height:  |  Size: 709 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1540728926061" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2165" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M211.91 606.15V409.82a111.23 111.23 0 0 0 0-210.65V99a36 36 0 0 0-72 0v100.33a111.23 111.23 0 0 0 0 210.32v197.18c-43.62 15.91-75 59.15-75 109.88s31.37 94 75 109.88V922a36 36 0 0 0 72 0v-94.73c44.62-15.33 76.91-59.09 76.91-110.56s-32.29-95.23-76.91-110.56z m-35.76-340.88a39.22 39.22 0 1 1-39.22 39.22 39.27 39.27 0 0 1 39.22-39.22z m0.73 495.84c-22 0-40-19.92-40-44.4s17.92-44.4 40-44.4 40 19.92 40 44.4-17.98 44.4-40.01 44.4z m242.95-477.32h401a36 36 0 0 0 0-72h-401a36 36 0 0 0 0 72z m0 139.01h246.92a36 36 0 0 0 0-72H419.83a36 36 0 0 0 0 72z m401.02 199.25h-401a36 36 0 0 0 0 72h401a36 36 0 0 0 0-72z m-154.1 139H419.83a36 36 0 1 0 0 72h246.92a36 36 0 0 0 0-72z" fill="" p-id="2166"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
/* Web Font Loader v1.6.28 - (c) Adobe Systems, Google. License: Apache 2.0 */(function(){function aa(a,b,c){return a.call.apply(a.bind,arguments)}function ba(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}}function p(a,b,c){p=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?aa:ba;return p.apply(null,arguments)}var q=Date.now||function(){return+new Date};function ca(a,b){this.a=a;this.o=b||a;this.c=this.o.document}var da=!!window.FontFace;function t(a,b,c,d){b=a.c.createElement(b);if(c)for(var e in c)c.hasOwnProperty(e)&&("style"==e?b.style.cssText=c[e]:b.setAttribute(e,c[e]));d&&b.appendChild(a.c.createTextNode(d));return b}function u(a,b,c){a=a.c.getElementsByTagName(b)[0];a||(a=document.documentElement);a.insertBefore(c,a.lastChild)}function v(a){a.parentNode&&a.parentNode.removeChild(a)}
function w(a,b,c){b=b||[];c=c||[];for(var d=a.className.split(/\s+/),e=0;e<b.length;e+=1){for(var f=!1,g=0;g<d.length;g+=1)if(b[e]===d[g]){f=!0;break}f||d.push(b[e])}b=[];for(e=0;e<d.length;e+=1){f=!1;for(g=0;g<c.length;g+=1)if(d[e]===c[g]){f=!0;break}f||b.push(d[e])}a.className=b.join(" ").replace(/\s+/g," ").replace(/^\s+|\s+$/,"")}function y(a,b){for(var c=a.className.split(/\s+/),d=0,e=c.length;d<e;d++)if(c[d]==b)return!0;return!1}
function ea(a){return a.o.location.hostname||a.a.location.hostname}function z(a,b,c){function d(){m&&e&&f&&(m(g),m=null)}b=t(a,"link",{rel:"stylesheet",href:b,media:"all"});var e=!1,f=!0,g=null,m=c||null;da?(b.onload=function(){e=!0;d()},b.onerror=function(){e=!0;g=Error("Stylesheet failed to load");d()}):setTimeout(function(){e=!0;d()},0);u(a,"head",b)}
function A(a,b,c,d){var e=a.c.getElementsByTagName("head")[0];if(e){var f=t(a,"script",{src:b}),g=!1;f.onload=f.onreadystatechange=function(){g||this.readyState&&"loaded"!=this.readyState&&"complete"!=this.readyState||(g=!0,c&&c(null),f.onload=f.onreadystatechange=null,"HEAD"==f.parentNode.tagName&&e.removeChild(f))};e.appendChild(f);setTimeout(function(){g||(g=!0,c&&c(Error("Script load timeout")))},d||5E3);return f}return null};function B(){this.a=0;this.c=null}function C(a){a.a++;return function(){a.a--;D(a)}}function E(a,b){a.c=b;D(a)}function D(a){0==a.a&&a.c&&(a.c(),a.c=null)};function F(a){this.a=a||"-"}F.prototype.c=function(a){for(var b=[],c=0;c<arguments.length;c++)b.push(arguments[c].replace(/[\W_]+/g,"").toLowerCase());return b.join(this.a)};function G(a,b){this.c=a;this.f=4;this.a="n";var c=(b||"n4").match(/^([nio])([1-9])$/i);c&&(this.a=c[1],this.f=parseInt(c[2],10))}function fa(a){return H(a)+" "+(a.f+"00")+" 300px "+I(a.c)}function I(a){var b=[];a=a.split(/,\s*/);for(var c=0;c<a.length;c++){var d=a[c].replace(/['"]/g,"");-1!=d.indexOf(" ")||/^\d/.test(d)?b.push("'"+d+"'"):b.push(d)}return b.join(",")}function J(a){return a.a+a.f}function H(a){var b="normal";"o"===a.a?b="oblique":"i"===a.a&&(b="italic");return b}
function ga(a){var b=4,c="n",d=null;a&&((d=a.match(/(normal|oblique|italic)/i))&&d[1]&&(c=d[1].substr(0,1).toLowerCase()),(d=a.match(/([1-9]00|normal|bold)/i))&&d[1]&&(/bold/i.test(d[1])?b=7:/[1-9]00/.test(d[1])&&(b=parseInt(d[1].substr(0,1),10))));return c+b};function ha(a,b){this.c=a;this.f=a.o.document.documentElement;this.h=b;this.a=new F("-");this.j=!1!==b.events;this.g=!1!==b.classes}function ia(a){a.g&&w(a.f,[a.a.c("wf","loading")]);K(a,"loading")}function L(a){if(a.g){var b=y(a.f,a.a.c("wf","active")),c=[],d=[a.a.c("wf","loading")];b||c.push(a.a.c("wf","inactive"));w(a.f,c,d)}K(a,"inactive")}function K(a,b,c){if(a.j&&a.h[b])if(c)a.h[b](c.c,J(c));else a.h[b]()};function ja(){this.c={}}function ka(a,b,c){var d=[],e;for(e in b)if(b.hasOwnProperty(e)){var f=a.c[e];f&&d.push(f(b[e],c))}return d};function M(a,b){this.c=a;this.f=b;this.a=t(this.c,"span",{"aria-hidden":"true"},this.f)}function N(a){u(a.c,"body",a.a)}function O(a){return"display:block;position:absolute;top:-9999px;left:-9999px;font-size:300px;width:auto;height:auto;line-height:normal;margin:0;padding:0;font-variant:normal;white-space:nowrap;font-family:"+I(a.c)+";"+("font-style:"+H(a)+";font-weight:"+(a.f+"00")+";")};function P(a,b,c,d,e,f){this.g=a;this.j=b;this.a=d;this.c=c;this.f=e||3E3;this.h=f||void 0}P.prototype.start=function(){var a=this.c.o.document,b=this,c=q(),d=new Promise(function(d,e){function f(){q()-c>=b.f?e():a.fonts.load(fa(b.a),b.h).then(function(a){1<=a.length?d():setTimeout(f,25)},function(){e()})}f()}),e=null,f=new Promise(function(a,d){e=setTimeout(d,b.f)});Promise.race([f,d]).then(function(){e&&(clearTimeout(e),e=null);b.g(b.a)},function(){b.j(b.a)})};function Q(a,b,c,d,e,f,g){this.v=a;this.B=b;this.c=c;this.a=d;this.s=g||"BESbswy";this.f={};this.w=e||3E3;this.u=f||null;this.m=this.j=this.h=this.g=null;this.g=new M(this.c,this.s);this.h=new M(this.c,this.s);this.j=new M(this.c,this.s);this.m=new M(this.c,this.s);a=new G(this.a.c+",serif",J(this.a));a=O(a);this.g.a.style.cssText=a;a=new G(this.a.c+",sans-serif",J(this.a));a=O(a);this.h.a.style.cssText=a;a=new G("serif",J(this.a));a=O(a);this.j.a.style.cssText=a;a=new G("sans-serif",J(this.a));a=
O(a);this.m.a.style.cssText=a;N(this.g);N(this.h);N(this.j);N(this.m)}var R={D:"serif",C:"sans-serif"},S=null;function T(){if(null===S){var a=/AppleWebKit\/([0-9]+)(?:\.([0-9]+))/.exec(window.navigator.userAgent);S=!!a&&(536>parseInt(a[1],10)||536===parseInt(a[1],10)&&11>=parseInt(a[2],10))}return S}Q.prototype.start=function(){this.f.serif=this.j.a.offsetWidth;this.f["sans-serif"]=this.m.a.offsetWidth;this.A=q();U(this)};
function la(a,b,c){for(var d in R)if(R.hasOwnProperty(d)&&b===a.f[R[d]]&&c===a.f[R[d]])return!0;return!1}function U(a){var b=a.g.a.offsetWidth,c=a.h.a.offsetWidth,d;(d=b===a.f.serif&&c===a.f["sans-serif"])||(d=T()&&la(a,b,c));d?q()-a.A>=a.w?T()&&la(a,b,c)&&(null===a.u||a.u.hasOwnProperty(a.a.c))?V(a,a.v):V(a,a.B):ma(a):V(a,a.v)}function ma(a){setTimeout(p(function(){U(this)},a),50)}function V(a,b){setTimeout(p(function(){v(this.g.a);v(this.h.a);v(this.j.a);v(this.m.a);b(this.a)},a),0)};function W(a,b,c){this.c=a;this.a=b;this.f=0;this.m=this.j=!1;this.s=c}var X=null;W.prototype.g=function(a){var b=this.a;b.g&&w(b.f,[b.a.c("wf",a.c,J(a).toString(),"active")],[b.a.c("wf",a.c,J(a).toString(),"loading"),b.a.c("wf",a.c,J(a).toString(),"inactive")]);K(b,"fontactive",a);this.m=!0;na(this)};
W.prototype.h=function(a){var b=this.a;if(b.g){var c=y(b.f,b.a.c("wf",a.c,J(a).toString(),"active")),d=[],e=[b.a.c("wf",a.c,J(a).toString(),"loading")];c||d.push(b.a.c("wf",a.c,J(a).toString(),"inactive"));w(b.f,d,e)}K(b,"fontinactive",a);na(this)};function na(a){0==--a.f&&a.j&&(a.m?(a=a.a,a.g&&w(a.f,[a.a.c("wf","active")],[a.a.c("wf","loading"),a.a.c("wf","inactive")]),K(a,"active")):L(a.a))};function oa(a){this.j=a;this.a=new ja;this.h=0;this.f=this.g=!0}oa.prototype.load=function(a){this.c=new ca(this.j,a.context||this.j);this.g=!1!==a.events;this.f=!1!==a.classes;pa(this,new ha(this.c,a),a)};
function qa(a,b,c,d,e){var f=0==--a.h;(a.f||a.g)&&setTimeout(function(){var a=e||null,m=d||null||{};if(0===c.length&&f)L(b.a);else{b.f+=c.length;f&&(b.j=f);var h,l=[];for(h=0;h<c.length;h++){var k=c[h],n=m[k.c],r=b.a,x=k;r.g&&w(r.f,[r.a.c("wf",x.c,J(x).toString(),"loading")]);K(r,"fontloading",x);r=null;if(null===X)if(window.FontFace){var x=/Gecko.*Firefox\/(\d+)/.exec(window.navigator.userAgent),xa=/OS X.*Version\/10\..*Safari/.exec(window.navigator.userAgent)&&/Apple/.exec(window.navigator.vendor);
X=x?42<parseInt(x[1],10):xa?!1:!0}else X=!1;X?r=new P(p(b.g,b),p(b.h,b),b.c,k,b.s,n):r=new Q(p(b.g,b),p(b.h,b),b.c,k,b.s,a,n);l.push(r)}for(h=0;h<l.length;h++)l[h].start()}},0)}function pa(a,b,c){var d=[],e=c.timeout;ia(b);var d=ka(a.a,c,a.c),f=new W(a.c,b,e);a.h=d.length;b=0;for(c=d.length;b<c;b++)d[b].load(function(b,d,c){qa(a,f,b,d,c)})};function ra(a,b){this.c=a;this.a=b}
ra.prototype.load=function(a){function b(){if(f["__mti_fntLst"+d]){var c=f["__mti_fntLst"+d](),e=[],h;if(c)for(var l=0;l<c.length;l++){var k=c[l].fontfamily;void 0!=c[l].fontStyle&&void 0!=c[l].fontWeight?(h=c[l].fontStyle+c[l].fontWeight,e.push(new G(k,h))):e.push(new G(k))}a(e)}else setTimeout(function(){b()},50)}var c=this,d=c.a.projectId,e=c.a.version;if(d){var f=c.c.o;A(this.c,(c.a.api||"https://fast.fonts.net/jsapi")+"/"+d+".js"+(e?"?v="+e:""),function(e){e?a([]):(f["__MonotypeConfiguration__"+
d]=function(){return c.a},b())}).id="__MonotypeAPIScript__"+d}else a([])};function sa(a,b){this.c=a;this.a=b}sa.prototype.load=function(a){var b,c,d=this.a.urls||[],e=this.a.families||[],f=this.a.testStrings||{},g=new B;b=0;for(c=d.length;b<c;b++)z(this.c,d[b],C(g));var m=[];b=0;for(c=e.length;b<c;b++)if(d=e[b].split(":"),d[1])for(var h=d[1].split(","),l=0;l<h.length;l+=1)m.push(new G(d[0],h[l]));else m.push(new G(d[0]));E(g,function(){a(m,f)})};function ta(a,b){a?this.c=a:this.c=ua;this.a=[];this.f=[];this.g=b||""}var ua="https://fonts.googleapis.com/css";function va(a,b){for(var c=b.length,d=0;d<c;d++){var e=b[d].split(":");3==e.length&&a.f.push(e.pop());var f="";2==e.length&&""!=e[1]&&(f=":");a.a.push(e.join(f))}}
function wa(a){if(0==a.a.length)throw Error("No fonts to load!");if(-1!=a.c.indexOf("kit="))return a.c;for(var b=a.a.length,c=[],d=0;d<b;d++)c.push(a.a[d].replace(/ /g,"+"));b=a.c+"?family="+c.join("%7C");0<a.f.length&&(b+="&subset="+a.f.join(","));0<a.g.length&&(b+="&text="+encodeURIComponent(a.g));return b};function ya(a){this.f=a;this.a=[];this.c={}}
var za={latin:"BESbswy","latin-ext":"\u00e7\u00f6\u00fc\u011f\u015f",cyrillic:"\u0439\u044f\u0416",greek:"\u03b1\u03b2\u03a3",khmer:"\u1780\u1781\u1782",Hanuman:"\u1780\u1781\u1782"},Aa={thin:"1",extralight:"2","extra-light":"2",ultralight:"2","ultra-light":"2",light:"3",regular:"4",book:"4",medium:"5","semi-bold":"6",semibold:"6","demi-bold":"6",demibold:"6",bold:"7","extra-bold":"8",extrabold:"8","ultra-bold":"8",ultrabold:"8",black:"9",heavy:"9",l:"3",r:"4",b:"7"},Ba={i:"i",italic:"i",n:"n",normal:"n"},
Ca=/^(thin|(?:(?:extra|ultra)-?)?light|regular|book|medium|(?:(?:semi|demi|extra|ultra)-?)?bold|black|heavy|l|r|b|[1-9]00)?(n|i|normal|italic)?$/;
function Da(a){for(var b=a.f.length,c=0;c<b;c++){var d=a.f[c].split(":"),e=d[0].replace(/\+/g," "),f=["n4"];if(2<=d.length){var g;var m=d[1];g=[];if(m)for(var m=m.split(","),h=m.length,l=0;l<h;l++){var k;k=m[l];if(k.match(/^[\w-]+$/)){var n=Ca.exec(k.toLowerCase());if(null==n)k="";else{k=n[2];k=null==k||""==k?"n":Ba[k];n=n[1];if(null==n||""==n)n="4";else var r=Aa[n],n=r?r:isNaN(n)?"4":n.substr(0,1);k=[k,n].join("")}}else k="";k&&g.push(k)}0<g.length&&(f=g);3==d.length&&(d=d[2],g=[],d=d?d.split(","):
g,0<d.length&&(d=za[d[0]])&&(a.c[e]=d))}a.c[e]||(d=za[e])&&(a.c[e]=d);for(d=0;d<f.length;d+=1)a.a.push(new G(e,f[d]))}};function Ea(a,b){this.c=a;this.a=b}var Fa={Arimo:!0,Cousine:!0,Tinos:!0};Ea.prototype.load=function(a){var b=new B,c=this.c,d=new ta(this.a.api,this.a.text),e=this.a.families;va(d,e);var f=new ya(e);Da(f);z(c,wa(d),C(b));E(b,function(){a(f.a,f.c,Fa)})};function Ga(a,b){this.c=a;this.a=b}Ga.prototype.load=function(a){var b=this.a.id,c=this.c.o;b?A(this.c,(this.a.api||"https://use.typekit.net")+"/"+b+".js",function(b){if(b)a([]);else if(c.Typekit&&c.Typekit.config&&c.Typekit.config.fn){b=c.Typekit.config.fn;for(var e=[],f=0;f<b.length;f+=2)for(var g=b[f],m=b[f+1],h=0;h<m.length;h++)e.push(new G(g,m[h]));try{c.Typekit.load({events:!1,classes:!1,async:!0})}catch(l){}a(e)}},2E3):a([])};function Ha(a,b){this.c=a;this.f=b;this.a=[]}Ha.prototype.load=function(a){var b=this.f.id,c=this.c.o,d=this;b?(c.__webfontfontdeckmodule__||(c.__webfontfontdeckmodule__={}),c.__webfontfontdeckmodule__[b]=function(b,c){for(var g=0,m=c.fonts.length;g<m;++g){var h=c.fonts[g];d.a.push(new G(h.name,ga("font-weight:"+h.weight+";font-style:"+h.style)))}a(d.a)},A(this.c,(this.f.api||"https://f.fontdeck.com/s/css/js/")+ea(this.c)+"/"+b+".js",function(b){b&&a([])})):a([])};var Y=new oa(window);Y.a.c.custom=function(a,b){return new sa(b,a)};Y.a.c.fontdeck=function(a,b){return new Ha(b,a)};Y.a.c.monotype=function(a,b){return new ra(b,a)};Y.a.c.typekit=function(a,b){return new Ga(b,a)};Y.a.c.google=function(a,b){return new Ea(b,a)};var Z={load:p(Y.load,Y)};"function"===typeof define&&define.amd?define(function(){return Z}):"undefined"!==typeof module&&module.exports?module.exports=Z:(window.WebFont=Z,window.WebFontConfig&&Y.load(window.WebFontConfig));}());

Binary file not shown.

Binary file not shown.

View File

@ -113,7 +113,7 @@ p.ag-paragraph.ag-active > span.ag-line:first-of-type:empty::after {
color: transparent; color: transparent;
} }
figure pre.ag-multiple-math, figure.ag-container-block pre,
div.ag-function-html pre.ag-html-block { div.ag-function-html pre.ag-html-block {
width: 0; width: 0;
height: 0; height: 0;
@ -127,7 +127,7 @@ div.ag-function-html pre.ag-html-block {
} }
div.ag-function-html.ag-active pre.ag-html-block, div.ag-function-html.ag-active pre.ag-html-block,
figure.ag-active pre.ag-multiple-math { figure.ag-active.ag-container-block pre {
position: static; position: static;
width: 100%; width: 100%;
height: auto; height: auto;
@ -491,15 +491,43 @@ pre.ag-active.ag-multiple-math::after {
content: '$$'; content: '$$';
} }
pre.ag-active[data-role="mermaid"]::before {
content: '``` mermaid';
}
pre.ag-active[data-role="flowchart"]::before {
content: '``` flowchart';
}
pre.ag-active[data-role="sequence"]::before {
content: '``` sequence';
}
pre.ag-active[data-role="vega-lite"]::before {
content: '``` vega-lite';
}
pre.ag-active.ag-fence-code::before, pre.ag-active.ag-fence-code::before,
pre.ag-active.ag-indent-code::after, pre.ag-active.ag-indent-code::after,
pre.ag-active.ag-fence-code::after, pre.ag-active.ag-fence-code::after,
pre.ag-active.ag-indent-code::before { pre.ag-active.ag-indent-code::before,
pre.ag-active[data-role="mermaid"]::after,
pre.ag-active[data-role="flowchart"]::after,
pre.ag-active[data-role="sequence"]::after,
pre.ag-active[data-role="vega-lite"]::after {
content: '```'; content: '```';
} }
pre.ag-active.ag-front-matter::before, pre.ag-active.ag-front-matter::before,
pre.ag-active.ag-front-matter::after, pre.ag-active.ag-front-matter::after,
pre.ag-active[data-role="mermaid"]::before,
pre.ag-active[data-role="mermaid"]::after,
pre.ag-active[data-role="flowchart"]::before,
pre.ag-active[data-role="flowchart"]::after,
pre.ag-active[data-role="sequence"]::before,
pre.ag-active[data-role="sequence"]::after,
pre.ag-active[data-role="vega-lite"]::before,
pre.ag-active[data-role="vega-lite"]::after,
pre.ag-active.ag-fence-code::before, pre.ag-active.ag-fence-code::before,
pre.ag-active.ag-fence-code::after, pre.ag-active.ag-fence-code::after,
pre.ag-active.ag-indent-code::before, pre.ag-active.ag-indent-code::before,
@ -514,6 +542,10 @@ pre.ag-active.ag-multiple-math::after {
} }
pre.ag-active.ag-front-matter::before, pre.ag-active.ag-front-matter::before,
pre.ag-active[data-role="mermaid"]::before,
pre.ag-active[data-role="flowchart"]::before,
pre.ag-active[data-role="sequence"]::before,
pre.ag-active[data-role="vega-lite"]::before,
pre.ag-active.ag-multiple-math::before, pre.ag-active.ag-multiple-math::before,
pre.ag-active.ag-indent-code::before, pre.ag-active.ag-indent-code::before,
pre.ag-active.ag-fence-code::before { pre.ag-active.ag-fence-code::before {
@ -521,6 +553,10 @@ pre.ag-active.ag-fence-code::before {
} }
pre.ag-active.ag-front-matter::after, pre.ag-active.ag-front-matter::after,
pre.ag-active[data-role="mermaid"]::after,
pre.ag-active[data-role="flowchart"]::after,
pre.ag-active[data-role="sequence"]::after,
pre.ag-active[data-role="vega-lite"]::after,
pre.ag-active.ag-multiple-math::after, pre.ag-active.ag-multiple-math::after,
pre.ag-active.ag-fence-code::after, pre.ag-active.ag-fence-code::after,
pre.ag-active.ag-indent-code::after { pre.ag-active.ag-indent-code::after {
@ -532,16 +568,17 @@ span.ag-multiple-math-line {
font-family: monospace; font-family: monospace;
} }
figure div.ag-math-preview { figure.ag-container-block div.ag-container-preview {
width: 100%; width: 100%;
text-align: center; text-align: center;
} }
figure.ag-active div.ag-math-preview { figure.ag-active.ag-container-block > div.ag-container-preview {
position: absolute; position: absolute;
top: calc(100% + 8px); top: calc(100% + 20px);
left: 50%; left: 50%;
width: auto; width: 100%;
box-sizing: border-box;
z-index: 10000; z-index: 10000;
transform: translateX(-50%); transform: translateX(-50%);
padding: .5rem; padding: .5rem;

View File

@ -0,0 +1,12 @@
/** js sequence diagrams
* https://bramp.github.io/js-sequence-diagrams/
* (c) 2012-2017 Andrew Brampton (bramp.net)
* Simplified BSD license.
*/
@font-face {
font-family: 'danielbd';
src: url('danielbd.woff2') format('woff2'),
url('danielbd.woff') format('woff');
font-weight: normal;
font-style: normal;
}

View File

@ -112,8 +112,12 @@ export const CLASS_OR_ID = genUpper2LowerKeyHash([
'AG_MATH_ERROR', 'AG_MATH_ERROR',
'AG_EMPTY', 'AG_EMPTY',
'AG_MATH_MARKER', 'AG_MATH_MARKER',
'AG_MATH_PREVIEW', 'AG_CONTAINER_PREVIEW',
'AG_MULTIPLE_MATH_BLOCK', 'AG_FLOWCHART',
'AG_SEQUENCE',
'AG_MERMAID',
'AG_VEGA_LITE',
'AG_CONTAINER_BLOCK',
'AG_MULTIPLE_MATH', 'AG_MULTIPLE_MATH',
'AG_LOOSE_LIST_ITEM', 'AG_LOOSE_LIST_ITEM',
'AG_TIGHT_LIST_ITEM', 'AG_TIGHT_LIST_ITEM',
@ -211,4 +215,22 @@ export const EXPORT_DOMPURIFY_CONFIG = {
} }
} }
export const MUYA_DEFAULT_OPTION = {
focusMode: false,
theme: 'light',
markdown: '',
preferLooseListItem: true,
autoPairBracket: true,
autoPairMarkdownSyntax: true,
autoPairQuote: true,
bulletListMarker: '-',
tabSize: 4,
sequenceTheme: 'hand', // hand or simple
mermaidTheme: 'forest' // dark or forest
}
// export const DIAGRAM_TEMPLATE = {
// 'mermaid': `graph LR;\nYou-->|Mark Text|Me;`
// }
export const isInElectron = window && window.process && window.process.type === 'renderer' export const isInElectron = window && window.process && window.process.type === 'renderer'

View File

@ -179,6 +179,10 @@ const backspaceCtrl = ContentState => {
referenceBlock = preBlock referenceBlock = preBlock
break break
case 'multiplemath': case 'multiplemath':
case 'flowchart':
case 'mermaid':
case 'sequence':
case 'vega-lite':
referenceBlock = this.getParent(preBlock) referenceBlock = this.getParent(preBlock)
break break
case 'html': case 'html':

View File

@ -0,0 +1,85 @@
const LINE_BREAKS_REG = /\n/
const FUNCTION_TYPE_LANG = {
'multiplemath': 'latex',
'flowchart': 'yaml',
'mermaid': 'yaml',
'sequence': 'yaml',
'vega-lite': 'yaml'
}
const containerCtrl = ContentState => {
ContentState.prototype.createContainerBlock = function (functionType, value = '') {
const figureBlock = this.createBlock('figure')
figureBlock.functionType = functionType
const { preBlock, preview } = this.createPreAndPreview(functionType, value)
this.appendChild(figureBlock, preBlock)
this.appendChild(figureBlock, preview)
this.codeBlocks.set(preBlock.key, value)
return figureBlock
}
ContentState.prototype.createPreAndPreview = function (functionType, value = '') {
const preBlock = this.createBlock('pre')
const codeBlock = this.createBlock('code')
preBlock.functionType = functionType
preBlock.lang = codeBlock.lang = FUNCTION_TYPE_LANG[functionType]
this.appendChild(preBlock, codeBlock)
if (typeof value === 'string' && value) {
value.replace(/^\s+/, '').split(LINE_BREAKS_REG).forEach(line => {
const codeLine = this.createBlock('span', line)
codeLine.functionType = 'codeLine'
codeLine.lang = FUNCTION_TYPE_LANG[functionType]
this.appendChild(codeBlock, codeLine)
})
} else {
const emptyLine = this.createBlock('span')
emptyLine.functionType = 'codeLine'
emptyLine.lang = FUNCTION_TYPE_LANG[functionType]
this.appendChild(codeBlock, emptyLine)
}
const preview = this.createBlock('div', '', false)
this.codeBlocks.set(preBlock.key, '')
preview.functionType = functionType
return { preBlock, preview }
}
ContentState.prototype.initContainerBlock = function (functionType, block) { // p block
block.type = 'figure'
block.functionType = functionType
block.children = []
const { preBlock, preview } = this.createPreAndPreview(functionType)
this.appendChild(block, preBlock)
this.appendChild(block, preview)
return preBlock.children[0].children[0]
}
ContentState.prototype.handleContainerBlockClick = function (figure) {
const { id } = figure
const mathBlock = this.getBlock(id)
const preBlock = mathBlock.children[0]
const firstLine = preBlock.children[0].children[0]
const { key } = firstLine
const offset = 0
this.cursor = {
start: { key, offset },
end: { key, offset }
}
this.partialRender()
}
ContentState.prototype.updateMathBlock = function (block) {
const { type } = block
if (type !== 'p') return false
const { text } = block.children[0]
const functionType = 'multiplemath'
return text.trim() === '$$' ? this.initContainerBlock(functionType, block) : false
}
}
export default containerCtrl

View File

@ -86,14 +86,29 @@ const copyCutCtrl = ContentState => {
hb.replaceWith(pre) hb.replaceWith(pre)
}) })
const mathBlock = wrapper.querySelectorAll(`figure.ag-multiple-math-block`) const mathBlock = wrapper.querySelectorAll(`figure.ag-container-block`)
;[...mathBlock].forEach(mb => { ;[...mathBlock].forEach(mb => {
const preElement = mb.querySelector('pre[data-role]')
const functionType = preElement.getAttribute('data-role')
const selectedCodeLines = mb.querySelectorAll('span.ag-code-line') const selectedCodeLines = mb.querySelectorAll('span.ag-code-line')
const value = [...selectedCodeLines].map(codeLine => codeLine.textContent).join('\n') const value = [...selectedCodeLines].map(codeLine => codeLine.textContent).join('\n')
const pre = document.createElement('pre') let pre
switch (functionType) {
case 'multiplemath':
pre = document.createElement('pre')
pre.classList.add('multiple-math') pre.classList.add('multiple-math')
pre.textContent = value pre.textContent = value
mb.replaceWith(pre) mb.replaceWith(pre)
break
case 'mermaid':
case 'flowchart':
case 'sequence':
case 'vega-lite':
pre = document.createElement('pre')
pre.innerHTML = `<code class="language-${functionType}">${value}</code>`
mb.replaceWith(pre)
break
}
}) })
const htmlData = wrapper.innerHTML const htmlData = wrapper.innerHTML

View File

@ -17,7 +17,7 @@ import paragraphCtrl from './paragraphCtrl'
import tabCtrl from './tabCtrl' import tabCtrl from './tabCtrl'
import formatCtrl from './formatCtrl' import formatCtrl from './formatCtrl'
import searchCtrl from './searchCtrl' import searchCtrl from './searchCtrl'
import mathCtrl from './mathCtrl' import containerCtrl from './containerCtrl'
import imagePathCtrl from './imagePathCtrl' import imagePathCtrl from './imagePathCtrl'
import htmlBlockCtrl from './htmlBlock' import htmlBlockCtrl from './htmlBlock'
import clickCtrl from './clickCtrl' import clickCtrl from './clickCtrl'
@ -39,7 +39,7 @@ const prototypes = [
paragraphCtrl, paragraphCtrl,
formatCtrl, formatCtrl,
searchCtrl, searchCtrl,
mathCtrl, containerCtrl,
imagePathCtrl, imagePathCtrl,
htmlBlockCtrl, htmlBlockCtrl,
clickCtrl, clickCtrl,

View File

@ -1,81 +0,0 @@
// import { CLASS_OR_ID } from '../config'
const LINE_BREAKS_REG = /\n/
const mathCtrl = ContentState => {
ContentState.prototype.createMathBlock = function (value = '') {
const FUNCTION_TYPE = 'multiplemath'
const mathBlock = this.createBlock('figure')
mathBlock.functionType = FUNCTION_TYPE
const { preBlock, mathPreview } = this.createMathAndPreview(value)
this.appendChild(mathBlock, preBlock)
this.appendChild(mathBlock, mathPreview)
this.codeBlocks.set(preBlock.key, value)
return mathBlock
}
ContentState.prototype.createMathAndPreview = function (value = '') {
const FUNCTION_TYPE = 'multiplemath'
const preBlock = this.createBlock('pre')
const codeBlock = this.createBlock('code')
preBlock.functionType = FUNCTION_TYPE
preBlock.lang = codeBlock.lang = 'latex'
this.appendChild(preBlock, codeBlock)
if (typeof value === 'string' && value) {
value.replace(/^\s+/, '').split(LINE_BREAKS_REG).forEach(line => {
const codeLine = this.createBlock('span', line)
codeLine.functionType = 'codeLine'
codeLine.lang = 'latex'
this.appendChild(codeBlock, codeLine)
})
} else {
const emptyLine = this.createBlock('span')
emptyLine.functionType = 'codeLine'
emptyLine.lang = 'latex'
this.appendChild(codeBlock, emptyLine)
}
const mathPreview = this.createBlock('div', '', false)
this.codeBlocks.set(preBlock.key, '')
mathPreview.functionType = FUNCTION_TYPE
return { preBlock, mathPreview }
}
ContentState.prototype.initMathBlock = function (block) { // p block
const FUNCTION_TYPE = 'multiplemath'
block.type = 'figure'
block.functionType = FUNCTION_TYPE
block.children = []
const { preBlock, mathPreview } = this.createMathAndPreview()
this.appendChild(block, preBlock)
this.appendChild(block, mathPreview)
return preBlock.children[0].children[0]
}
ContentState.prototype.handleMathBlockClick = function (mathFigure) {
const { id } = mathFigure
const mathBlock = this.getBlock(id)
const preBlock = mathBlock.children[0]
const firstLine = preBlock.children[0].children[0]
const { key } = firstLine
const offset = 0
this.cursor = {
start: { key, offset },
end: { key, offset }
}
this.partialRender()
}
ContentState.prototype.updateMathBlock = function (block) {
const { type } = block
if (type !== 'p') return false
const { text } = block.children[0]
return text.trim() === '$$' ? this.initMathBlock(block) : false
}
}
export default mathCtrl

View File

@ -319,19 +319,19 @@ const paragraphCtrl = ContentState => {
} }
} }
ContentState.prototype.insertMathBlock = function () { ContentState.prototype.insertContainerBlock = function (functionType, value = '') {
const { start, end } = selection.getCursorRange() const { start, end } = selection.getCursorRange()
if (start.key !== end.key) return if (start.key !== end.key) return
let block = this.getBlock(start.key) let block = this.getBlock(start.key)
if (block.type === 'span') { if (block.type === 'span') {
block = this.getParent(block) block = this.getParent(block)
} }
const mathBlock = this.createMathBlock() const mathBlock = this.createContainerBlock(functionType, value)
this.insertAfter(mathBlock, block) this.insertAfter(mathBlock, block)
if (block.type === 'p' && block.children.length === 1 && !block.children[0].text) { if (block.type === 'p' && block.children.length === 1 && !block.children[0].text) {
this.removeBlock(block) this.removeBlock(block)
} }
const cursorBlock = mathBlock.children[0].children[0] const cursorBlock = mathBlock.children[0].children[0].children[0]
const { key } = cursorBlock const { key } = cursorBlock
const offset = 0 const offset = 0
this.cursor = { this.cursor = {
@ -391,7 +391,7 @@ const paragraphCtrl = ContentState => {
break break
} }
case 'mathblock': { case 'mathblock': {
this.insertMathBlock() this.insertContainerBlock('multiplemath')
break break
} }
case 'table': { case 'table': {
@ -402,6 +402,12 @@ const paragraphCtrl = ContentState => {
this.insertHtmlBlock(block) this.insertHtmlBlock(block)
break break
} }
case 'flowchart':
case 'sequence':
case 'mermaid':
case 'vega-lite':
this.insertContainerBlock(paraType)
break
case 'heading 1': case 'heading 1':
case 'heading 2': case 'heading 2':
case 'heading 3': case 'heading 3':

View File

@ -127,7 +127,7 @@ const pasteCtrl = ContentState => {
end: { key, offset } end: { key, offset }
} }
} }
this.updateCodeBlocks(startBlock)
return this.partialRender() return this.partialRender()
} }

View File

@ -41,12 +41,12 @@ class ClickEvent {
event.stopPropagation() event.stopPropagation()
contentState.handleHtmlBlockClick(htmlPreview) contentState.handleHtmlBlockClick(htmlPreview)
} }
// handler math block preview click // handler container block preview click
const mathFigure = target.closest('.ag-multiple-math-block') const container = target.closest('.ag-container-block')
if (mathFigure && !mathFigure.classList.contains(CLASS_OR_ID['AG_ACTIVE'])) { if (container && !container.classList.contains(CLASS_OR_ID['AG_ACTIVE'])) {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
contentState.handleMathBlockClick(mathFigure) contentState.handleContainerBlockClick(container)
} }
// handler to-do checkbox click // handler to-do checkbox click
if (target.tagName === 'INPUT' && target.classList.contains(CLASS_OR_ID['AG_TASK_LIST_ITEM_CHECKBOX'])) { if (target.tagName === 'INPUT' && target.classList.contains(CLASS_OR_ID['AG_TASK_LIST_ITEM_CHECKBOX'])) {

View File

@ -3,7 +3,7 @@ import EventCenter from './eventHandler/event'
import Clipboard from './eventHandler/clipboard' import Clipboard from './eventHandler/clipboard'
import Keyboard from './eventHandler/keyboard' import Keyboard from './eventHandler/keyboard'
import ClickEvent from './eventHandler/clickEvent' import ClickEvent from './eventHandler/clickEvent'
import { CLASS_OR_ID } from './config' import { CLASS_OR_ID, MUYA_DEFAULT_OPTION } from './config'
import { wordCount } from './utils' import { wordCount } from './utils'
import ExportMarkdown from './utils/exportMarkdown' import ExportMarkdown from './utils/exportMarkdown'
import ExportHtml from './utils/exportHtml' import ExportHtml from './utils/exportHtml'
@ -18,11 +18,8 @@ import './assets/styles/index.css'
class Muya { class Muya {
constructor (container, options) { constructor (container, options) {
const { this.options = Object.assign({}, MUYA_DEFAULT_OPTION, options)
focusMode = false, theme = 'light', markdown = '', preferLooseListItem = true, const { focusMode, theme, markdown } = this.options
autoPairBracket = true, autoPairMarkdownSyntax = true, autoPairQuote = true,
bulletListMarker = '-', tabSize = 4
} = options
this.focusMode = focusMode this.focusMode = focusMode
this.theme = theme this.theme = theme
this.markdown = markdown this.markdown = markdown
@ -35,7 +32,7 @@ class Muya {
this.emojiPicker = new EmojiPicker(this) this.emojiPicker = new EmojiPicker(this)
this.imagePathPicker = new ImagePathPicker(this) this.imagePathPicker = new ImagePathPicker(this)
this.formatPicker = new FormatPicker(this) this.formatPicker = new FormatPicker(this)
this.contentState = new ContentState(this, { preferLooseListItem, autoPairBracket, autoPairMarkdownSyntax, autoPairQuote, bulletListMarker, tabSize }) this.contentState = new ContentState(this, this.options)
this.clipboard = new Clipboard(this) this.clipboard = new Clipboard(this)
this.clickEvent = new ClickEvent(this) this.clickEvent = new ClickEvent(this)
this.keyboard = new Keyboard(this) this.keyboard = new Keyboard(this)

View File

@ -1,8 +1,11 @@
import mermaid from 'mermaid'
import flowchart from 'flowchart.js'
import Diagram from './sequence'
import vegaEmbed from 'vega-embed'
import { CLASS_OR_ID } from '../../config' import { CLASS_OR_ID } from '../../config'
import { conflict, mixins } from '../../utils' import { conflict, mixins } from '../../utils'
import { patch, toVNode, toHTML, h } from './snabbdom' import { patch, toVNode, toHTML, h } from './snabbdom'
import { beginRules } from '../rules' import { beginRules } from '../rules'
import renderInlines from './renderInlines' import renderInlines from './renderInlines'
import renderBlock from './renderBlock' import renderBlock from './renderBlock'
@ -12,6 +15,8 @@ class StateRender {
this.eventCenter = muya.eventCenter this.eventCenter = muya.eventCenter
this.loadImageMap = new Map() this.loadImageMap = new Map()
this.loadMathMap = new Map() this.loadMathMap = new Map()
this.mermaidCache = new Set()
this.diagramCache = new Map()
this.tokenCache = new Map() this.tokenCache = new Map()
this.labels = new Map() this.labels = new Map()
this.container = null this.container = null
@ -84,6 +89,48 @@ class StateRender {
return selector return selector
} }
renderMermaid () {
if (this.mermaidCache.size) {
mermaid.init(undefined, document.querySelectorAll([...this.mermaidCache].join(', ')))
this.mermaidCache.clear()
}
}
async renderDiagram () {
const cache = this.diagramCache
const RENDER_MAP = {
'flowchart': flowchart,
'sequence': Diagram,
'vega-lite': vegaEmbed
}
if (cache.size) {
for (const [key, value] of cache.entries()) {
const target = document.querySelector(key)
const { code, functionType } = value
const render = RENDER_MAP[functionType]
const options = {}
if (functionType === 'sequence') {
Object.assign(options, { theme: this.muya.options.sequenceTheme })
} else if (functionType === 'vega-lite') {
Object.assign(options, { actions: false, tooltip: false, renderer: 'svg' })
}
try {
if (functionType === 'flowchart' || functionType === 'sequence') {
const diagram = render.parse(code)
target.innerHTML = ''
diagram.drawSVG(target, options)
} else if (functionType === 'vega-lite') {
await vegaEmbed(key, JSON.parse(code), options)
}
} catch (err) {
target.innerHTML = `< Invalid ${functionType === 'flowchart' ? 'Flow Chart' : 'Sequence'} Codes >`
target.classList.add(CLASS_OR_ID['AG_MATH_ERROR'])
}
}
this.diagramCache.clear()
}
}
render (blocks, cursor, activeBlocks, matches) { render (blocks, cursor, activeBlocks, matches) {
const selector = `div#${CLASS_OR_ID['AG_EDITOR_ID']}` const selector = `div#${CLASS_OR_ID['AG_EDITOR_ID']}`
@ -96,6 +143,8 @@ class StateRender {
const oldVdom = toVNode(rootDom) const oldVdom = toVNode(rootDom)
patch(oldVdom, newVdom) patch(oldVdom, newVdom)
this.renderMermaid()
this.renderDiagram()
} }
// Only render the blocks which you updated // Only render the blocks which you updated
@ -133,6 +182,8 @@ class StateRender {
patch(oldCursorVnode, newCursorVnode) patch(oldCursorVnode, newCursorVnode)
} }
} }
this.renderMermaid()
this.renderDiagram()
} }
} }

View File

@ -6,7 +6,11 @@ const PRE_BLOCK_HASH = {
'indentcode': `.${CLASS_OR_ID['AG_INDENT_CODE']}`, 'indentcode': `.${CLASS_OR_ID['AG_INDENT_CODE']}`,
'html': `.${CLASS_OR_ID['AG_HTML_BLOCK']}`, 'html': `.${CLASS_OR_ID['AG_HTML_BLOCK']}`,
'frontmatter': `.${CLASS_OR_ID['AG_FRONT_MATTER']}`, 'frontmatter': `.${CLASS_OR_ID['AG_FRONT_MATTER']}`,
'multiplemath': `.${CLASS_OR_ID['AG_MULTIPLE_MATH']}` 'multiplemath': `.${CLASS_OR_ID['AG_MULTIPLE_MATH']}`,
'flowchart': `.${CLASS_OR_ID['AG_FLOWCHART']}`,
'sequence': `.${CLASS_OR_ID['AG_SEQUENCE']}`,
'mermaid': `.${CLASS_OR_ID['AG_MERMAID']}`,
'vega-lite': `.${CLASS_OR_ID['AG_VEGA_LITE']}`
} }
export default function renderContainerBlock (block, cursor, activeBlocks, matches, useCache = false) { export default function renderContainerBlock (block, cursor, activeBlocks, matches, useCache = false) {
@ -29,11 +33,14 @@ export default function renderContainerBlock (block, cursor, activeBlocks, match
} }
// handle `figure` block // handle `figure` block
if (block.type === 'figure') { if (block.type === 'figure') {
if (block.functionType === 'html') { // HTML Block if (block.functionType) {
Object.assign(data.dataset, { role: block.functionType.toUpperCase() }) Object.assign(data.dataset, { role: block.functionType.toUpperCase() })
} }
if (block.functionType === 'multiplemath') {
selector += `.${CLASS_OR_ID['AG_MULTIPLE_MATH_BLOCK']}` if (
/multiplemath|flowchart|mermaid|sequence|vega-lite/.test(block.functionType)
) {
selector += `.${CLASS_OR_ID['AG_CONTAINER_BLOCK']}`
} }
} }
// hanle list block // hanle list block

View File

@ -1,4 +1,5 @@
import katex from 'katex' import katex from 'katex'
import mermaid from 'mermaid'
import prism, { loadedCache } from '../../../prism/' import prism, { loadedCache } from '../../../prism/'
import { CLASS_OR_ID, DEVICE_MEMORY, isInElectron, PREVIEW_DOMPURIFY_CONFIG } from '../../../config' import { CLASS_OR_ID, DEVICE_MEMORY, isInElectron, PREVIEW_DOMPURIFY_CONFIG } from '../../../config'
import { tokenizer } from '../../parse' import { tokenizer } from '../../parse'
@ -90,27 +91,30 @@ export default function renderLeafBlock (block, cursor, activeBlocks, matches, u
style: `text-align:${align}` style: `text-align:${align}`
}) })
} else if (type === 'div') { } else if (type === 'div') {
if (functionType === 'preview') { const code = this.muya.contentState.codeBlocks.get(block.preSibling)
switch (functionType) {
case 'preview': {
selector += `.${CLASS_OR_ID['AG_HTML_PREVIEW']}` selector += `.${CLASS_OR_ID['AG_HTML_PREVIEW']}`
const htmlContent = sanitize(this.muya.contentState.codeBlocks.get(block.preSibling), PREVIEW_DOMPURIFY_CONFIG) const htmlContent = sanitize(code, PREVIEW_DOMPURIFY_CONFIG)
// handle empty html bock // handle empty html bock
if (/<([a-z][a-z\d]*).*>\s*<\/\1>/.test(htmlContent)) { if (/<([a-z][a-z\d]*).*>\s*<\/\1>/.test(htmlContent)) {
children = htmlToVNode('<div class="ag-empty">&lt;Empty HTML Block&gt;</div>') children = htmlToVNode('<div class="ag-empty">&lt;Empty HTML Block&gt;</div>')
} else { } else {
children = htmlToVNode(htmlContent) children = htmlToVNode(htmlContent)
} }
} else if (functionType === 'multiplemath') { break
const math = this.muya.contentState.codeBlocks.get(block.preSibling) }
const key = `${math}_display_math` case 'multiplemath': {
selector += `.${CLASS_OR_ID['AG_MATH_PREVIEW']}` const key = `${code}_display_math`
if (math === '') { selector += `.${CLASS_OR_ID['AG_CONTAINER_PREVIEW']}`
if (code === '') {
children = '< Empty Mathematical Formula >' children = '< Empty Mathematical Formula >'
selector += `.${CLASS_OR_ID['AG_EMPTY']}` selector += `.${CLASS_OR_ID['AG_EMPTY']}`
} else if (loadMathMap.has(key)) { } else if (loadMathMap.has(key)) {
children = loadMathMap.get(key) children = loadMathMap.get(key)
} else { } else {
try { try {
const html = katex.renderToString(math, { const html = katex.renderToString(code, {
displayMode: true displayMode: true
}) })
@ -121,6 +125,42 @@ export default function renderLeafBlock (block, cursor, activeBlocks, matches, u
selector += `.${CLASS_OR_ID['AG_MATH_ERROR']}` selector += `.${CLASS_OR_ID['AG_MATH_ERROR']}`
} }
} }
break
}
case 'mermaid': {
selector += `.${CLASS_OR_ID['AG_CONTAINER_PREVIEW']}`
if (code === '') {
children = '< Empty Mermaid Block >'
selector += `.${CLASS_OR_ID['AG_EMPTY']}`
} else {
try {
mermaid.parse(code)
children = code
this.mermaidCache.add(`#${block.key}`)
} catch (err) {
children = '< Invalid Mermaid Codes >'
selector += `.${CLASS_OR_ID['AG_MATH_ERROR']}`
}
}
break
}
case 'flowchart':
case 'sequence':
case 'vega-lite': {
const code = this.muya.contentState.codeBlocks.get(block.preSibling)
selector += `.${CLASS_OR_ID['AG_CONTAINER_PREVIEW']}`
if (code === '') {
children = '< Empty Diagram Block >'
selector += `.${CLASS_OR_ID['AG_EMPTY']}`
} else {
children = ''
this.diagramCache.set(`#${block.key}`, {
code,
functionType
})
}
break
}
} }
} else if (type === 'svg' && icon) { } else if (type === 'svg' && icon) {
selector += '.icon' selector += '.icon'

View File

@ -0,0 +1,5 @@
import Diagram from '../../assets/libs/sequence-diagram'
import '../../assets/styles/sequence-diagram.css'
export default Diagram

View File

@ -843,7 +843,9 @@ class Selection {
range.collapse(true) range.collapse(true)
let rects = range.getClientRects() let rects = range.getClientRects()
if (rects.length === 0) { if (rects.length === 0) {
rects = range.startContainer ? range.startContainer.getClientRects() : [] rects = range.startContainer && range.startContainer.nodeType === Node.ELEMENT_NODE
? range.startContainer.getClientRects()
: []
} }
if (rects.length) { if (rects.length) {
const { left, top, x: rectX, y: rectY } = rects[0] const { left, top, x: rectX, y: rectY } = rects[0]

View File

@ -15,8 +15,37 @@ import quoteIcon from '../../assets/icons/quote.svg'
import todoListIcon from '../../assets/icons/todolist.svg' import todoListIcon from '../../assets/icons/todolist.svg'
import mathblockIcon from '../../assets/icons/math.svg' import mathblockIcon from '../../assets/icons/math.svg'
import orderListIcon from '../../assets/icons/order_list.svg' import orderListIcon from '../../assets/icons/order_list.svg'
import flowchartIcon from '../../assets/icons/flowchart.svg'
import sequenceIcon from '../../assets/icons/sequence.svg'
import mermaidIcon from '../../assets/icons/mermaid.svg'
import vegaIcon from '../../assets/icons/chart.svg'
export const quicInsertObj = { export const quicInsertObj = {
'diagram': [{
title: 'Vega Chart',
subTitle: 'Render flow chart by vega-lite.js.',
label: 'vega-lite',
icon: vegaIcon,
color: 'rgb(224, 54, 54)'
}, {
title: 'Flow Chart',
subTitle: 'Render flow chart by flowchart.js.',
label: 'flowchart',
icon: flowchartIcon,
color: 'rgb(224, 54, 54)'
}, {
title: 'Sequence Diagram',
subTitle: 'Render sequence diagram by js-sequence.',
label: 'sequence',
icon: sequenceIcon,
color: 'rgb(224, 54, 54)'
}, {
title: 'Mermaid',
subTitle: 'Render Diagram by mermaid.',
label: 'mermaid',
icon: mermaidIcon,
color: 'rgb(224, 54, 54)'
}],
'basic block': [{ 'basic block': [{
title: 'Text', title: 'Text',
subTitle: 'Just start write plain text.', subTitle: 'Just start write plain text.',

View File

@ -52,13 +52,23 @@ class ExportMarkdown {
case 'figure': case 'figure':
this.insertLineBreak(result, indent, true) this.insertLineBreak(result, indent, true)
if (block.functionType === 'table') { switch (block.functionType) {
case 'table':
const table = block.children[1] const table = block.children[1]
result.push(this.normalizeTable(table, indent)) result.push(this.normalizeTable(table, indent))
} else if (block.functionType === 'html') { break
case 'html':
result.push(this.normalizeHTML(block, indent)) result.push(this.normalizeHTML(block, indent))
} else if (block.functionType === 'multiplemath') { break
case 'multiplemath':
result.push(this.normalizeMultipleMath(block, indent)) result.push(this.normalizeMultipleMath(block, indent))
break
case 'mermaid':
case 'flowchart':
case 'sequence':
case 'vega-lite':
result.push(this.normalizeContainer(block, indent))
break
} }
break break
@ -173,6 +183,18 @@ class ExportMarkdown {
return result.join('') return result.join('')
} }
// `mermaid` `flowchart` `sequence` `vega-lite`
normalizeContainer (block, indent) {
const result = []
const diagramType = block.children[0].functionType
result.push('```' + diagramType + '\n')
for (const line of block.children[0].children[0].children) {
result.push(`${line.text}\n`)
}
result.push('```\n')
return result.join('')
}
normalizeCodeBlock (block, indent) { normalizeCodeBlock (block, indent) {
const result = [] const result = []
const textList = block.children[1].children.map(codeLine => codeLine.text) const textList = block.children[1].children.map(codeLine => codeLine.text)

View File

@ -73,7 +73,7 @@ const importRegister = ContentState => {
} }
case 'multiplemath': { case 'multiplemath': {
value = token.text value = token.text
block = this.createMathBlock(value) block = this.createContainerBlock(token.type, value)
this.appendChild(parentList[0], block) this.appendChild(parentList[0], block)
break break
} }
@ -83,6 +83,10 @@ const importRegister = ContentState => {
if (value.endsWith('\n')) { if (value.endsWith('\n')) {
value = value.replace(/\n+$/, '') value = value.replace(/\n+$/, '')
} }
if (/mermaid|flowchart|vega-lite|sequence/.test(lang)) {
block = this.createContainerBlock(lang, value)
this.appendChild(parentList[0], block)
} else {
block = this.createBlock('pre') block = this.createBlock('pre')
const codeBlock = this.createBlock('code') const codeBlock = this.createBlock('code')
value.split(LINE_BREAKS_REG).forEach(line => { value.split(LINE_BREAKS_REG).forEach(line => {
@ -102,6 +106,7 @@ const importRegister = ContentState => {
this.appendChild(block, inputBlock) this.appendChild(block, inputBlock)
this.appendChild(block, codeBlock) this.appendChild(block, codeBlock)
this.appendChild(parentList[0], block) this.appendChild(parentList[0], block)
}
break break
} }
case 'table': { case 'table': {

View File

@ -321,15 +321,14 @@ table tr:nth-child(2n) {
table tr th { table tr th {
font-weight: bold; font-weight: bold;
border-top: 2px solid #606266; border: 2px solid #606266;
border-bottom: 2px solid #606266;
text-align: left; text-align: left;
margin: 0; margin: 0;
padding: 6px 13px; padding: 6px 13px;
} }
table tr td { table tr td {
border-bottom: 1px solid #606266; border: 1px solid #606266;
text-align: left; text-align: left;
margin: 0; margin: 0;
padding: 6px 13px; padding: 6px 13px;