@mjasnikovs/pi-task 0.17.21 → 0.17.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/remote/bridge.d.ts +8 -0
- package/dist/remote/bridge.js +10 -0
- package/dist/remote/events.js +10 -4
- package/dist/remote/history.d.ts +11 -1
- package/dist/remote/history.js +1 -1
- package/dist/remote/protocol.d.ts +23 -2
- package/dist/remote/protocol.js +2 -0
- package/dist/remote/register.js +7 -3
- package/dist/remote/server.d.ts +1 -1
- package/dist/remote/server.js +5 -1
- package/dist/remote/session-state.d.ts +19 -5
- package/dist/remote/session-state.js +55 -9
- package/dist/remote/ui-highlight.d.ts +2 -0
- package/dist/remote/ui-highlight.js +119 -0
- package/dist/remote/ui-render.d.ts +2 -0
- package/dist/remote/ui-render.js +173 -0
- package/dist/remote/ui-script.js +425 -146
- package/dist/remote/ui-styles.d.ts +1 -1
- package/dist/remote/ui-styles.js +175 -8
- package/dist/remote/ui-tools.d.ts +2 -0
- package/dist/remote/ui-tools.js +113 -0
- package/dist/remote/ui.js +19 -1
- package/dist/task/impl-widget.js +2 -2
- package/dist/task/widget.d.ts +9 -0
- package/dist/task/widget.js +42 -2
- package/package.json +1 -1
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// Pure string→HTML render helpers, shipped to the browser as a JS string and
|
|
2
|
+
// concatenated into the page by ui.ts BEFORE clientScript. Splitting these out
|
|
3
|
+
// of the 900-line client template gives them a testability seam: each emitted
|
|
4
|
+
// function is `new Function`-eval'd in a unit test and asserted on its return
|
|
5
|
+
// value, with no DOM needed. (The shipped fence bug survived because the client
|
|
6
|
+
// JS was never executed by any test — only string-matched.)
|
|
7
|
+
//
|
|
8
|
+
// Exposes (as top-level fn declarations in the page's single <script>):
|
|
9
|
+
// escHtml(s) — HTML-escape & < >
|
|
10
|
+
// parseBlocks(text) — line-based fence scanner (text vs code segments)
|
|
11
|
+
// renderInline(s) — inline markdown (bold/italic/strike/code/links)
|
|
12
|
+
// renderMarkdown(text) — full block-level markdown → HTML string
|
|
13
|
+
// renderMarkdown calls syntaxHighlight (ui-highlight.ts); both land in the same
|
|
14
|
+
// <script>, so declaration order across the concatenated modules doesn't matter.
|
|
15
|
+
/** Emitted client JS (top-level function declarations). */
|
|
16
|
+
export function renderModule() {
|
|
17
|
+
return ` function escHtml(s) {
|
|
18
|
+
return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Split text into ordered {type:'text'|'code', ...} blocks by scanning lines
|
|
22
|
+
// for a fenced code marker at line start. This replaces a RegExp that was built
|
|
23
|
+
// from a string where '[\\\\s\\\\S]' collapsed to '[sS]', so it matched nothing
|
|
24
|
+
// and every code block rendered as raw text. A line scanner also tolerates an
|
|
25
|
+
// unclosed trailing fence, which the regex never could.
|
|
26
|
+
function parseBlocks(text) {
|
|
27
|
+
var FENCE = String.fromCharCode(96, 96, 96);
|
|
28
|
+
var lines = String(text == null ? '' : text).split('\\n');
|
|
29
|
+
var blocks = [];
|
|
30
|
+
var textBuf = [];
|
|
31
|
+
function flushText() {
|
|
32
|
+
if (textBuf.length) { blocks.push({type: 'text', content: textBuf.join('\\n')}); textBuf = []; }
|
|
33
|
+
}
|
|
34
|
+
var i = 0;
|
|
35
|
+
while (i < lines.length) {
|
|
36
|
+
var line = lines[i];
|
|
37
|
+
if (line.slice(0, 3) === FENCE) {
|
|
38
|
+
flushText();
|
|
39
|
+
var lang = line.slice(3).trim();
|
|
40
|
+
var codeLines = [];
|
|
41
|
+
i++;
|
|
42
|
+
while (i < lines.length && lines[i].trim() !== FENCE) { codeLines.push(lines[i]); i++; }
|
|
43
|
+
if (i < lines.length) i++; // consume the closing fence; tolerate EOF (unclosed)
|
|
44
|
+
blocks.push({type: 'code', lang: lang, content: codeLines.join('\\n')});
|
|
45
|
+
} else {
|
|
46
|
+
textBuf.push(line);
|
|
47
|
+
i++;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
flushText();
|
|
51
|
+
return blocks;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Inline formatting on ONE line's worth of text. Code spans are extracted first
|
|
55
|
+
// (and protected with a NUL placeholder) so emphasis inside them is left alone.
|
|
56
|
+
function renderInline(s) {
|
|
57
|
+
s = escHtml(String(s == null ? '' : s));
|
|
58
|
+
var BT = String.fromCharCode(96);
|
|
59
|
+
var codes = [];
|
|
60
|
+
var codeRe = new RegExp(BT + '([^' + BT + ']+)' + BT, 'g');
|
|
61
|
+
s = s.replace(codeRe, function (_, c) { codes.push(c); return '\\u0000' + (codes.length - 1) + '\\u0000'; });
|
|
62
|
+
s = s.replace(/\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/g, function (_, t, u) {
|
|
63
|
+
var safe = /^(https?:|mailto:)/i.test(u) ? u : '#';
|
|
64
|
+
return '<a href="' + safe + '" target="_blank" rel="noopener">' + t + '</a>';
|
|
65
|
+
});
|
|
66
|
+
s = s.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');
|
|
67
|
+
s = s.replace(/__([^_]+)__/g, '<strong>$1</strong>');
|
|
68
|
+
s = s.replace(/\\*([^*]+)\\*/g, '<em>$1</em>');
|
|
69
|
+
s = s.replace(/~~([^~]+)~~/g, '<del>$1</del>');
|
|
70
|
+
s = s.replace(/\\u0000(\\d+)\\u0000/g, function (_, n) { return '<code class="md-code">' + codes[n] + '</code>'; });
|
|
71
|
+
return s;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// A line that begins a block-level construct — used to stop paragraph grouping.
|
|
75
|
+
function mdIsSpecial(l) {
|
|
76
|
+
return /^(#{1,6})\\s+/.test(l)
|
|
77
|
+
|| /^\\s*>\\s?/.test(l)
|
|
78
|
+
|| /^\\s*([-*+]|\\d+\\.)\\s+/.test(l)
|
|
79
|
+
|| /^\\s*([-*_])\\s*(\\1\\s*){2,}$/.test(l);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function mdParseList(lines, i) {
|
|
83
|
+
var ordered = /^\\s*\\d+\\.\\s+/.test(lines[i]);
|
|
84
|
+
var tag = ordered ? 'ol' : 'ul';
|
|
85
|
+
var items = '';
|
|
86
|
+
while (i < lines.length && /^\\s*([-*+]|\\d+\\.)\\s+/.test(lines[i])) {
|
|
87
|
+
var content = lines[i].replace(/^\\s*([-*+]|\\d+\\.)\\s+/, '');
|
|
88
|
+
var task = /^\\[([ xX])\\]\\s+(.*)$/.exec(content);
|
|
89
|
+
if (task) {
|
|
90
|
+
var checked = task[1].toLowerCase() === 'x';
|
|
91
|
+
items += '<li class="md-task"><span class="md-check">' + (checked ? '\\u2611' : '\\u2610') + '</span> ' + renderInline(task[2]) + '</li>';
|
|
92
|
+
} else {
|
|
93
|
+
items += '<li>' + renderInline(content) + '</li>';
|
|
94
|
+
}
|
|
95
|
+
i++;
|
|
96
|
+
}
|
|
97
|
+
return {html: '<' + tag + ' class="md-list">' + items + '</' + tag + '>', next: i};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function mdParseTable(lines, i) {
|
|
101
|
+
function cells(l) {
|
|
102
|
+
var s = l.trim().replace(/^\\|/, '').replace(/\\|$/, '');
|
|
103
|
+
return s.split('|').map(function (c) { return c.trim(); });
|
|
104
|
+
}
|
|
105
|
+
var head = cells(lines[i]);
|
|
106
|
+
i += 2; // skip the header row and the |---| separator
|
|
107
|
+
var body = '';
|
|
108
|
+
while (i < lines.length && /\\|/.test(lines[i]) && lines[i].trim() !== '') {
|
|
109
|
+
var row = cells(lines[i]);
|
|
110
|
+
var tds = '';
|
|
111
|
+
for (var c = 0; c < row.length; c++) tds += '<td>' + renderInline(row[c]) + '</td>';
|
|
112
|
+
body += '<tr>' + tds + '</tr>';
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
115
|
+
var ths = '';
|
|
116
|
+
for (var c2 = 0; c2 < head.length; c2++) ths += '<th>' + renderInline(head[c2]) + '</th>';
|
|
117
|
+
return {html: '<table class="md-table"><thead><tr>' + ths + '</tr></thead><tbody>' + body + '</tbody></table>', next: i};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Block-level markdown for one text segment (no fences — those are split off by
|
|
121
|
+
// renderMarkdown first). Headers, hr, blockquotes, tables, lists, paragraphs.
|
|
122
|
+
function renderProse(src) {
|
|
123
|
+
var lines = String(src == null ? '' : src).split('\\n');
|
|
124
|
+
var html = '';
|
|
125
|
+
var i = 0;
|
|
126
|
+
while (i < lines.length) {
|
|
127
|
+
var line = lines[i];
|
|
128
|
+
if (line.trim() === '') { i++; continue; }
|
|
129
|
+
var h = /^(#{1,6})\\s+(.*)$/.exec(line);
|
|
130
|
+
if (h) { var lvl = h[1].length; html += '<h' + lvl + ' class="md-h md-h' + lvl + '">' + renderInline(h[2]) + '</h' + lvl + '>'; i++; continue; }
|
|
131
|
+
if (/^\\s*([-*_])\\s*(\\1\\s*){2,}$/.test(line)) { html += '<hr class="md-hr">'; i++; continue; }
|
|
132
|
+
if (/^\\s*>\\s?/.test(line)) {
|
|
133
|
+
var q = [];
|
|
134
|
+
while (i < lines.length && /^\\s*>\\s?/.test(lines[i])) { q.push(lines[i].replace(/^\\s*>\\s?/, '')); i++; }
|
|
135
|
+
html += '<blockquote class="md-quote">' + renderProse(q.join('\\n')) + '</blockquote>';
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (/\\|/.test(line) && i + 1 < lines.length && /^\\s*\\|?[\\s:|-]*-[\\s:|-]*\\|?\\s*$/.test(lines[i + 1])) {
|
|
139
|
+
var t = mdParseTable(lines, i); html += t.html; i = t.next; continue;
|
|
140
|
+
}
|
|
141
|
+
if (/^\\s*([-*+]|\\d+\\.)\\s+/.test(line)) {
|
|
142
|
+
var lst = mdParseList(lines, i); html += lst.html; i = lst.next; continue;
|
|
143
|
+
}
|
|
144
|
+
var para = [];
|
|
145
|
+
while (i < lines.length && lines[i].trim() !== '' && !mdIsSpecial(lines[i])) { para.push(lines[i]); i++; }
|
|
146
|
+
var inner = [];
|
|
147
|
+
for (var p = 0; p < para.length; p++) inner.push(renderInline(para[p]));
|
|
148
|
+
html += '<p class="md-p">' + inner.join('<br>') + '</p>';
|
|
149
|
+
}
|
|
150
|
+
return html;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function renderMarkdown(text) {
|
|
154
|
+
var blocks = parseBlocks(text);
|
|
155
|
+
var out = '';
|
|
156
|
+
for (var k = 0; k < blocks.length; k++) {
|
|
157
|
+
var b = blocks[k];
|
|
158
|
+
if (b.type === 'code') {
|
|
159
|
+
// Header row carries the language label and a copy button (wired by
|
|
160
|
+
// event delegation in clientScript — it reads the <code> textContent).
|
|
161
|
+
out += '<div class="code-block"><div class="code-head">'
|
|
162
|
+
+ '<div class="code-lang">' + (b.lang ? escHtml(b.lang) : '') + '</div>'
|
|
163
|
+
+ '<button class="copy-btn" type="button" aria-label="Copy code">Copy</button>'
|
|
164
|
+
+ '</div>'
|
|
165
|
+
+ '<pre><code>' + syntaxHighlight(b.content, b.lang) + '</code></pre></div>';
|
|
166
|
+
} else {
|
|
167
|
+
out += renderProse(b.content);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
`;
|
|
173
|
+
}
|