diff --git a/web/lib/editor.js b/web/lib/editor.js
index 586796a..6bdf17a 100644
--- a/web/lib/editor.js
+++ b/web/lib/editor.js
@@ -253,51 +253,61 @@
{
code: '**{text}**',
preview: 'A -> B: **bold**',
+ surround: true,
title: 'Bold markdown',
},
{
code: '_{text}_',
preview: 'A -> B: _italic_',
+ surround: true,
title: 'Italic markdown',
},
{
code: '~{text}~',
preview: 'A -> B: ~strikeout~',
+ surround: true,
title: 'Strikeout markdown',
},
{
code: '{text}',
preview: 'A -> B: underline',
+ surround: true,
title: 'Underline markdown',
},
{
code: '{text}',
preview: 'A -> B: overline',
+ surround: true,
title: 'Overline markdown',
},
{
code: '{text}',
preview: 'A -> B: superscript',
+ surround: true,
title: 'Superscript markdown',
},
{
code: '{text}',
preview: 'A -> B: subscript',
+ surround: true,
title: 'Subscript markdown',
},
{
code: '`{text}`',
preview: 'A -> B: `mono`',
+ surround: true,
title: 'Monospace markdown',
},
{
code: '{text}',
preview: 'A -> B: red',
+ surround: true,
title: 'Red markdown',
},
{
code: '{text}',
preview: 'A -> B: highlight',
+ surround: true,
title: 'Highlight markdown',
},
{
@@ -870,6 +880,15 @@
return null;
}
+ function lineWithinRange(doc, ln, start, end) {
+ const full = doc.getLine(ln);
+ const begin = (ln === start.line) ? start.ch : 0;
+ return {
+ chOffset: begin,
+ line: (ln === end.line) ? full.slice(begin, end.ch) : full.slice(begin),
+ };
+ }
+
class CodeEditor extends EventObject {
constructor(dom, container, {
mode = '',
@@ -974,8 +993,8 @@
this.code.off('cursorActivity', move);
this.paramMarkers.forEach((m) => m.clear());
this.paramMarkers = null;
+ this.code.setCursor(endBookmark.find());
endBookmark.clear();
- this.code.setCursor(end);
this.cancelParams = null;
this.advanceParams = null;
};
@@ -1001,12 +1020,12 @@
const doc = this.code.getDoc();
const ranges = [];
- let {ch} = start;
- for(let ln = start.line; ln < endBookmark.find().line; ++ ln) {
- const line = doc.getLine(ln).slice(ch);
+ const end = endBookmark.find();
+ for(let ln = start.line; ln <= end.line; ++ ln) {
+ const {chOffset, line} = lineWithinRange(doc, ln, start, end);
for(let p = 0; (p = line.indexOf(tok, p)) !== -1; p += tok.length) {
- const anchor = {ch: p, line: ln};
- const head = {ch: p + tok.length, line: ln};
+ const anchor = {ch: chOffset + p, line: ln};
+ const head = {ch: chOffset + p + tok.length, line: ln};
ranges.push({anchor, head});
this.paramMarkers.push(doc.markText(anchor, head, {
className: 'param',
@@ -1015,7 +1034,6 @@
inclusiveRight: true,
}));
}
- ch = 0;
}
if(ranges.length > 0) {
@@ -1025,11 +1043,39 @@
}
}
- addCodeBlock(block) {
- const lines = block.split('\n').length;
+ hasSelection() {
+ const from = this.code.getCursor('from');
+ const to = this.code.getCursor('to');
+ return from.line !== to.line || from.ch !== to.ch;
+ }
- this.code.focus();
+ internalAddSurroundCode(block) {
+ if(this.enhanced) {
+ if(this.hasSelection()) {
+ this.code.replaceSelection(
+ block.replace(/\{.*\}/, this.code.getSelection()),
+ 'end',
+ 'library'
+ );
+ } else {
+ const cur = this.code.getCursor('head');
+ this.code.replaceSelection(block, null, 'library');
+ const end = {ch: cur.ch + block.length, line: cur.line};
+ this.enterParams(cur, end, block);
+ }
+ } else {
+ const value = this.value();
+ const s1 = this.code.element.selectionStart;
+ const s2 = this.code.element.selectionEnd;
+ const wrapped = block.replace(/\{.*\}/, value.substring(s1, s2));
+ this.code
+ .val(value.substr(0, s1) + wrapped + value.substr(s2))
+ .select(s1 + wrapped.length);
+ this.trigger('change');
+ }
+ }
+ internalAddIndependentCode(block) {
if(this.enhanced) {
const cur = this.code.getCursor('head');
const pos = {ch: 0, line: cur.line + ((cur.ch > 0) ? 1 : 0)};
@@ -1038,6 +1084,7 @@
replaced = '\n' + replaced;
}
this.code.replaceRange(replaced, pos, null, 'library');
+ const lines = block.split('\n').length;
const end = {ch: 0, line: pos.line + lines};
this.enterParams(pos, end, block);
} else {
@@ -1055,6 +1102,16 @@
}
}
+ addCodeBlock(block, surround = false) {
+ this.code.focus();
+
+ if(surround) {
+ this.internalAddSurroundCode(block);
+ } else {
+ this.internalAddIndependentCode(block);
+ }
+ }
+
value() {
if(this.enhanced) {
return this.code.getDoc().getValue();
@@ -1645,7 +1702,10 @@
.setClass('library-item')
.add(holdInner)
.fastClick()
- .on('click', () => this.code.addCodeBlock(lib.code))
+ .on('click', () => this.code.addCodeBlock(
+ lib.code,
+ lib.surround
+ ))
.attach(container);
return this.diagram.clone({
diff --git a/web/lib/editor.min.js b/web/lib/editor.min.js
index 75306bf..cfbefa3 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){const i=e.toString(),s=i.indexOf(".");return-1===s||i.length-s-1<=t?i:e.toFixed(t)}function o(e=null){return null!==e&&!Number.isNaN(e)}var l=[{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 "[]