From a84f2e01fc4180f360199dece76327b57d37ac35 Mon Sep 17 00:00:00 2001
From: David Evans
Date: Thu, 9 Dec 2021 23:03:46 +0000
Subject: [PATCH] Fix blocked resources in library.htm, add new security
headers
---
bin/server.js | 44 +++++++++++++++++++++--
index.html | 6 ++--
lib/sequence-diagram-web.js | 2 +-
lib/sequence-diagram-web.min.js | 2 +-
lib/sequence-diagram.js | 2 +-
library.htm | 56 +++++++----------------------
scripts/svg/SVGTextBlock.mjs | 2 +-
scripts/svg/SVGTextBlock_spec.mjs | 3 +-
web/lib/editor.js | 6 +++-
web/lib/editor.min.js | 2 +-
web/resources/library.js | 31 ++++++++++++++++
web/scripts/interface/Interface.mjs | 6 +++-
12 files changed, 106 insertions(+), 56 deletions(-)
create mode 100644 web/resources/library.js
diff --git a/bin/server.js b/bin/server.js
index 8445ed3..b29ab4a 100755
--- a/bin/server.js
+++ b/bin/server.js
@@ -55,20 +55,41 @@ const PREVIEW_CACHE = {
};
const SKETCH_CSS_SHA = 'sha256-s7UPtBgvov5WNF9C1DlTZDpqwLgEmfiWha5a5p/Zn7E=';
+const PERMISSIONS_POLICY = [
+ 'accelerometer=()',
+ 'autoplay=()',
+ 'camera=()',
+ 'geolocation=()',
+ 'gyroscope=()',
+ 'interest-cohort=()',
+ 'magnetometer=()',
+ 'microphone=()',
+ 'payment=()',
+ 'sync-xhr=()',
+ 'usb=()',
+].join(', ');
+
const statics = new StaticRequestHandler('')
.setCache(DEV ? {} : STATIC_CACHE)
.addHeader('Content-Security-Policy', [
'base-uri \'self\'',
'default-src \'none\'',
'script-src \'self\' https://unpkg.com',
- `style-src 'self' '${SKETCH_CSS_SHA}'`,
+ // Using fonts.googleapis.com for library.htm only
+ `style-src 'self' https://fonts.googleapis.com '${SKETCH_CSS_SHA}'`,
'connect-src \'self\'',
- 'font-src \'self\' data:',
+ // Using fonts.gstatic.com for library.htm only
+ 'font-src \'self\' data: https://fonts.gstatic.com',
'img-src \'self\' blob:',
'form-action \'self\'',
'frame-ancestors \'self\'',
'frame-src \'self\'',
].join('; '))
+ .addHeader('Cross-Origin-Embedder-Policy', 'require-corp')
+ .addHeader('Cross-Origin-Opener-Policy', 'same-origin')
+ .addHeader('Cross-Origin-Resource-Policy', 'same-origin')
+ .addHeader('Permissions-Policy', PERMISSIONS_POLICY)
+ .addHeader('Referrer-Policy', 'no-referrer')
.addHeader('X-Content-Type-Options', 'nosniff')
.addHeader('X-Frame-Options', 'DENY')
.addHeader('X-XSS-Protection', '1; mode=block')
@@ -83,6 +104,15 @@ const statics = new StaticRequestHandler('')
statics
.add('/robots.txt', '')
+ .add('/ads.txt', [
+ '# Deny inclusion in any advertising system\n',
+ 'placeholder.example.com, placeholder, DIRECT, placeholder\n',
+ ].join(''))
+ .add('/.well-known/security.txt', [
+ 'Contact: https://github.com/davidje13/SequenceDiagram/issues\n',
+ 'Preferred-Languages: en\n',
+ 'Expires: 3000-01-01T00:00:00Z\n',
+ ].join(''))
.addResources('/', BASEDIR, [
'index.html',
'library.htm',
@@ -115,6 +145,11 @@ const render = new RenderRequestHandler('/render')
'font-src data:',
'form-action \'none\'',
].join('; '))
+ .addHeader('Cross-Origin-Embedder-Policy', 'require-corp')
+ .addHeader('Cross-Origin-Opener-Policy', 'unsafe-none')
+ .addHeader('Cross-Origin-Resource-Policy', 'cross-origin')
+ .addHeader('Permissions-Policy', PERMISSIONS_POLICY)
+ .addHeader('Referrer-Policy', 'no-referrer')
.addHeader('X-Content-Type-Options', 'nosniff');
const preview = new PreviewRequestHandler('/preview')
@@ -129,6 +164,11 @@ const preview = new PreviewRequestHandler('/preview')
'frame-ancestors \'self\'',
'frame-src \'self\'',
].join('; '))
+ .addHeader('Cross-Origin-Embedder-Policy', 'require-corp')
+ .addHeader('Cross-Origin-Opener-Policy', 'same-origin')
+ .addHeader('Cross-Origin-Resource-Policy', 'same-origin')
+ .addHeader('Permissions-Policy', PERMISSIONS_POLICY)
+ .addHeader('Referrer-Policy', 'no-referrer')
.addHeader('X-Content-Type-Options', 'nosniff');
new Server()
diff --git a/index.html b/index.html
index 09e8590..3cc5498 100644
--- a/index.html
+++ b/index.html
@@ -82,8 +82,8 @@
Loading…
My Diagrams
-Library
-GitHub
+Library
+GitHub
@@ -92,7 +92,7 @@
API
@@ -877,29 +847,29 @@ for all types.
There are quite a lot of sequence diagram drawing tools available. If this one
doesn’t fit your needs for whatever reason, you might want to take a look
at the alternatives: (but also feel free to raise feature requests in the
-issue tracker !)
+issue tracker !)
-websequencediagrams.com
+websequencediagrams.com
is a commercial offering which inspired the syntax of this project and many
others. It has a wide range of themes but limited functionality. Also offers a
hosted image generation service.
-js-sequence-diagrams
+js-sequence-diagrams
is a Javascript library which has wider browser support via snap.svg but very
limited functionality.
-mermaid
+mermaid
is a Javascript library and online editor which can render multiple types of UML
diagram, including simple sequence diagrams.
-Scruffy UML
+Scruffy UML
is a Python library which can render multiple types of UML diagram, including
simple sequence diagrams, from the commandline. Uses yUML syntax rather than the
human friendly syntax used by most other projects.
-PlantUML
+PlantUML
is a Java project and online editor which can render multiple types of UML
diagram, including sequence diagrams. Has a good range of features and allows a
high degree of customisation (e.g. diagram colours).
@@ -911,7 +881,7 @@ high degree of customisation (e.g. diagram colours).
Thanks to the other tools mentioned above for inspiring parts of the syntax of
this project, and to
-the Handlee font
+the Handlee font
which is used in the sketch theme.
@@ -935,7 +905,7 @@ which is used in the sketch theme.
-Online Editor GitHub
+Online Editor GitHub
diff --git a/scripts/svg/SVGTextBlock.mjs b/scripts/svg/SVGTextBlock.mjs
index c5a7886..44aac41 100644
--- a/scripts/svg/SVGTextBlock.mjs
+++ b/scripts/svg/SVGTextBlock.mjs
@@ -20,7 +20,7 @@ function populateSvgTextLine(svg, node, formattedLine) {
if(attrs.href) {
element = svg.el('a').attrs({
'cursor': 'pointer',
- 'rel': 'nofollow',
+ 'rel': 'nofollow noopener',
'target': '_blank',
});
} else {
diff --git a/scripts/svg/SVGTextBlock_spec.mjs b/scripts/svg/SVGTextBlock_spec.mjs
index 4e00790..7d75f32 100644
--- a/scripts/svg/SVGTextBlock_spec.mjs
+++ b/scripts/svg/SVGTextBlock_spec.mjs
@@ -105,7 +105,8 @@ describe('SVGTextBlock', () => {
expect(hold.childNodes[0].innerHTML).toContain(' cursor="pointer"');
expect(hold.childNodes[0].innerHTML).toContain(' target="_blank"');
- expect(hold.childNodes[0].innerHTML).toContain(' rel="nofollow"');
+ expect(hold.childNodes[0].innerHTML)
+ .toContain(' rel="nofollow noopener"');
});
it('re-uses text nodes when possible, adding more if needed', () => {
diff --git a/web/lib/editor.js b/web/lib/editor.js
index ec00d88..ef835ec 100644
--- a/web/lib/editor.js
+++ b/web/lib/editor.js
@@ -1819,7 +1819,11 @@
const links = this.links.map((link) => {
const label = this.touchUI ? link.touchLabel : link.label;
return label && this.dom.el('a')
- .attrs({'href': link.href, 'target': link.target || ''})
+ .attrs({
+ 'href': link.href,
+ 'rel': 'noopener',
+ 'target': link.target || '',
+ })
.text(label);
}).filter((x) => x);
diff --git a/web/lib/editor.min.js b/web/lib/editor.min.js
index 4aa4e3c..60a3328 100644
--- a/web/lib/editor.min.js
+++ b/web/lib/editor.min.js
@@ -1 +1 @@
-!function(){"use strict";function e(){const e=window.location.hash;return e?e.substr(1):""}function t(e){return null===e?null:e.element?e.element:e}function i(e){return e.length>0&&"\n"!==e.charAt(e.length-1)?e+"\n":e}function s(e,t){let i=0,s=0;for(;;){const n=e.indexOf("\n",i)+1;if(ti.line||e.line===i.line&&e.ch>i.ch)}function r(e,t,i,s){const n=e.getLine(t),r=t===i.line?i.ch:0;return{chOffset:r,line:t===s.line?n.slice(r,s.ch):n.slice(r)}}function o(e,t){const i=e.toString(),s=i.indexOf(".");return-1===s||i.length-s-1<=t?i:e.toFixed(t)}function l(e=null){return null!==e&&!Number.isNaN(e)}var a=[{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}\n& {Agent1} -> {Agent3}: {Broadcast}",title:"Broadcast 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 "[] "',preview:'autolabel "[] "\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:"{Agent1} -> {Agent2}\n& note right of {Agent2}: {Message}",title:"Inline note"},{code:"state over {Agent1}: {State}",title:"State over agent"},{code:"[ -> {Agent1}: {Message1}\n{Agent1} -> ]: {Message2}",title:"Arrows to/from the sides"},{code:"{Agent1} -~ ]: {Message1}\n{Agent1} <-~ ]: {Message2}",title:"Fading arrows"},{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**",surround:!0,title:"Bold markdown"},{code:"_{text}_",preview:"A -> B: _italic_",surround:!0,title:"Italic markdown"},{code:"~{text}~",preview:"A -> B: ~strikeout~",surround:!0,title:"Strikeout markdown"},{code:"{text} ",preview:"A -> B: underline ",surround:!0,title:"Underline markdown"},{code:"{text} ",preview:"A -> B: overline ",surround:!0,title:"Overline markdown"},{code:"{text} ",preview:"A -> B: superscript ",surround:!0,title:"Superscript markdown"},{code:"{text} ",preview:"A -> B: subscript ",surround:!0,title:"Subscript markdown"},{code:"`{text}`",preview:"A -> B: `mono`",surround:!0,title:"Monospace markdown"},{code:"{text} ",preview:"A -> B: red ",surround:!0,title:"Red markdown"},{code:"{text} ",preview:"A -> B: highlight ",surround:!0,title:"Highlight markdown"},{code:"{Agent} is red",preview:"headers box\nA is red\nbegin A",title:"Red agent line"},{code:"{Agent} is a person",preview:"headers box\nA is a person\nbegin A",title:"Person indicator"},{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"}];const d=/^[0-9]{1,2}$/;class h{constructor(e){this.element=e}addBefore(e=null,i=null){if(null===e)return this;if(Array.isArray(e))for(const t of e)this.addBefore(t,i);else{const s=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}(e,this.element.ownerDocument);this.element.insertBefore(s,t(i))}return this}add(...e){return this.addBefore(e,null)}del(e=null){return null!==e&&this.element.removeChild(t(e)),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 i=t.split(" ");return i.includes(e)?this:(i.push(e),this.attr("class",i.join(" ")))}delClass(e){const t=this.element.getAttribute("class");if(!t)return this;const i=t.split(" "),s=i.indexOf(e);return-1!==s&&(i.splice(s,1),this.attr("class",i.join(" "))),this}text(e){return this.element.textContent=e,this}on(e,t,i={}){if(Array.isArray(e))for(const s of e)this.on(s,t,i);else this.element.addEventListener(e,t,i);return this}off(e,t,i={}){if(Array.isArray(e))for(const s of e)this.off(s,t,i);else this.element.removeEventListener(e,t,i);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(e){return t(e).appendChild(this.element),this}detach(){return this.element.parentNode&&this.element.parentNode.removeChild(this.element),this}}class c{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 h(e)}el(e,t=null){let i=null;return i=null===t?this.document.createElement(e):this.document.createElementNS(t,e),new h(i)}txt(e=""){return this.document.createTextNode(e)}}c.WrappedElement=h,c.WrappedElement.prototype.fastClick=function(){const e={x:-1,y:0};return this.on("touchstart",t=>{const[i]=t.touches;e.x=i.pageX,e.y=i.pageY},{passive:!0}).on("touchend",t=>{if(-1===e.x||0!==t.touches.length||1!==t.changedTouches.length)return void(e.x=-1);const[i]=t.changedTouches;Math.abs(e.x-i.pageX)<10&&Math.abs(e.y-i.pageY)<10&&(t.preventDefault(),t.target.click()),e.x=-1})},c.WrappedElement.prototype.split=function(e,t){return this.add(e),function(e,t){const i=[],s={direction:t.direction,minSize:[],sizes:[],snapOffset:t.snapOffset};let n=0;for(let r=0;r{const n=e[0].element.parentNode,r=n.addEventListener,o=n.removeEventListener;n.addEventListener=((e,t)=>{"mousemove"===e||"touchmove"===e?window.addEventListener(e,t,{passive:!0}):r.call(n,e,t)}),n.removeEventListener=((e,t)=>{"mousemove"===e||"touchmove"===e?window.removeEventListener(e,t):o.call(n,e,t)});let l=null;const a="vertical"===s.direction?"row-resize":"col-resize";return new t(i.map(e=>e.element),Object.assign({cursor:a,direction:"vertical",gutterSize:0,onDragEnd:()=>{document.body.style.cursor=l,l=null},onDragStart:()=>{l=document.body.style.cursor,document.body.style.cursor=a}},s))})}(e,t),this};class u{constructor(){this.listeners=new Map,this.forwards=new Set}addEventListener(e,t){const i=this.listeners.get(e);i?i.push(t):this.listeners.set(e,[t])}removeEventListener(e,t){const i=this.listeners.get(e);if(!i)return;const s=i.indexOf(t);-1!==s&&i.splice(s,1)}on(e,t){return this.addEventListener(e,t),this}off(e,t){return this.removeEventListener(e,t),this}countEventListeners(e){return(this.listeners.get(e)||[]).length}removeAllEventListeners(e){e?this.listeners.delete(e):this.listeners.clear()}addEventForwarding(e){this.forwards.add(e)}removeEventForwarding(e){this.forwards.delete(e)}removeAllEventForwardings(){this.forwards.clear()}trigger(e,t=[]){(this.listeners.get(e)||[]).forEach(e=>e(...t)),this.forwards.forEach(i=>i.trigger(e,t))}}const m=/\{[^}]+\}/g;class g extends u{constructor(e,t,{mode:i="",require:s=null,value:n=""}){super(),this.mode=i,this.require=s||(()=>null),this.marker=null,this.isAutocompleting=!1,this.enhanced=!1,this.code=e.el("textarea").setClass("editor-simple").val(n).on("input",()=>this.trigger("change")).on("focus",()=>this.trigger("focus")).attach(t),this._enhance()}markLineHover(e=null){this.unmarkLineHover(),null!==e&&this.enhanced&&(this.marker=this.code.markText({ch:0,line:e},{ch:0,line:e+1},{className:"hover",clearOnEnter:!0,inclusiveLeft:!1,inclusiveRight:!1}))}unmarkLineHover(){this.marker&&(this.marker.clear(),this.marker=null)}selectLine(e=null){null!==e&&this.enhanced&&(this.code.setSelection({ch:0,line:e},{ch:0,line:e+1},{bias:-1,origin:"+focus"}),this.code.focus())}enterParams(e,t,i){if(!i.includes("{"))return;this.cancelParams&&this.cancelParams();const s=this.code.getDoc(),r=s.setBookmark(t),o=[],l=(e,t)=>{switch(t.keyCode){case 13:case 9:this.isAutocompleting||t.preventDefault(),this.advanceParams();break;case 27:this.isAutocompleting||(t.preventDefault(),this.cancelParams())}},a=()=>{if(0===this.paramMarkers.length)return;const e=this.paramMarkers[0].find(),[t]=s.listSelections();n(t.anchor,e)&&n(t.head,e)||(this.cancelParams(),this.code.setSelection(t.anchor,t.head))};this.paramMarkers=[],this.cancelParams=(()=>{this.code.off("keydown",l),this.code.off("cursorActivity",a),this.paramMarkers.forEach(e=>e.clear()),this.paramMarkers=null,this.code.setCursor(r.find()),r.clear(),this.cancelParams=null,this.advanceParams=null}),this.advanceParams=(()=>{this.paramMarkers.forEach(e=>e.clear()),this.paramMarkers.length=0,this.nextParams(e,r,i,o)}),this.code.on("keydown",l),this.code.on("cursorActivity",a),this.advanceParams()}nextParams(e,t,i,s){const n=function(e,t){m.lastIndex=0;for(let i=null;i=m.exec(e);)if(!t.includes(i[0]))return i[0];return null}(i,s);if(!n)return void this.cancelParams();s.push(n);const o=this.code.getDoc(),l=[],a=t.find();for(let t=e.line;t<=a.line;++t){const{chOffset:i,line:s}=r(o,t,e,a);for(let e=0;-1!==(e=s.indexOf(n,e));e+=n.length){const s={ch:i+e,line:t},r={ch:i+e+n.length,line:t};l.push({anchor:s,head:r}),this.paramMarkers.push(o.markText(s,r,{className:"param",clearWhenEmpty:!1,inclusiveLeft:!0,inclusiveRight:!0}))}}l.length>0?o.setSelections(l,0):this.cancelParams()}hasSelection(){const e=this.code.getCursor("from"),t=this.code.getCursor("to");return e.line!==t.line||e.ch!==t.ch}internalAddSurroundCode(e){if(this.enhanced)if(this.hasSelection())this.code.replaceSelection(e.replace(/\{.*\}/,this.code.getSelection()),"end","library");else{const t=this.code.getCursor("head");this.code.replaceSelection(e,null,"library");const i={ch:t.ch+e.length,line:t.line};this.enterParams(t,i,e)}else{const t=this.value(),i=this.code.element.selectionStart,s=this.code.element.selectionEnd,n=e.replace(/\{.*\}/,t.substring(i,s));this.code.val(t.substr(0,i)+n+t.substr(s)).select(i+n.length),this.trigger("change")}}internalAddIndependentCode(e){if(this.enhanced){const t=this.code.getCursor("head"),s={ch:0,line:t.line+(t.ch>0?1:0)};let n=i(e);s.line>=this.code.lineCount()&&(n="\n"+n),this.code.replaceRange(n,s,null,"library");const r=e.split("\n").length,o={ch:0,line:s.line+r};this.enterParams(s,o,e)}else{const t=this.value(),s=this.code.element.selectionStart,n=("\n"+t+"\n").indexOf("\n",s),r=i(t.substr(0,n))+i(e);this.code.val(r+t.substr(n)).select(r.length),this.trigger("change")}}addCodeBlock(e,t=!1){this.code.focus(),t?this.internalAddSurroundCode(e):this.internalAddIndependentCode(e)}value(){return this.enhanced?this.code.getDoc().getValue():this.code.element.value}setValue(e){if(this.enhanced){const t=this.code.getDoc();t.setValue(e),t.clearHistory()}else this.code.val(e)}_enhance(){this.require(["cm/lib/codemirror","cm/addon/hint/show-hint","cm/addon/edit/trailingspace","cm/addon/comment/comment"],e=>{const t={};this.trigger("enhance",[e,t]);const i=this.code,{selectionStart:n,selectionEnd:r,value:o}=i.element,l=i.focussed(),a=new e(i.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:t,lineNumbers:!0,mode:this.mode,showTrailingSpace:!0,value:o});i.detach(),a.getDoc().setSelection(s(o,n),s(o,r));let d=0;a.on("keydown",(e,t)=>{d=t.keyCode}),a.on("change",(t,i)=>{if(this.trigger("change"),"+input"===i.origin){if(13===d)return void(d=0)}else if("complete"!==i.origin)return;e.commands.autocomplete(t,null,{completeSingle:!1})}),a.on("focus",()=>this.trigger("focus")),a.on("cursorActivity",()=>{const e=a.getCursor("from"),t=a.getCursor("to");this.trigger("cursorActivity",[e,t])}),a.on("hint-shown",()=>{this.isAutocompleting=!0}),a.on("endCompletion",()=>{this.isAutocompleting=!1}),l&&a.focus(),this.code=a,this.enhanced=!0})}}class p{constructor(e="",t=""){this.renderBase=e,this.editBase=t}setRenderBase(e){this.renderBase=e}setEditBase(e){this.editBase=e}_convertCode(e,t=!1){let i=e.split("\n").map(encodeURIComponent);if(t)for(;i.length>0&&""===i[i.length-1];)--i.length;else i=i.filter(e=>""!==e);return i.join("/")}_convertWidthHeight(e,t){let i="";return l(e)&&(i+="w"+o(Math.max(e,0),4)),l(t)&&(i+="h"+o(Math.max(t,0),4)),i+"/"}_convertZoom(e){return 1===e?"":"z"+o(Math.max(e,0),4)+"/"}_convertSize({height:e,width:t,zoom:i}){return l(t)||l(e)?this._convertWidthHeight(t,e):l(i)?this._convertZoom(i):""}getRenderURL(e,t={}){return this.renderBase+this._convertSize(t)+this._convertCode(e)+".svg"}getEditURL(e){return this.editBase+"#edit:"+this._convertCode(e,!0)}}class w{constructor(){this.value=""}set(e){this.value=e}get(){return this.value}remove(){this.value=""}}const v=500,f=250,b=4;class y{constructor(e){this.id=e}set(e){try{window.localStorage.setItem(this.id,e)}catch(e){}}get(){try{return window.localStorage.getItem(this.id)||""}catch(e){return""}}remove(){try{window.localStorage.removeItem(this.id)}catch(e){}}}var A=window.SequenceDiagram;const S=/^s[0-9]+$/;var k=(e,t)=>{if(null!==e.getSlot())return Promise.resolve();const i=t.getAllSlots().sort((e,t)=>e-t);if(!i.length)return e.setSlot(1),Promise.resolve();const s=new c(window.document),n=s.el("div").setClass("pick-document").add(s.el("h1").text("Diagrams on this device:")).add(s.el("p").text("(right-click to delete)")).attach(document.body),r=new A;return new Promise(o=>{const l=i.map(e=>{const i=t.get(e),l=s.el("div").attr("title",i.trim()),a=s.el("a").attr("href",`#${e}`).setClass("pick-document-item").add(l).on("click",t=>{t.preventDefault(),o(e)}).on("contextmenu",i=>{i.preventDefault(),function(e){window.confirm("Delete this diagram?")&&(t.remove(e),window.location.reload())}(e)}).attach(n);return r.clone({code:i,container:l.element,render:!1}).on("error",(e,t)=>{window.console.warn("Failed to render preview",t),a.attr("class","pick-document-item broken"),l.text(i)})});try{r.renderAll(l)}catch(e){}i.lengtho(t.nextAvailableSlot())).attach(n)}).then(t=>{n.detach(),e.setSlot(t)})};const C=window.requirejs,x={},B={},L=window.document.getElementsByTagName("meta");for(let e=0;e{t.hashes[i]&&(e.setAttribute("integrity",t.hashes[i]),e.setAttribute("crossorigin","anonymous"))},paths:x});window.addEventListener("load",()=>{const t=window.document.getElementById("loader"),[i]=t.getElementsByTagName("nav"),s=i.getElementsByTagName("a"),n=[];for(let e=0;enull)){this.hash=e(),window.addEventListener("hashchange",()=>{e()!==this.hash&&t()})}getRawHash(){return e()}maxSlots(){return 100}getSlot(){const t=e();return d.test(t)?Number(t):null}setSlot(e){this.hash=e.toFixed(0),window.location.hash=this.hash}}(()=>{window.location.reload()});!function(e,t){const i=e.getRawHash();if(!i.startsWith("edit:"))return;let s=i.substr("edit:".length).split("/").map(decodeURIComponent).join("\n");if(!s)return;s.endsWith("\n")||(s+="\n");const n=t.nextAvailableSlot();t.set(n,s),e.setSlot(n)}(o,r),t.parentNode.removeChild(t),k(o,r).then(()=>{new class{constructor({sequenceDiagram:e,defaultCode:t="",library:i=[],links:s=[],require:n=null,storage:r=new w,touchUI:o=!1}){this.diagram=e,this.defaultCode=t,this.storage=r,this.library=i,this.links=s,this.minScale=1.5,this.require=n||(()=>null),this.touchUI=o,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._downloadURLClick=this._downloadURLClick.bind(this),this._hideDropStyle=this._hideDropStyle.bind(this),this.diagram.on("render",()=>{this.updateMinSize(this.diagram.getSize()),function(e){let t=e.trim();t.length>20&&(t=t.substr(0,18).trim()+"…"),document.title=(t?`${t} — `:"")+"Sequence Diagram"}(this.diagram.getTitle()),this.pngDirty=!0}).on("mouseover",e=>this.code.markLineHover(e.ln)).on("mouseout",()=>this.code.unmarkLineHover()).on("click",e=>{this.code.unmarkLineHover(),this.code.selectLine(e.ln),this._hideURLBuilder()}).on("dblclick",e=>{this.diagram.toggleCollapsed(e.ln),this._hideURLBuilder()})}buildURLBuilder(){const e=this.dom.el("div").setClass("copied").add("Copied to Clipboard");this.urlOutput=this.dom.el("input").setClass("output").attr("readonly","readonly").on("focus",()=>{this.urlOutput.select(0,this.urlOutput.element.value.length)});const t=this.dom.el("button").setClass("copy").attr("title","Copy to clipboard").fastClick().on("click",()=>{this.touchUI&&this.urlOutput.styles({display:"block"}),this.urlOutput.focus().select(0,this.urlOutput.element.value.length).element.ownerDocument.execCommand("copy"),t.focus(),this.container.delClass("keyinput"),this.touchUI&&this.urlOutput.styles({display:"none"}),e.styles({display:"block",opacity:1,transition:"none"}),setTimeout(()=>e.styles({opacity:0,transition:"opacity 0.5s linear"}),1e3),setTimeout(()=>e.styles({display:"none"}),1500)}),i=()=>{this.renderOpts.styles({display:this.modeEdit.element.checked?"none":"block"}),this._refreshURL()};this.modeRender=this.dom.el("input").attrs({checked:"checked",name:"export-mode",type:"radio",value:"render"}).on("change",i),this.modeEdit=this.dom.el("input").attrs({name:"export-mode",type:"radio",value:"edit"}).on("change",i),this.modeMarkdown=this.dom.el("input").attrs({name:"export-mode",type:"radio",value:"markdown"}).on("change",i),this.urlWidth=this.dom.el("input").attrs({min:0,placeholder:"auto",step:"any",type:"number"}).on("input",()=>{this.urlZoom.val("1"),this._refreshURL()}),this.urlHeight=this.dom.el("input").attrs({min:0,placeholder:"auto",step:"any",type:"number"}).on("input",()=>{this.urlZoom.val("1"),this._refreshURL()}),this.urlZoom=this.dom.el("input").attrs({min:0,step:"any",type:"number",value:1}).on("input",()=>{this.urlWidth.val(""),this.urlHeight.val(""),this._refreshURL()}),this.renderOpts=this.dom.el("div").add(this.dom.el("label").add("width ",this.urlWidth),", ",this.dom.el("label").add("height ",this.urlHeight),this.dom.el("span").setClass("or").add("or"),this.dom.el("label").add("zoom ",this.urlZoom));const s=this.dom.el("div").setClass("config").add(this.dom.el("div").setClass("export-mode").add(this.dom.el("label").add(this.modeRender,"View"),this.dom.el("label").add(this.modeEdit,"Edit"),this.dom.el("label").add(this.modeMarkdown,"Markdown")),this.renderOpts,this.urlOutput,t,e),n=this.dom.el("div").setClass("urlbuilder").styles({display:"none"}).add(this.dom.el("div").setClass("message").add("Loading…")),r="undefined"==typeof window?"http://localhost":window.location.href;return this.renderService=new p,this.renderService.setEditBase(new URL(".",r).href),function(e){return"undefined"==typeof fetch?Promise.reject(new Error):fetch(e).then(e=>{if(!e.ok)throw new Error(e.statusText);return e})}("render/").then(e=>e.text()).then(e=>{let t=e.trim();t&&!t.startsWith("<")||(t="render/"),this.renderService.setRenderBase(new URL(t,r).href),n.empty().add(s),this._refreshURL()}).catch(()=>{n.empty().add(this.dom.el("div").setClass("message").add("No online rendering service available."))}),n}_refreshURL(){const e=this.code.value(),t={height:Number.parseFloat(this.urlHeight.element.value),width:Number.parseFloat(this.urlWidth.element.value),zoom:Number.parseFloat(this.urlZoom.element.value||"1")};let i="";if(this.modeMarkdown.element.checked){const s=this.renderService.getEditURL(e),n=this.renderService.getRenderURL(e,t);i=`[![${this.diagram.getTitle().replace(/[^a-zA-Z0-9 \-_'"]/g,"").trim()}](${n})](${s})`}else i=this.modeEdit.element.checked?this.renderService.getEditURL(e):this.renderService.getRenderURL(e,t);this.urlOutput.val(i)}_showURLBuilder(){this.builderVisible||(this.builderVisible=!0,this.touchUI?this.urlBuilder.styles({bottom:"-210px",display:"block"}):this.urlBuilder.styles({display:"block",height:"0px",padding:"0px",width:this.optsHold.element.clientWidth+"px"}),clearTimeout(this.builderTm),this.builderTm=setTimeout(()=>{this.touchUI?this.urlBuilder.styles({bottom:0}):(this.urlBuilder.styles({height:"150px",padding:"10px",width:"400px"}),this.optsHold.styles({"box-shadow":"10px 10px 25px 12px rgba(0,0,0,0.3)"}))},0),this._refreshURL())}_hideURLBuilder(){this.builderVisible&&(this.builderVisible=!1,this.touchUI?this.urlBuilder.styles({bottom:-this.urlBuilder.element.clientHeight-60+"px"}):(this.urlBuilder.styles({height:"0px",padding:"0px",width:"0px"}),this.optsHold.styles({"box-shadow":"none"})),this.container.delClass("keyinput"),clearTimeout(this.builderTm),this.builderTm=setTimeout(()=>{this.urlBuilder.styles({display:"none"})},200))}buildOptionsDownloads(){return this.downloadPNG=this.dom.el("a").text("Export PNG").attrs({download:"SequenceDiagram.png",href:"#"}).on(["focus","mouseover","mousedown"],this._downloadPNGFocus).on("touchend",this._downloadPNGFocus).on("click",this._downloadPNGClick),this.downloadSVG=this.dom.el("a").text("SVG").attrs({download:"SequenceDiagram.svg",href:"#"}).fastClick().on("click",this._downloadSVGClick),this.downloadURL=this.dom.el("a").text("URL").attrs({href:"#"}).fastClick().on("click",this._downloadURLClick),this.urlBuilder=this.buildURLBuilder(),this.optsHold=this.dom.el("div").setClass("options downloads").add(this.downloadPNG,this.downloadSVG,this.downloadURL,this.urlBuilder),this.optsHold}buildLibrary(e){const t=this.library.map(t=>{const i=this.dom.el("div").attr("title",t.title||t.code),s=this.dom.el("div").setClass("library-item").add(i).fastClick().on("click",()=>this.code.addCodeBlock(t.code,t.surround)).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:i.element,render:!1}).on("error",(e,n)=>{window.console.warn("Failed to render preview",n),s.attr("class","library-item broken"),i.text(t.code)})});try{this.diagram.renderAll(t)}catch(e){}return e}buildCodePane(){const e=this.dom.el("div").setClass("pane-code");return this.code=new g(this.dom,e,{mode:"sequence",require:this.require,value:this.storage.get()||this.defaultCode}),this.code.on("enhance",(e,t)=>{this.diagram.registerCodeMirrorMode(e),t.themes=this.diagram.getThemeNames()}).on("change",()=>this.update(!1)).on("cursorActivity",(e,t)=>{this.diagram.setHighlight(Math.min(e.line,t.line))}).on("focus",()=>this._hideURLBuilder()),e}buildLibPane(){return 0===this.library.length?null:this.dom.el("div").setClass("pane-library").add(this.dom.el("div").setClass("pane-library-scroller").add(this.buildLibrary(this.dom.el("div").setClass("pane-library-inner"))))}buildViewPane(){return this.viewPaneInner=this.dom.el("div").setClass("pane-view-inner").add(this.diagram.dom()).on("touchstart",()=>this._hideURLBuilder(),{passive:!0}).on("mousedown",()=>this._hideURLBuilder()),this.errorMsg=this.dom.el("div").setClass("msg-error"),this.dom.el("div").setClass("pane-view").add(this.dom.el("div").setClass("pane-view-scroller").add(this.viewPaneInner),this.errorMsg)}build(e){this.dom=new c(e.ownerDocument),this.container=this.dom.wrap(e).on("dragover",e=>{e.preventDefault(),function(e,t){if(!e.dataTransfer.items&&0===e.dataTransfer.files.length)return[...e.dataTransfer.types].includes("Files");const i=e.dataTransfer.items||e.dataTransfer.files;return 1===i.length&&i[0].type===t}(e,"image/svg+xml")?(e.dataTransfer.dropEffect="copy",this._showDropStyle()):e.dataTransfer.dropEffect="none"}).on("dragleave",this._hideDropStyle).on("dragend",this._hideDropStyle).on("drop",e=>{e.preventDefault(),this._hideDropStyle();const t=function(e,t){const i=e.dataTransfer.items||e.dataTransfer.files;if(1!==i.length||i[0].type!==t)return null;const[s]=i;return s.getAsFile?s.getAsFile():s}(e,"image/svg+xml");t&&this.loadFile(t)}).on("focusin",()=>this.container.addClass("keyinput")).on("focusout",()=>this.container.delClass("keyinput"));const t=this.buildCodePane(),i=this.buildLibPane(),s=this.buildViewPane(),n=this.links.map(e=>{const t=this.touchUI?e.touchLabel:e.label;return t&&this.dom.el("a").attrs({href:e.href,target:e.target||""}).text(t)}).filter(e=>e);this.touchUI?(this.buildOptionsDownloads(),this.container.addClass("touch").add(this.dom.el("div").setClass("pane-hold").split([s,t],{direction:"vertical",minSize:[10,10],require:this.require,sizes:[80,20],snapOffset:20}),i.styles({display:"none",top:"100%"}),this.urlBuilder,this.dom.el("div").setClass("optbar").add(...n,this.downloadPNG.text("PNG"),this.downloadSVG.text("SVG"),this.downloadURL.text("URL")))):this.container.add(this.dom.el("div").setClass("pane-hold").split([this.dom.el("div").setClass("pane-side").split([t,i],{direction:"vertical",minSize:[100,5],require:this.require,sizes:[70,30],snapOffset:5}),s],{direction:"horizontal",minSize:[10,10],require:this.require,sizes:[30,70],snapOffset:70}),this.dom.el("div").setClass("options links").add(n),this.buildOptionsDownloads()),"undefined"!=typeof window&&window.addEventListener("keydown",e=>{27===e.keyCode&&this._hideURLBuilder()}),setTimeout(this.update.bind(this),0)}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)}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")}loadFile(e){return function(e){return new Promise(t=>{const i=new FileReader;i.addEventListener("loadend",()=>{t(i.result)},{once:!0}),i.readAsText(e)})}(e).then(e=>{const t=this.diagram.extractCodeFromSVG(e);t&&(this.code.setValue(t),this.diagram.expandAll({render:!1}),this.update(!0),this.diagram.setHighlight(null))})}update(e=!0){this._hideURLBuilder();const t=this.code.value();this.storage.set(t);let i=null;try{i=this.diagram.process(t)}catch(e){return void this.markError(e)}this.markOK();let s=0;if(!e&&this.renderedSeq){const e=this.renderedSeq;i.agents.length!==e.agents.length?s=v:i.stages.length!==e.stages.length&&(s=f)}this.redrawDebounced(i,s)}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:b}).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(),this._hideURLBuilder()}_downloadSVGClick(){this.forceRender();const e=this.diagram.getSVGSynchronous();this.downloadSVG.attr("href",e),this._hideURLBuilder()}_downloadURLClick(e){e.preventDefault(),this.builderVisible?this._hideURLBuilder():this._showURLBuilder()}}({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:a,links:n,require:C,sequenceDiagram:new A,storage:new class{constructor(e,t){this.slotManager=e,this.slotStorage=t,this.slot=this.slotManager.getSlot(),this.value=this.get(),this.originalValue=this.value,this.loadTime=Date.now(),this.internalStorageListener=this.internalStorageListener.bind(this),window.addEventListener("storage",this.internalStorageListener),this.checkSlot()}getCurrentValue(){return Date.now()0&&"\n"!==e.charAt(e.length-1)?e+"\n":e}function n(e,t){let i=0,n=0;for(;;){const s=e.indexOf("\n",i)+1;if(ti.line||e.line===i.line&&e.ch>i.ch)}function r(e,t,i,n){const s=e.getLine(t),r=t===i.line?i.ch:0;return{chOffset:r,line:t===n.line?s.slice(r,n.ch):s.slice(r)}}function o(e,t){const i=e.toString(),n=i.indexOf(".");return-1===n||i.length-n-1<=t?i:e.toFixed(t)}function l(e=null){return null!==e&&!Number.isNaN(e)}var a=[{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}\n& {Agent1} -> {Agent3}: {Broadcast}",title:"Broadcast 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 "[] "',preview:'autolabel "[] "\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:"{Agent1} -> {Agent2}\n& note right of {Agent2}: {Message}",title:"Inline note"},{code:"state over {Agent1}: {State}",title:"State over agent"},{code:"[ -> {Agent1}: {Message1}\n{Agent1} -> ]: {Message2}",title:"Arrows to/from the sides"},{code:"{Agent1} -~ ]: {Message1}\n{Agent1} <-~ ]: {Message2}",title:"Fading arrows"},{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**",surround:!0,title:"Bold markdown"},{code:"_{text}_",preview:"A -> B: _italic_",surround:!0,title:"Italic markdown"},{code:"~{text}~",preview:"A -> B: ~strikeout~",surround:!0,title:"Strikeout markdown"},{code:"{text} ",preview:"A -> B: underline ",surround:!0,title:"Underline markdown"},{code:"{text} ",preview:"A -> B: overline ",surround:!0,title:"Overline markdown"},{code:"{text} ",preview:"A -> B: superscript ",surround:!0,title:"Superscript markdown"},{code:"{text} ",preview:"A -> B: subscript ",surround:!0,title:"Subscript markdown"},{code:"`{text}`",preview:"A -> B: `mono`",surround:!0,title:"Monospace markdown"},{code:"{text} ",preview:"A -> B: red ",surround:!0,title:"Red markdown"},{code:"{text} ",preview:"A -> B: highlight ",surround:!0,title:"Highlight markdown"},{code:"{Agent} is red",preview:"headers box\nA is red\nbegin A",title:"Red agent line"},{code:"{Agent} is a person",preview:"headers box\nA is a person\nbegin A",title:"Person indicator"},{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"}];const d=/^[0-9]{1,2}$/;class h{constructor(e){this.element=e}addBefore(e=null,i=null){if(null===e)return this;if(Array.isArray(e))for(const t of e)this.addBefore(t,i);else{const n=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}(e,this.element.ownerDocument);this.element.insertBefore(n,t(i))}return this}add(...e){return this.addBefore(e,null)}del(e=null){return null!==e&&this.element.removeChild(t(e)),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 i=t.split(" ");return i.includes(e)?this:(i.push(e),this.attr("class",i.join(" ")))}delClass(e){const t=this.element.getAttribute("class");if(!t)return this;const i=t.split(" "),n=i.indexOf(e);return-1!==n&&(i.splice(n,1),this.attr("class",i.join(" "))),this}text(e){return this.element.textContent=e,this}on(e,t,i={}){if(Array.isArray(e))for(const n of e)this.on(n,t,i);else this.element.addEventListener(e,t,i);return this}off(e,t,i={}){if(Array.isArray(e))for(const n of e)this.off(n,t,i);else this.element.removeEventListener(e,t,i);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(e){return t(e).appendChild(this.element),this}detach(){return this.element.parentNode&&this.element.parentNode.removeChild(this.element),this}}class c{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 h(e)}el(e,t=null){let i=null;return i=null===t?this.document.createElement(e):this.document.createElementNS(t,e),new h(i)}txt(e=""){return this.document.createTextNode(e)}}c.WrappedElement=h,c.WrappedElement.prototype.fastClick=function(){const e={x:-1,y:0};return this.on("touchstart",t=>{const[i]=t.touches;e.x=i.pageX,e.y=i.pageY},{passive:!0}).on("touchend",t=>{if(-1===e.x||0!==t.touches.length||1!==t.changedTouches.length)return void(e.x=-1);const[i]=t.changedTouches;Math.abs(e.x-i.pageX)<10&&Math.abs(e.y-i.pageY)<10&&(t.preventDefault(),t.target.click()),e.x=-1})},c.WrappedElement.prototype.split=function(e,t){return this.add(e),function(e,t){const i=[],n={direction:t.direction,minSize:[],sizes:[],snapOffset:t.snapOffset};let s=0;for(let r=0;r{const s=e[0].element.parentNode,r=s.addEventListener,o=s.removeEventListener;s.addEventListener=((e,t)=>{"mousemove"===e||"touchmove"===e?window.addEventListener(e,t,{passive:!0}):r.call(s,e,t)}),s.removeEventListener=((e,t)=>{"mousemove"===e||"touchmove"===e?window.removeEventListener(e,t):o.call(s,e,t)});let l=null;const a="vertical"===n.direction?"row-resize":"col-resize";return new t(i.map(e=>e.element),Object.assign({cursor:a,direction:"vertical",gutterSize:0,onDragEnd:()=>{document.body.style.cursor=l,l=null},onDragStart:()=>{l=document.body.style.cursor,document.body.style.cursor=a}},n))})}(e,t),this};class u{constructor(){this.listeners=new Map,this.forwards=new Set}addEventListener(e,t){const i=this.listeners.get(e);i?i.push(t):this.listeners.set(e,[t])}removeEventListener(e,t){const i=this.listeners.get(e);if(!i)return;const n=i.indexOf(t);-1!==n&&i.splice(n,1)}on(e,t){return this.addEventListener(e,t),this}off(e,t){return this.removeEventListener(e,t),this}countEventListeners(e){return(this.listeners.get(e)||[]).length}removeAllEventListeners(e){e?this.listeners.delete(e):this.listeners.clear()}addEventForwarding(e){this.forwards.add(e)}removeEventForwarding(e){this.forwards.delete(e)}removeAllEventForwardings(){this.forwards.clear()}trigger(e,t=[]){(this.listeners.get(e)||[]).forEach(e=>e(...t)),this.forwards.forEach(i=>i.trigger(e,t))}}const m=/\{[^}]+\}/g;class g extends u{constructor(e,t,{mode:i="",require:n=null,value:s=""}){super(),this.mode=i,this.require=n||(()=>null),this.marker=null,this.isAutocompleting=!1,this.enhanced=!1,this.code=e.el("textarea").setClass("editor-simple").val(s).on("input",()=>this.trigger("change")).on("focus",()=>this.trigger("focus")).attach(t),this._enhance()}markLineHover(e=null){this.unmarkLineHover(),null!==e&&this.enhanced&&(this.marker=this.code.markText({ch:0,line:e},{ch:0,line:e+1},{className:"hover",clearOnEnter:!0,inclusiveLeft:!1,inclusiveRight:!1}))}unmarkLineHover(){this.marker&&(this.marker.clear(),this.marker=null)}selectLine(e=null){null!==e&&this.enhanced&&(this.code.setSelection({ch:0,line:e},{ch:0,line:e+1},{bias:-1,origin:"+focus"}),this.code.focus())}enterParams(e,t,i){if(!i.includes("{"))return;this.cancelParams&&this.cancelParams();const n=this.code.getDoc(),r=n.setBookmark(t),o=[],l=(e,t)=>{switch(t.keyCode){case 13:case 9:this.isAutocompleting||t.preventDefault(),this.advanceParams();break;case 27:this.isAutocompleting||(t.preventDefault(),this.cancelParams())}},a=()=>{if(0===this.paramMarkers.length)return;const e=this.paramMarkers[0].find(),[t]=n.listSelections();s(t.anchor,e)&&s(t.head,e)||(this.cancelParams(),this.code.setSelection(t.anchor,t.head))};this.paramMarkers=[],this.cancelParams=(()=>{this.code.off("keydown",l),this.code.off("cursorActivity",a),this.paramMarkers.forEach(e=>e.clear()),this.paramMarkers=null,this.code.setCursor(r.find()),r.clear(),this.cancelParams=null,this.advanceParams=null}),this.advanceParams=(()=>{this.paramMarkers.forEach(e=>e.clear()),this.paramMarkers.length=0,this.nextParams(e,r,i,o)}),this.code.on("keydown",l),this.code.on("cursorActivity",a),this.advanceParams()}nextParams(e,t,i,n){const s=function(e,t){m.lastIndex=0;for(let i=null;i=m.exec(e);)if(!t.includes(i[0]))return i[0];return null}(i,n);if(!s)return void this.cancelParams();n.push(s);const o=this.code.getDoc(),l=[],a=t.find();for(let t=e.line;t<=a.line;++t){const{chOffset:i,line:n}=r(o,t,e,a);for(let e=0;-1!==(e=n.indexOf(s,e));e+=s.length){const n={ch:i+e,line:t},r={ch:i+e+s.length,line:t};l.push({anchor:n,head:r}),this.paramMarkers.push(o.markText(n,r,{className:"param",clearWhenEmpty:!1,inclusiveLeft:!0,inclusiveRight:!0}))}}l.length>0?o.setSelections(l,0):this.cancelParams()}hasSelection(){const e=this.code.getCursor("from"),t=this.code.getCursor("to");return e.line!==t.line||e.ch!==t.ch}internalAddSurroundCode(e){if(this.enhanced)if(this.hasSelection())this.code.replaceSelection(e.replace(/\{.*\}/,this.code.getSelection()),"end","library");else{const t=this.code.getCursor("head");this.code.replaceSelection(e,null,"library");const i={ch:t.ch+e.length,line:t.line};this.enterParams(t,i,e)}else{const t=this.value(),i=this.code.element.selectionStart,n=this.code.element.selectionEnd,s=e.replace(/\{.*\}/,t.substring(i,n));this.code.val(t.substr(0,i)+s+t.substr(n)).select(i+s.length),this.trigger("change")}}internalAddIndependentCode(e){if(this.enhanced){const t=this.code.getCursor("head"),n={ch:0,line:t.line+(t.ch>0?1:0)};let s=i(e);n.line>=this.code.lineCount()&&(s="\n"+s),this.code.replaceRange(s,n,null,"library");const r=e.split("\n").length,o={ch:0,line:n.line+r};this.enterParams(n,o,e)}else{const t=this.value(),n=this.code.element.selectionStart,s=("\n"+t+"\n").indexOf("\n",n),r=i(t.substr(0,s))+i(e);this.code.val(r+t.substr(s)).select(r.length),this.trigger("change")}}addCodeBlock(e,t=!1){this.code.focus(),t?this.internalAddSurroundCode(e):this.internalAddIndependentCode(e)}value(){return this.enhanced?this.code.getDoc().getValue():this.code.element.value}setValue(e){if(this.enhanced){const t=this.code.getDoc();t.setValue(e),t.clearHistory()}else this.code.val(e)}_enhance(){this.require(["cm/lib/codemirror","cm/addon/hint/show-hint","cm/addon/edit/trailingspace","cm/addon/comment/comment"],e=>{const t={};this.trigger("enhance",[e,t]);const i=this.code,{selectionStart:s,selectionEnd:r,value:o}=i.element,l=i.focussed(),a=new e(i.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:t,lineNumbers:!0,mode:this.mode,showTrailingSpace:!0,value:o});i.detach(),a.getDoc().setSelection(n(o,s),n(o,r));let d=0;a.on("keydown",(e,t)=>{d=t.keyCode}),a.on("change",(t,i)=>{if(this.trigger("change"),"+input"===i.origin){if(13===d)return void(d=0)}else if("complete"!==i.origin)return;e.commands.autocomplete(t,null,{completeSingle:!1})}),a.on("focus",()=>this.trigger("focus")),a.on("cursorActivity",()=>{const e=a.getCursor("from"),t=a.getCursor("to");this.trigger("cursorActivity",[e,t])}),a.on("hint-shown",()=>{this.isAutocompleting=!0}),a.on("endCompletion",()=>{this.isAutocompleting=!1}),l&&a.focus(),this.code=a,this.enhanced=!0})}}class p{constructor(e="",t=""){this.renderBase=e,this.editBase=t}setRenderBase(e){this.renderBase=e}setEditBase(e){this.editBase=e}_convertCode(e,t=!1){let i=e.split("\n").map(encodeURIComponent);if(t)for(;i.length>0&&""===i[i.length-1];)--i.length;else i=i.filter(e=>""!==e);return i.join("/")}_convertWidthHeight(e,t){let i="";return l(e)&&(i+="w"+o(Math.max(e,0),4)),l(t)&&(i+="h"+o(Math.max(t,0),4)),i+"/"}_convertZoom(e){return 1===e?"":"z"+o(Math.max(e,0),4)+"/"}_convertSize({height:e,width:t,zoom:i}){return l(t)||l(e)?this._convertWidthHeight(t,e):l(i)?this._convertZoom(i):""}getRenderURL(e,t={}){return this.renderBase+this._convertSize(t)+this._convertCode(e)+".svg"}getEditURL(e){return this.editBase+"#edit:"+this._convertCode(e,!0)}}class w{constructor(){this.value=""}set(e){this.value=e}get(){return this.value}remove(){this.value=""}}const v=500,f=250,b=4;class y{constructor(e){this.id=e}set(e){try{window.localStorage.setItem(this.id,e)}catch(e){}}get(){try{return window.localStorage.getItem(this.id)||""}catch(e){return""}}remove(){try{window.localStorage.removeItem(this.id)}catch(e){}}}var A=window.SequenceDiagram;const S=/^s[0-9]+$/;var k=(e,t)=>{if(null!==e.getSlot())return Promise.resolve();const i=t.getAllSlots().sort((e,t)=>e-t);if(!i.length)return e.setSlot(1),Promise.resolve();const n=new c(window.document),s=n.el("div").setClass("pick-document").add(n.el("h1").text("Diagrams on this device:")).add(n.el("p").text("(right-click to delete)")).attach(document.body),r=new A;return new Promise(o=>{const l=i.map(e=>{const i=t.get(e),l=n.el("div").attr("title",i.trim()),a=n.el("a").attr("href",`#${e}`).setClass("pick-document-item").add(l).on("click",t=>{t.preventDefault(),o(e)}).on("contextmenu",i=>{i.preventDefault(),function(e){window.confirm("Delete this diagram?")&&(t.remove(e),window.location.reload())}(e)}).attach(s);return r.clone({code:i,container:l.element,render:!1}).on("error",(e,t)=>{window.console.warn("Failed to render preview",t),a.attr("class","pick-document-item broken"),l.text(i)})});try{r.renderAll(l)}catch(e){}i.lengtho(t.nextAvailableSlot())).attach(s)}).then(t=>{s.detach(),e.setSlot(t)})};const C=window.requirejs,x={},B={},L=window.document.getElementsByTagName("meta");for(let e=0;e{t.hashes[i]&&(e.setAttribute("integrity",t.hashes[i]),e.setAttribute("crossorigin","anonymous"))},paths:x});window.addEventListener("load",()=>{const t=window.document.getElementById("loader"),[i]=t.getElementsByTagName("nav"),n=i.getElementsByTagName("a"),s=[];for(let e=0;enull)){this.hash=e(),window.addEventListener("hashchange",()=>{e()!==this.hash&&t()})}getRawHash(){return e()}maxSlots(){return 100}getSlot(){const t=e();return d.test(t)?Number(t):null}setSlot(e){this.hash=e.toFixed(0),window.location.hash=this.hash}}(()=>{window.location.reload()});!function(e,t){const i=e.getRawHash();if(!i.startsWith("edit:"))return;let n=i.substr("edit:".length).split("/").map(decodeURIComponent).join("\n");if(!n)return;n.endsWith("\n")||(n+="\n");const s=t.nextAvailableSlot();t.set(s,n),e.setSlot(s)}(o,r),t.parentNode.removeChild(t),k(o,r).then(()=>{new class{constructor({sequenceDiagram:e,defaultCode:t="",library:i=[],links:n=[],require:s=null,storage:r=new w,touchUI:o=!1}){this.diagram=e,this.defaultCode=t,this.storage=r,this.library=i,this.links=n,this.minScale=1.5,this.require=s||(()=>null),this.touchUI=o,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._downloadURLClick=this._downloadURLClick.bind(this),this._hideDropStyle=this._hideDropStyle.bind(this),this.diagram.on("render",()=>{this.updateMinSize(this.diagram.getSize()),function(e){let t=e.trim();t.length>20&&(t=t.substr(0,18).trim()+"…"),document.title=(t?`${t} — `:"")+"Sequence Diagram"}(this.diagram.getTitle()),this.pngDirty=!0}).on("mouseover",e=>this.code.markLineHover(e.ln)).on("mouseout",()=>this.code.unmarkLineHover()).on("click",e=>{this.code.unmarkLineHover(),this.code.selectLine(e.ln),this._hideURLBuilder()}).on("dblclick",e=>{this.diagram.toggleCollapsed(e.ln),this._hideURLBuilder()})}buildURLBuilder(){const e=this.dom.el("div").setClass("copied").add("Copied to Clipboard");this.urlOutput=this.dom.el("input").setClass("output").attr("readonly","readonly").on("focus",()=>{this.urlOutput.select(0,this.urlOutput.element.value.length)});const t=this.dom.el("button").setClass("copy").attr("title","Copy to clipboard").fastClick().on("click",()=>{this.touchUI&&this.urlOutput.styles({display:"block"}),this.urlOutput.focus().select(0,this.urlOutput.element.value.length).element.ownerDocument.execCommand("copy"),t.focus(),this.container.delClass("keyinput"),this.touchUI&&this.urlOutput.styles({display:"none"}),e.styles({display:"block",opacity:1,transition:"none"}),setTimeout(()=>e.styles({opacity:0,transition:"opacity 0.5s linear"}),1e3),setTimeout(()=>e.styles({display:"none"}),1500)}),i=()=>{this.renderOpts.styles({display:this.modeEdit.element.checked?"none":"block"}),this._refreshURL()};this.modeRender=this.dom.el("input").attrs({checked:"checked",name:"export-mode",type:"radio",value:"render"}).on("change",i),this.modeEdit=this.dom.el("input").attrs({name:"export-mode",type:"radio",value:"edit"}).on("change",i),this.modeMarkdown=this.dom.el("input").attrs({name:"export-mode",type:"radio",value:"markdown"}).on("change",i),this.urlWidth=this.dom.el("input").attrs({min:0,placeholder:"auto",step:"any",type:"number"}).on("input",()=>{this.urlZoom.val("1"),this._refreshURL()}),this.urlHeight=this.dom.el("input").attrs({min:0,placeholder:"auto",step:"any",type:"number"}).on("input",()=>{this.urlZoom.val("1"),this._refreshURL()}),this.urlZoom=this.dom.el("input").attrs({min:0,step:"any",type:"number",value:1}).on("input",()=>{this.urlWidth.val(""),this.urlHeight.val(""),this._refreshURL()}),this.renderOpts=this.dom.el("div").add(this.dom.el("label").add("width ",this.urlWidth),", ",this.dom.el("label").add("height ",this.urlHeight),this.dom.el("span").setClass("or").add("or"),this.dom.el("label").add("zoom ",this.urlZoom));const n=this.dom.el("div").setClass("config").add(this.dom.el("div").setClass("export-mode").add(this.dom.el("label").add(this.modeRender,"View"),this.dom.el("label").add(this.modeEdit,"Edit"),this.dom.el("label").add(this.modeMarkdown,"Markdown")),this.renderOpts,this.urlOutput,t,e),s=this.dom.el("div").setClass("urlbuilder").styles({display:"none"}).add(this.dom.el("div").setClass("message").add("Loading…")),r="undefined"==typeof window?"http://localhost":window.location.href;return this.renderService=new p,this.renderService.setEditBase(new URL(".",r).href),function(e){return"undefined"==typeof fetch?Promise.reject(new Error):fetch(e).then(e=>{if(!e.ok)throw new Error(e.statusText);return e})}("render/").then(e=>e.text()).then(e=>{let t=e.trim();t&&!t.startsWith("<")||(t="render/"),this.renderService.setRenderBase(new URL(t,r).href),s.empty().add(n),this._refreshURL()}).catch(()=>{s.empty().add(this.dom.el("div").setClass("message").add("No online rendering service available."))}),s}_refreshURL(){const e=this.code.value(),t={height:Number.parseFloat(this.urlHeight.element.value),width:Number.parseFloat(this.urlWidth.element.value),zoom:Number.parseFloat(this.urlZoom.element.value||"1")};let i="";if(this.modeMarkdown.element.checked){const n=this.renderService.getEditURL(e),s=this.renderService.getRenderURL(e,t);i=`[![${this.diagram.getTitle().replace(/[^a-zA-Z0-9 \-_'"]/g,"").trim()}](${s})](${n})`}else i=this.modeEdit.element.checked?this.renderService.getEditURL(e):this.renderService.getRenderURL(e,t);this.urlOutput.val(i)}_showURLBuilder(){this.builderVisible||(this.builderVisible=!0,this.touchUI?this.urlBuilder.styles({bottom:"-210px",display:"block"}):this.urlBuilder.styles({display:"block",height:"0px",padding:"0px",width:this.optsHold.element.clientWidth+"px"}),clearTimeout(this.builderTm),this.builderTm=setTimeout(()=>{this.touchUI?this.urlBuilder.styles({bottom:0}):(this.urlBuilder.styles({height:"150px",padding:"10px",width:"400px"}),this.optsHold.styles({"box-shadow":"10px 10px 25px 12px rgba(0,0,0,0.3)"}))},0),this._refreshURL())}_hideURLBuilder(){this.builderVisible&&(this.builderVisible=!1,this.touchUI?this.urlBuilder.styles({bottom:-this.urlBuilder.element.clientHeight-60+"px"}):(this.urlBuilder.styles({height:"0px",padding:"0px",width:"0px"}),this.optsHold.styles({"box-shadow":"none"})),this.container.delClass("keyinput"),clearTimeout(this.builderTm),this.builderTm=setTimeout(()=>{this.urlBuilder.styles({display:"none"})},200))}buildOptionsDownloads(){return this.downloadPNG=this.dom.el("a").text("Export PNG").attrs({download:"SequenceDiagram.png",href:"#"}).on(["focus","mouseover","mousedown"],this._downloadPNGFocus).on("touchend",this._downloadPNGFocus).on("click",this._downloadPNGClick),this.downloadSVG=this.dom.el("a").text("SVG").attrs({download:"SequenceDiagram.svg",href:"#"}).fastClick().on("click",this._downloadSVGClick),this.downloadURL=this.dom.el("a").text("URL").attrs({href:"#"}).fastClick().on("click",this._downloadURLClick),this.urlBuilder=this.buildURLBuilder(),this.optsHold=this.dom.el("div").setClass("options downloads").add(this.downloadPNG,this.downloadSVG,this.downloadURL,this.urlBuilder),this.optsHold}buildLibrary(e){const t=this.library.map(t=>{const i=this.dom.el("div").attr("title",t.title||t.code),n=this.dom.el("div").setClass("library-item").add(i).fastClick().on("click",()=>this.code.addCodeBlock(t.code,t.surround)).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:i.element,render:!1}).on("error",(e,s)=>{window.console.warn("Failed to render preview",s),n.attr("class","library-item broken"),i.text(t.code)})});try{this.diagram.renderAll(t)}catch(e){}return e}buildCodePane(){const e=this.dom.el("div").setClass("pane-code");return this.code=new g(this.dom,e,{mode:"sequence",require:this.require,value:this.storage.get()||this.defaultCode}),this.code.on("enhance",(e,t)=>{this.diagram.registerCodeMirrorMode(e),t.themes=this.diagram.getThemeNames()}).on("change",()=>this.update(!1)).on("cursorActivity",(e,t)=>{this.diagram.setHighlight(Math.min(e.line,t.line))}).on("focus",()=>this._hideURLBuilder()),e}buildLibPane(){return 0===this.library.length?null:this.dom.el("div").setClass("pane-library").add(this.dom.el("div").setClass("pane-library-scroller").add(this.buildLibrary(this.dom.el("div").setClass("pane-library-inner"))))}buildViewPane(){return this.viewPaneInner=this.dom.el("div").setClass("pane-view-inner").add(this.diagram.dom()).on("touchstart",()=>this._hideURLBuilder(),{passive:!0}).on("mousedown",()=>this._hideURLBuilder()),this.errorMsg=this.dom.el("div").setClass("msg-error"),this.dom.el("div").setClass("pane-view").add(this.dom.el("div").setClass("pane-view-scroller").add(this.viewPaneInner),this.errorMsg)}build(e){this.dom=new c(e.ownerDocument),this.container=this.dom.wrap(e).on("dragover",e=>{e.preventDefault(),function(e,t){if(!e.dataTransfer.items&&0===e.dataTransfer.files.length)return[...e.dataTransfer.types].includes("Files");const i=e.dataTransfer.items||e.dataTransfer.files;return 1===i.length&&i[0].type===t}(e,"image/svg+xml")?(e.dataTransfer.dropEffect="copy",this._showDropStyle()):e.dataTransfer.dropEffect="none"}).on("dragleave",this._hideDropStyle).on("dragend",this._hideDropStyle).on("drop",e=>{e.preventDefault(),this._hideDropStyle();const t=function(e,t){const i=e.dataTransfer.items||e.dataTransfer.files;if(1!==i.length||i[0].type!==t)return null;const[n]=i;return n.getAsFile?n.getAsFile():n}(e,"image/svg+xml");t&&this.loadFile(t)}).on("focusin",()=>this.container.addClass("keyinput")).on("focusout",()=>this.container.delClass("keyinput"));const t=this.buildCodePane(),i=this.buildLibPane(),n=this.buildViewPane(),s=this.links.map(e=>{const t=this.touchUI?e.touchLabel:e.label;return t&&this.dom.el("a").attrs({href:e.href,rel:"noopener",target:e.target||""}).text(t)}).filter(e=>e);this.touchUI?(this.buildOptionsDownloads(),this.container.addClass("touch").add(this.dom.el("div").setClass("pane-hold").split([n,t],{direction:"vertical",minSize:[10,10],require:this.require,sizes:[80,20],snapOffset:20}),i.styles({display:"none",top:"100%"}),this.urlBuilder,this.dom.el("div").setClass("optbar").add(...s,this.downloadPNG.text("PNG"),this.downloadSVG.text("SVG"),this.downloadURL.text("URL")))):this.container.add(this.dom.el("div").setClass("pane-hold").split([this.dom.el("div").setClass("pane-side").split([t,i],{direction:"vertical",minSize:[100,5],require:this.require,sizes:[70,30],snapOffset:5}),n],{direction:"horizontal",minSize:[10,10],require:this.require,sizes:[30,70],snapOffset:70}),this.dom.el("div").setClass("options links").add(s),this.buildOptionsDownloads()),"undefined"!=typeof window&&window.addEventListener("keydown",e=>{27===e.keyCode&&this._hideURLBuilder()}),setTimeout(this.update.bind(this),0)}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)}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")}loadFile(e){return function(e){return new Promise(t=>{const i=new FileReader;i.addEventListener("loadend",()=>{t(i.result)},{once:!0}),i.readAsText(e)})}(e).then(e=>{const t=this.diagram.extractCodeFromSVG(e);t&&(this.code.setValue(t),this.diagram.expandAll({render:!1}),this.update(!0),this.diagram.setHighlight(null))})}update(e=!0){this._hideURLBuilder();const t=this.code.value();this.storage.set(t);let i=null;try{i=this.diagram.process(t)}catch(e){return void this.markError(e)}this.markOK();let n=0;if(!e&&this.renderedSeq){const e=this.renderedSeq;i.agents.length!==e.agents.length?n=v:i.stages.length!==e.stages.length&&(n=f)}this.redrawDebounced(i,n)}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:b}).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(),this._hideURLBuilder()}_downloadSVGClick(){this.forceRender();const e=this.diagram.getSVGSynchronous();this.downloadSVG.attr("href",e),this._hideURLBuilder()}_downloadURLClick(e){e.preventDefault(),this.builderVisible?this._hideURLBuilder():this._showURLBuilder()}}({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:a,links:s,require:C,sequenceDiagram:new A,storage:new class{constructor(e,t){this.slotManager=e,this.slotStorage=t,this.slot=this.slotManager.getSlot(),this.value=this.get(),this.originalValue=this.value,this.loadTime=Date.now(),this.internalStorageListener=this.internalStorageListener.bind(this),window.addEventListener("storage",this.internalStorageListener),this.checkSlot()}getCurrentValue(){return Date.now() {
+ const diagrams = [];
+
+ // Example 1:
+ (() => {
+ const diagram = new SequenceDiagram();
+ diagram.set('A -> B\nB -> A', {render: false});
+ diagram.dom().setAttribute('class', 'sequence-diagram');
+ document.getElementById('hold1').appendChild(diagram.dom());
+ diagram.setHighlight(1);
+ diagrams.push(diagram);
+ })();
+
+ // Snippets:
+ const elements = document.getElementsByClassName('example');
+ for(let i = 0; i < elements.length; ++ i) {
+ const el = elements[i];
+ const diagram = new SequenceDiagram(el.textContent, {render: false});
+ diagram.dom().setAttribute('class', 'example-diagram');
+ el.parentNode.insertBefore(diagram.dom(), el);
+ diagrams.push(diagram);
+ }
+
+ SequenceDiagram.renderAll(diagrams);
+
+ if(CodeMirror && CodeMirror.colorize) {
+ CodeMirror.colorize();
+ }
+}, {once: true});
diff --git a/web/scripts/interface/Interface.mjs b/web/scripts/interface/Interface.mjs
index dbde966..053383a 100644
--- a/web/scripts/interface/Interface.mjs
+++ b/web/scripts/interface/Interface.mjs
@@ -491,7 +491,11 @@ export default class Interface {
const links = this.links.map((link) => {
const label = this.touchUI ? link.touchLabel : link.label;
return label && this.dom.el('a')
- .attrs({'href': link.href, 'target': link.target || ''})
+ .attrs({
+ 'href': link.href,
+ 'rel': 'noopener',
+ 'target': link.target || '',
+ })
.text(label);
}).filter((x) => x);