SequenceDiagram/weblib/editor.min.js

1 line
17 KiB
JavaScript

!function(){"use strict";function e(e){return null===e?null:e.element?e.element:e}function t(e){return e.length>0&&"\n"!==e.charAt(e.length-1)?e+"\n":e}function n(e,t){let n=0,i=0;for(;;){const s=e.indexOf("\n",n)+1;if(t<s||0===s)return{ch:t-n,line:i};n=s,++i}}function i(e,t,n){e(["split"],e=>{const i=t[0].parentNode,s=i.addEventListener,r=i.removeEventListener;i.addEventListener=((e,t)=>{"mousemove"===e||"touchmove"===e?window.addEventListener(e,t,{passive:!0}):s.call(i,e,t)}),i.removeEventListener=((e,t)=>{"mousemove"===e||"touchmove"===e?window.removeEventListener(e,t):r.call(i,e,t)});let o=null;const a=Object.assign({cursor:"vertical"===n.direction?"row-resize":"col-resize",direction:"vertical",gutterSize:0,onDragEnd:()=>{document.body.style.cursor=o,o=null},onDragStart:()=>{o=document.body.style.cursor,document.body.style.cursor=a.cursor}},n);return new e(t,a)})}var s=[{code:"{Agent1} -> {Agent2}: {Message}",title:"Simple arrow (synchronous)"},{code:"{Agent1} --\x3e {Agent2}: {Message}",title:"Arrow with dotted line (response)"},{code:"{Agent1} ->> {Agent2}: {Message}",title:"Open arrow (asynchronous)"},{code:"{Agent1} -x {Agent2}: {Message}",title:"Lost message"},{code:"{Agent1} ~> {Agent2}: {Message}",title:"Wavy line"},{code:"{Agent1} -> {Agent1}: {Message}",title:"Self-connection"},{code:"{Agent1} -> ...{id}\n...{id} -> {Agent2}: {Message}",preview:"begin A, B\nA -> ...x\n...x -> B: Message",title:"Asynchronous message"},{code:"* -> {Agent1}: {Message}",title:"Found message"},{code:"{Agent1} -> +{Agent2}: {Request}\n{Agent1} <-- -{Agent2}: {Response}",title:"Request/response pair"},{code:"{Agent1} -> *{Agent2}: {Request}\n{Agent1} <-- !{Agent2}: {Response}",title:"Inline agent creation / destruction"},{code:"{Agent1} -> {Agent2}: {Request}\n{Agent1} <-- {Agent2}: {Response}\nend {Agent2}",preview:"begin A\n::\nA -> B: Request\nA <-- B: Response\nend B",title:"Agent creation / destruction"},{code:'autolabel "[<inc>] <label>"',preview:'autolabel "[<inc>] <label>"\nA -> B: Foo\nA <- B: Bar\nA -> B: Baz',title:"Numbered labels"},{code:"if {Condition1}\n {Agent1} -> {Agent2}\nelse if {Condition2}\n {Agent1} -> {Agent2}\nelse\n {Agent1} -> {Agent2}\nend",preview:"begin A, B\nif Condition1\n A -> B\nelse if Condition2\n A -> B\nelse\n A -> B\nend",title:"Conditional blocks"},{code:"repeat {Condition}\n {Agent1} -> {Agent2}\nend",preview:"begin A, B\nrepeat Condition\n A -> B\nend",title:"Repeated block"},{code:"begin reference: {Label} as {Name}\n{Agent1} -> {Name}\nend {Name}",preview:'begin A\nbegin reference: "See 1.3" as myRef\nA -> myRef\nmyRef -> A\nend myRef',title:"Reference"},{code:"begin reference over {Covered}: {Label} as {Name}\n{Agent1} -> {Name}\nend {Name}",preview:'begin A, B, C\nbegin reference over B, C: "See 1.3" as myRef\nA -> myRef\nmyRef -> A\nend myRef',title:"Reference over agents"},{code:"group {Label}\n {Agent1} -> {Agent2}\nend",preview:"begin A, B\ngroup Label\n A -> B\nend",title:"Group"},{code:"note over {Agent1}: {Message}",title:"Note over agent"},{code:"note over {Agent1}, {Agent2}: {Message}",title:"Note over multiple agents"},{code:"note left of {Agent1}: {Message}",title:"Note left of agent"},{code:"note right of {Agent1}: {Message}",title:"Note right of agent"},{code:"note between {Agent1}, {Agent2}: {Message}",title:"Note between agents"},{code:"state over {Agent1}: {State}",title:"State over agent"},{code:"[ -> {Agent1}: {Message1}\n{Agent1} -> ]: {Message2}",title:"Arrows to/from the sides"},{code:"text right: {Message}",preview:'A -> B\nsimultaneously:\ntext right: "Message\\non the\\nside"',title:"Text beside the diagram"},{code:"divider space with height 10: {message}",preview:"begin A, B, C, D, E, F\ndivider space with height 30: message",title:"Vertical space divider"},{code:"divider line with height 10: {message}",preview:"begin A, B, C, D, E, F\ndivider line with height 30: message",title:"Line divider"},{code:"divider delay with height 10: {message}",preview:"begin A, B, C, D, E, F\ndivider delay with height 30: message",title:"Delay divider"},{code:"divider tear with height 10: {message}",preview:"begin A, B, C, D, E, F\ndivider tear with height 30: message",title:"Tear divider"},{code:"title {Title}",preview:"headers box\ntitle Title\nA -> B",title:"Title"},{code:"**{text}**",preview:"A -> B: **bold**",title:"Bold markdown"},{code:"_{text}_",preview:"A -> B: _italic_",title:"Italic markdown"},{code:"~{text}~",preview:"A -> B: ~strikeout~",title:"Strikeout markdown"},{code:"`{text}`",preview:"A -> B: `mono`",title:"Monospace markdown"},{code:"{Agent} is red",preview:"headers box\nA is red\nbegin A",title:"Red agent line"},{code:"{Agent} is a database",preview:"headers box\nA is a database\nbegin A",title:"Database indicator"},{code:"theme monospace",preview:"headers box\ntitle mono\ntheme monospace\nA -> B",title:"Monospace theme"},{code:"theme chunky",preview:"headers box\ntitle chunky\ntheme chunky\nA -> B",title:"Chunky theme"},{code:"theme sketch",preview:"headers box\ntitle sketch\ntheme sketch\nA -> B",title:"Sketch theme"},{code:"terminators cross",preview:"begin A\nterminators cross",title:"Cross terminators"},{code:"terminators fade",preview:"begin A\nterminators fade",title:"Fade terminators"},{code:"terminators bar",preview:"begin A\nterminators bar",title:"Bar terminators"},{code:"terminators box",preview:"begin A\nterminators box",title:"Box terminators"}];class r{constructor(e){this.element=e}addBefore(t=null,n=null){if(null===t)return this;if(Array.isArray(t))for(const e of t)this.addBefore(e,n);else{const i=function(e,t){return"string"==typeof e?t.createTextNode(e):"number"==typeof e?t.createTextNode(e.toString(10)):"object"==typeof e&&e.element?e.element:e}(t,this.element.ownerDocument);this.element.insertBefore(i,e(n))}return this}add(...e){return this.addBefore(e,null)}del(t=null){return null!==t&&this.element.removeChild(e(t)),this}attr(e,t){return this.element.setAttribute(e,t),this}attrs(e){for(const t in e)Object.prototype.hasOwnProperty.call(e,t)&&this.element.setAttribute(t,e[t]);return this}styles(e){for(const t in e)Object.prototype.hasOwnProperty.call(e,t)&&(this.element.style[t]=e[t]);return this}setClass(e){return this.attr("class",e)}addClass(e){const t=this.element.getAttribute("class");if(!t)return this.setClass(e);const n=t.split(" ");return n.includes(e)?this:(n.push(e),this.attr("class",n.join(" ")))}delClass(e){const t=this.element.getAttribute("class");if(!t)return this;const n=t.split(" "),i=n.indexOf(e);return-1!==i&&(n.splice(i,1),this.attr("class",n.join(" "))),this}text(e){return this.element.textContent=e,this}on(e,t,n={}){if(Array.isArray(e))for(const i of e)this.on(i,t,n);else this.element.addEventListener(e,t,n);return this}off(e,t,n={}){if(Array.isArray(e))for(const i of e)this.off(i,t,n);else this.element.removeEventListener(e,t,n);return this}val(e){return this.element.value=e,this}select(e,t=null){return this.element.selectionStart=e,this.element.selectionEnd=null===t?e:t,this}focus(){return this.element.focus(),this}focussed(){return this.element===this.element.ownerDocument.activeElement}empty(){for(;this.element.childNodes.length>0;)this.element.removeChild(this.element.lastChild);return this}attach(t){return e(t).appendChild(this.element),this}detach(){return this.element.parentNode.removeChild(this.element),this}}class o{constructor(e){if(!e)throw new Error("Missing document!");this.document=e,this.wrap=this.wrap.bind(this),this.el=this.el.bind(this),this.txt=this.txt.bind(this)}wrap(e){return e.element?e:new r(e)}el(e,t=null){let n=null;return n=null===t?this.document.createElement(e):this.document.createElementNS(t,e),new r(n)}txt(e=""){return this.document.createTextNode(e)}}const a=new o(document);class l{constructor({sequenceDiagram:e,defaultCode:t="",localStorage:n="",library:i=[],links:s=[],require:r=null}){this.diagram=e,this.defaultCode=t,this.localStorage=n,this.library=i,this.links=s,this.minScale=1.5,this.require=r||(()=>null),this.debounced=null,this.latestSeq=null,this.renderedSeq=null,this.pngDirty=!0,this.updatingPNG=!1,this.marker=null,this._downloadSVGClick=this._downloadSVGClick.bind(this),this._downloadPNGClick=this._downloadPNGClick.bind(this),this._downloadPNGFocus=this._downloadPNGFocus.bind(this),this._showDropStyle=this._showDropStyle.bind(this),this._hideDropStyle=this._hideDropStyle.bind(this),this.diagram.on("render",()=>{this.updateMinSize(this.diagram.getSize()),this.pngDirty=!0}).on("mouseover",e=>{this.marker&&this.marker.clear(),void 0!==e.ln&&this.code.markText&&(this.marker=this.code.markText({ch:0,line:e.ln},{ch:0,line:e.ln+1},{className:"hover",clearOnEnter:!0,inclusiveLeft:!1,inclusiveRight:!1}))}).on("mouseout",()=>{this.marker&&(this.marker.clear(),this.marker=null)}).on("click",e=>{this.marker&&(this.marker.clear(),this.marker=null),void 0!==e.ln&&this.code.setSelection&&(this.code.setSelection({ch:0,line:e.ln},{ch:0,line:e.ln+1},{bias:-1,origin:"+focus"}),this.code.focus())}).on("dblclick",e=>{this.diagram.toggleCollapsed(e.ln)})}buildOptionsDownloads(){return this.downloadPNG=a.el("a").text("Download PNG").attrs({download:"SequenceDiagram.png",href:"#"}).on(["focus","mouseover","mousedown"],this._downloadPNGFocus).on("click",this._downloadPNGClick),this.downloadSVG=a.el("a").text("SVG").attrs({download:"SequenceDiagram.svg",href:"#"}).on("click",this._downloadSVGClick),a.el("div").setClass("options downloads").add(this.downloadPNG,this.downloadSVG)}buildLibrary(e){const t=this.library.map(t=>{const n=a.el("div").attr("title",t.title||t.code),i=a.el("div").setClass("library-item").add(n).on("click",this.addCodeBlock.bind(this,t.code)).attach(e);return this.diagram.clone({code:function(e){return"headers fade\nterminators fade\n"+e.replace(/\{Agent([0-9]*)\}/g,(e,t)=>void 0===t?"A":String.fromCharCode("A".charCodeAt(0)+Number(t)-1)).replace(/[{}]/g,"")}(t.preview||t.code),container:n.element,render:!1}).on("error",(e,s)=>{window.console.warn("Failed to render preview",s),i.attr("class","library-item broken"),n.text(t.code)})});try{this.diagram.renderAll(t)}catch(e){}return e}buildViewPane(){return this.viewPaneInner=a.el("div").setClass("pane-view-inner").add(this.diagram.dom()),this.errorMsg=a.el("div").setClass("msg-error"),a.el("div").setClass("pane-view").add(a.el("div").setClass("pane-view-scroller").add(this.viewPaneInner),this.errorMsg)}buildLeftPanes(){const e=a.el("div").setClass("pane-side");this.code=a.el("textarea").setClass("editor-simple").val(this.loadCode()||this.defaultCode).on("input",()=>this.update(!1));const t=a.el("div").setClass("pane-code").add(this.code).attach(e);if(this.library.length>0){const n=a.el("div").setClass("pane-library").add(a.el("div").setClass("pane-library-scroller").add(this.buildLibrary(a.el("div").setClass("pane-library-inner")))).attach(e);i(this.require,[t.element,n.element],{direction:"vertical",minSize:[100,5],sizes:[70,30],snapOffset:5})}return e}build(e){const t=this.buildLeftPanes(),n=this.buildViewPane();this.container=a.wrap(e).add(a.el("div").setClass("pane-hold").add(t,n,a.el("div").setClass("options links").add(this.links.map(e=>a.el("a").attrs({href:e.href,target:"_blank"}).text(e.label))),this.buildOptionsDownloads())).on("dragover",e=>{e.preventDefault(),!function(e,t){if(!e.dataTransfer.items&&0===e.dataTransfer.files.length)return[...e.dataTransfer.types].includes("Files");const n=e.dataTransfer.items||e.dataTransfer.files;return 1===n.length&&n[0].type===t}(e,"image/svg+xml")?e.dataTransfer.dropEffect="none":(e.dataTransfer.dropEffect="copy",this._showDropStyle())}).on("dragleave",this._hideDropStyle).on("dragend",this._hideDropStyle).on("drop",e=>{e.preventDefault(),this._hideDropStyle();const t=function(e,t){const n=e.dataTransfer.items||e.dataTransfer.files;if(1!==n.length||n[0].type!==t)return null;const[i]=n;return i.getAsFile?i.getAsFile():i}(e,"image/svg+xml");t&&this.loadFile(t)}),i(this.require,[t.element,n.element],{direction:"horizontal",minSize:[10,10],sizes:[30,70],snapOffset:70}),setTimeout(this.update.bind(this),0),this._enhanceEditor()}addCodeBlock(e){const n=e.split("\n").length;if(this.code.getCursor){const i=this.code.getCursor("head"),s={ch:0,line:i.line+(i.ch>0?1:0)};this.code.replaceRange(t(e),s,null,"library"),this.code.setCursor({ch:0,line:s.line+n})}else{const n=this.value(),i=this.code.element.selectionStart,s=("\n"+n+"\n").indexOf("\n",i),r=t(n.substr(0,s))+t(e);this.code.val(r+n.substr(s)).select(r.length),this.update(!1)}this.code.focus()}updateMinSize({width:e,height:t}){this.viewPaneInner.styles({minHeight:Math.ceil(t*this.minScale)+"px",minWidth:Math.ceil(e*this.minScale)+"px"})}redrawDebounced(e,t){t<=0?this.redraw(e):(clearTimeout(this.debounced),this.latestSeq=e,this.debounced=setTimeout(()=>this.redraw(e),t))}redraw(e){clearTimeout(this.debounced),this.debounced=null,this.renderedSeq=e,this.diagram.render(e)}saveCode(e){if(this.localStorage)try{window.localStorage.setItem(this.localStorage,e)}catch(e){}}loadCode(){if(!this.localStorage)return"";try{return window.localStorage.getItem(this.localStorage)||""}catch(e){return""}}markError(e){"object"==typeof e&&e.message?this.errorMsg.text(e.message):this.errorMsg.text(e),this.errorMsg.addClass("error")}markOK(){this.errorMsg.text("").delClass("error")}value(){return this.code.getDoc?this.code.getDoc().getValue():this.code.element.value}setValue(e){if(this.code.getDoc){const t=this.code.getDoc();t.setValue(e),t.clearHistory()}else this.code.val(e);this.diagram.expandAll({render:!1}),this.update(!0),this.diagram.setHighlight(null)}loadFile(e){return function(e){return new Promise(t=>{const n=new FileReader;n.addEventListener("loadend",()=>{t(n.result)},{once:!0}),n.readAsText(e)})}(e).then(e=>{const t=this.diagram.extractCodeFromSVG(e);t&&this.setValue(t)})}update(e=!0){const t=this.value();this.saveCode(t);let n=null;try{n=this.diagram.process(t)}catch(e){return void this.markError(e)}this.markOK();let i=0;if(!e&&this.renderedSeq){const e=this.renderedSeq;n.agents.length!==e.agents.length?i=500:n.stages.length!==e.stages.length&&(i=250)}this.redrawDebounced(n,i)}forceRender(){this.debounced&&(clearTimeout(this.debounced),this.redraw(this.latestSeq))}updatePNGLink(){return this.forceRender(),!(this.updatingPNG||!this.pngDirty)&&(this.pngDirty=!1,this.updatingPNG=!0,this.diagram.getPNG({resolution:4}).then(({url:e,latest:t})=>{t&&(this.downloadPNG.attr("href",e),this.updatingPNG=!1)}),!0)}_showDropStyle(){this.container.addClass("drop-target")}_hideDropStyle(){this.container.delClass("drop-target")}_downloadPNGFocus(){this.updatePNGLink()}_downloadPNGClick(e){this.updatingPNG?e.preventDefault():this.updatePNGLink()&&e.preventDefault()}_downloadSVGClick(){this.forceRender();const e=this.diagram.getSVGSynchronous();this.downloadSVG.attr("href",e)}_enhanceEditor(){this.require(["cm/lib/codemirror","cm/addon/hint/show-hint","cm/addon/edit/trailingspace","cm/addon/comment/comment"],e=>{this.diagram.registerCodeMirrorMode(e);const t=this.code.element.selectionStart,i=this.code.element.selectionEnd,s=this.code.element.value,r=this.code.focussed(),o=new e(this.code.element.parentNode,{extraKeys:{"Cmd-/":e=>e.toggleComment({padding:""}),"Cmd-Enter":"autocomplete","Ctrl-/":e=>e.toggleComment({padding:""}),"Ctrl-Enter":"autocomplete","Ctrl-Space":"autocomplete","Shift-Tab":e=>e.execCommand("indentLess"),Tab:e=>e.execCommand("indentMore")},globals:{themes:this.diagram.getThemeNames()},lineNumbers:!0,mode:"sequence",showTrailingSpace:!0,value:s});this.code.detach(),o.getDoc().setSelection(n(s,t),n(s,i));let a=0;o.on("keydown",(e,t)=>{a=t.keyCode}),o.on("change",(t,n)=>{if(this.update(!1),"+input"===n.origin){if(13===a)return void(a=0)}else if("complete"!==n.origin)return;e.commands.autocomplete(t,null,{completeSingle:!1})}),o.on("cursorActivity",()=>{const e=o.getCursor("from").line,t=o.getCursor("to").line;this.diagram.setHighlight(Math.min(e,t))}),r&&o.focus(),this.code=o})}}var d=window.SequenceDiagram;const h=window.requirejs,c={},g={},u=window.document.getElementsByTagName("meta");for(let e=0;e<u.length;++e){const t=u[e],n=t.getAttribute("name");if(n&&n.startsWith("cdn-")){const e=n.substr("cdn-".length);let i=t.getAttribute("content");i.endsWith(".js")&&(i=i.substr(0,i.length-".js".length)),c[e]=i;const s=t.getAttribute("data-integrity");s&&(g[e]=s)}}h.config({hashes:g,onNodeCreated:(e,t,n)=>{t.hashes[n]&&(e.setAttribute("integrity",t.hashes[n]),e.setAttribute("crossorigin","anonymous"))},paths:c});window.addEventListener("load",()=>{const e=window.document.getElementById("loader"),[t]=e.getElementsByTagName("nav"),n=t.getElementsByTagName("a"),i=[];for(let e=0;e<n.length;++e)i.push({href:n[e].getAttribute("href"),label:n[e].textContent});const r=new l({defaultCode:'title Labyrinth\n\nBowie -> Goblin: You remind me of the babe\nGoblin -> Bowie: What babe?\nBowie -> Goblin: The babe with the power\nGoblin -> Bowie: What power?\nnote right of Bowie, Goblin: Most people get muddled here!\nBowie -> Goblin: "The power of voodoo"\nGoblin -> Bowie: "Who-do?"\nBowie -> Goblin: You do!\nGoblin -> Bowie: Do what?\nBowie -> Goblin: Remind me of the babe!\n\nBowie -> Audience: Sings\n\nterminators box\n',library:s,links:i,localStorage:"src",require:h,sequenceDiagram:new d});e.parentNode.removeChild(e),r.build(window.document.body)})}();