tangled
alpha
login
or
join now
ansxor.ca
/
markup2
0
fork
atom
this repo has no description
0
fork
atom
overview
issues
1
pulls
pipelines
change codeblock parsing, also major updates to demo page
12Me21
3 years ago
c0dd4e2c
7f815641
+268
-290
10 changed files
expand all
collapse all
unified
split
index.html
markup.css
parse.js
testing
common.css
index.html
nav.js
textarea.js
tree.css
tree.html
tree.js
+80
-105
index.html
···
1
1
-
<!DOCTYPE html>
2
2
-
<html lang=en-QS>
3
3
-
<meta id=ݽ charset=utf-8>
1
1
+
<!doctype html><html lang=en-QS><meta id=ݽ charset=utf-8>
2
2
+
<meta name=viewport content="width=device-width, height=device-height, initial-scale=1">
3
3
+
4
4
<title>Markup2 Demo</title>
5
5
6
6
<script src=langs.js></script>
···
9
9
<script src=render.js></script>
10
10
<script src=runtime.js></script>
11
11
<script src=helpers.js></script>
12
12
+
<link rel=stylesheet href=markup.css>
12
13
14
14
+
<script src=testing/textarea.js></script>
15
15
+
<link rel=stylesheet href=testing/common.css>
13
16
<script src=testing/tree.js></script>
17
17
+
<link rel=stylesheet href=testing/tree.css>
14
18
15
15
-
<meta name=viewport content="width=device-width, initial-scale=1, height=device-height">
16
16
-
<link rel=stylesheet href=markup.css>
17
19
<style>
18
18
-
html { word-break: break-word; }
19
19
-
20
20
-
html, body {
21
21
-
position:fixed; top:0;left:0;right:0;bottom:0;
22
22
-
background: var(--T-bg, white);
20
20
+
table.times {
21
21
+
width: 100%;
23
22
}
24
24
-
25
25
-
html, select { font: var(--T-font); }
26
26
-
27
23
table.times, table.times td, table.times th {
24
24
+
color: black;
28
25
border: 1px solid currentColor;
29
26
border-spacing: 0;
30
27
}
···
32
29
padding: 2px 5px;
33
30
word-break: normal; overflow-wrap: break-word;
34
31
}
32
32
+
table.times td {
33
33
+
color: black;
34
34
+
background: white;
35
35
+
}
35
36
table.times th {
36
37
font-weight: bold;
37
38
color: white;
···
39
40
}
40
41
table-overflow {
41
42
overflow-x: auto;
43
43
+
background: #222;
44
44
+
color: #FFF;
42
45
}
43
46
44
47
#\$output {
45
48
border: 3px solid black;
46
49
padding: 2px;
47
50
overflow-y: auto;
51
51
+
}
52
52
+
#\$inputs {
53
53
+
flex-wrap: wrap;
54
54
+
gap: .25em;
55
55
+
background: #222;
56
56
+
color: #FFF;
57
57
+
padding: 2px;
48
58
}
49
59
50
50
-
body {
51
51
-
display: flex; /* grid. rowheights: min-content auto, colwidths: 1fr 1fr on mobile, uh stack them liiike.. just do a normal block scrolling layout (should textarea/output ever scroll?) or maybe display one at a time? just have an options dropdown?*/
60
60
+
label {
61
61
+
align-self: center;
62
62
+
font-weight: bold;
52
63
}
53
53
-
body > * {
54
54
-
width: 50%;
55
55
-
}
56
56
-
.Col { display: flex; flex-direction: column; }
57
57
-
.Col > * { flex-shrink: 0; }
58
58
-
.Col > .limit { flex-shrink: 1; min-height: 0; }
59
64
</style>
60
65
61
61
-
<input-pane class='Col'>
62
62
-
<select id=$lang>
63
63
-
<option> 12y2
64
64
-
<option> 12y
65
65
-
<option> bbcode
66
66
-
<option> plaintext
67
67
-
</select>
66
66
+
<body class='Col'>
67
67
+
<script src=testing/nav.js></script>
68
68
+
69
69
+
<main class='fill Split'>
70
70
+
<input-pane class='Col'>
71
71
+
<div class='Row' id=$inputs>
72
72
+
<select id=$lang value=12y2>
73
73
+
<option> 12y2
74
74
+
<option> 12y
75
75
+
<option> bbcode
76
76
+
<option value=plaintext> plain
77
77
+
</select>
78
78
+
<span class='fill'></span>
79
79
+
<select id=$display value=render>
80
80
+
<option> render
81
81
+
<option> nodes
82
82
+
<option> json
83
83
+
</select>
84
84
+
</div>
85
85
+
86
86
+
<textarea-container class='limit'>
87
87
+
<textarea id=$input></textarea>
88
88
+
</textarea-container>
89
89
+
</input-pane>
68
90
69
69
-
<textarea-container class='limit'>
70
70
-
<textarea id=$input></textarea>
71
71
-
</textarea-container>
72
72
-
</input-pane>
91
91
+
<output-pane class='Col'>
92
92
+
<table-overflow><table class='times'>
93
93
+
<tr>
94
94
+
<th> <th> parse <th> render <th> layout <th> total
95
95
+
<tr>
96
96
+
<th> ms
97
97
+
<td> <time id=$time1 datetime=Z></time>
98
98
+
<td> <time id=$time2 datetime=Z></time>
99
99
+
<td> <time id=$time3 datetime=Z></time>
100
100
+
<td> <time id=$time4 datetime=Z></time>
101
101
+
</table></table-overflow>
102
102
+
<span id=$count></span>
103
103
+
<div id=$output class='Markup limit'></div>
104
104
+
</output-pane>
105
105
+
</main>
73
106
74
74
-
<output-pane class='Col'>
75
75
-
<table-overflow><table class=times>
76
76
-
<tr>
77
77
-
<th> <th> parse <th> render <th> layout <th> total
78
78
-
<tr>
79
79
-
<th> time (ms)
80
80
-
<td> <time id=$time1 datetime=Z></time>
81
81
-
<td> <time id=$time2 datetime=Z></time>
82
82
-
<td> <time id=$time3 datetime=Z></time>
83
83
-
<td> <time id=$time4 datetime=Z></time>
84
84
-
</table></table-overflow>
85
85
-
<span id=$count></span>
86
86
-
<div id=$output class='Markup limit'></div>
87
87
-
</output-pane>
88
88
-
89
107
<script>
90
90
-
let batch = (cb,w=0)=>e=>w++||requestAnimationFrame(_=>cb(e,w=0))
91
91
-
92
108
function show_time(elem, ms) {
93
109
elem.dateTime = (ms/1000).toFixed(4)+' s'
94
110
elem.textContent = ms.toFixed(1)
···
96
112
97
113
function update() {
98
114
//Markup.convert_lang($input.value, $lang.value, $output)
99
99
-
let t0 = performance.now()
115
115
+
let t0, t1, t2, t3
116
116
+
t0 = performance.now()
100
117
let tree = Markup.langs.parse($input.value, $lang.value)
101
101
-
window.tree = tree
102
102
-
let t1 = performance.now()
103
103
-
$output.replaceChildren(Markup.renderer.render(tree))
104
104
-
let t2 = performance.now()
118
118
+
t1 = performance.now()
119
119
+
if ('render'==$display.value) {
120
120
+
$output.replaceChildren(Markup.renderer.render(tree))
121
121
+
} else if ('nodes'==$display.value) {
122
122
+
let e = draw_tree(tree)
123
123
+
$output.replaceChildren(e)
124
124
+
} else if ('json'==$display.value) {
125
125
+
$output.textContent = JSON.stringify(tree)
126
126
+
}
127
127
+
t2 = performance.now()
105
128
$output.scrollHeight
106
106
-
let t3 = performance.now()
129
129
+
t3 = performance.now()
107
130
show_time($time1, t1-t0)
108
131
show_time($time2, t2-t1)
109
132
show_time($time3, t3-t2)
110
133
show_time($time4, t3-t0)
111
134
}
112
135
113
113
-
$input.addEventListener('input', batch(update), {passive:true})
136
136
+
setup_textarea($input, update)
114
137
115
115
-
//$input.oninput = update
116
138
$lang.onchange = update
139
139
+
$display.onchange = update
117
140
update()
118
141
</script>
119
119
-
120
120
-
121
121
-
<!-- textarea -->
122
122
-
123
123
-
<style>
124
124
-
textarea-container, textarea-container > textarea {
125
125
-
display: block;
126
126
-
box-sizing: content-box;
127
127
-
min-height: 5em;
128
128
-
height: 0;
129
129
-
font: 1em monospace;
130
130
-
}
131
131
-
132
132
-
textarea-container {
133
133
-
padding: 2px;
134
134
-
border: 2px solid #00C8B4;
135
135
-
border-radius: 2px;
136
136
-
}
137
137
-
138
138
-
textarea-container > textarea {
139
139
-
resize: none;
140
140
-
overflow-y: scroll;
141
141
-
margin: 0;
142
142
-
border: none;
143
143
-
padding: 0;
144
144
-
width: 100%;
145
145
-
146
146
-
appearance: none;
147
147
-
outline-offset: 2px;
148
148
-
}
149
149
-
</style>
150
150
-
151
151
-
<script>
152
152
-
{
153
153
-
let resize = (t)=>{
154
154
-
t.style.height = "0"
155
155
-
t.parentNode.style.height = `${t.scrollHeight+1}px`
156
156
-
t.style.height = "100%"
157
157
-
}
158
158
-
document.addEventListener('input', function(e) {
159
159
-
let t = e.target
160
160
-
if (t instanceof HTMLTextAreaElement && t.parentNode.tagName=='TEXTAREA-CONTAINER')
161
161
-
resize(t)
162
162
-
}, {passive: true})
163
163
-
for (let t of document.querySelectorAll("textarea-container > textarea"))
164
164
-
resize(t)
165
165
-
}
166
166
-
</script>
+30
markup.css
···
336
336
.M-media-volume {
337
337
width: 50px;
338
338
}
339
339
+
340
340
+
/**************/
341
341
+
/** Headings **/
342
342
+
/**************/
343
343
+
344
344
+
.Markup h2, .Markup h3, .Markup h4, .Markup h5 {
345
345
+
margin: 0.1em 0;
346
346
+
border-bottom: 1px dotted var(--T-border-color);
347
347
+
}
348
348
+
349
349
+
.Markup h2 {
350
350
+
font-size: 2em;
351
351
+
font-weight: 500;
352
352
+
background: var(--T-gray-bg);
353
353
+
padding: 0 0.1em;
354
354
+
border-bottom: 1px solid var(--T-border-color);
355
355
+
border-top: 1px solid var(--T-border-color);
356
356
+
}
357
357
+
358
358
+
.Markup h3 {
359
359
+
background: var(--T-box-bg);
360
360
+
padding: 0 0.1em;
361
361
+
font-size: 1.6875em;
362
362
+
font-weight: 500;
363
363
+
}
364
364
+
365
365
+
.Markup h4 {
366
366
+
font-size: 1.3125em;
367
367
+
font-weight: bold;
368
368
+
}
+8
-11
parse.js
···
68
68
const ARGS_TABLE = // /[...]? */
69
69
/(?:\[([^\]\n]*)\])? */y
70
70
71
71
-
const ARGS_CODE = // /uhhh
72
72
-
/(?: *([-\w.+#$ ]+?)? *(?:\n|$))?([^]*?)(?:```|$)/y
73
73
-
ARGS_CODE._raw = true
71
71
+
const ARGS_CODE = // ... ```
72
72
+
/(?: *([-\w.+#$ ]+?) *(?:\n|$))?([^]*?)(?:```|$)/y
74
73
75
74
// problem with improving style parsing:
76
75
// sometimes a style tag might be valid as both a start and end tag?
···
84
83
PAT`[\\][{][\n]?${{ NULL_ENV: 0}}`
85
84
PAT`[\\]{ANY}${{ ESCAPED: 0}}`
86
85
PAT`{BOL}[>]${{ QUOTE: ARGS_HEADING}}`
87
87
-
PAT`{BOL}[\`]{3}${{ CODE_BLOCK: ARGS_CODE}}`
86
86
+
PAT`{BOL}[\`]{3}(?=[^\n\`]*?{EOL})${{ CODE_BLOCK: ARGS_CODE}}`
88
87
PAT`[\`][^\`\n]*([\`]{2}[^\`\n]*)*[\`]?${{ INLINE_CODE: 0}}`
89
88
PAT`([!]${{ EMBED: ARGS_BODYLESS}})?\b(https?://|sbs:){URL_CHARS}({URL_FINAL}|[(]{URL_CHARS}[)]({URL_CHARS}{URL_FINAL})?)${{ LINK: ARGS_NORMAL}}`
90
89
PAT`{BOL} *[|]${{ TABLE_START: ARGS_TABLE}}`
···
180
179
OPEN('quote', token, {cite: rargs[0]}, body)
181
180
} break; case 'CODE_BLOCK': {
182
181
let lang = rargs
183
183
-
// idea: strip leading indent from code?
184
182
BLOCK('code', {text: body, lang})
185
183
} break; case 'INLINE_CODE': {
186
184
BLOCK('icode', {text: token.replace(/`(`)?/g, "$1")})
···
500
498
type = 'INVALID_TAG'
501
499
argregex = ARGS_NORMAL
502
500
}
501
501
+
} else if ('TABLE_CELL'===type && !in_table()) {
502
502
+
REGEX.lastIndex = match.index+1
503
503
+
last = match.index
504
504
+
continue
503
505
} else {
504
504
-
if ('TABLE_CELL'===type && !in_table()) {
505
505
-
REGEX.lastIndex = match.index+1
506
506
-
last = match.index
507
507
-
continue
508
508
-
}
509
506
argregex = ARGTYPES[group_num]
510
507
}
511
508
···
531
528
let body = argmatch[2] // the {, or contents of raw tags
532
529
let word = argmatch[3] // only for syntax like \sub word
533
530
534
534
-
if (!argregex._raw) {
531
531
+
if (ARGS_CODE!==argregex) {
535
532
args = parse_args(args)
536
533
start_line = body
537
534
}
+48
testing/common.css
···
1
1
+
html { word-break: break-word; }
2
2
+
3
3
+
html, body {
4
4
+
position: fixed;
5
5
+
top:0; left:0; right:0; bottom:0;
6
6
+
background: var(--T-bg, white);
7
7
+
}
8
8
+
9
9
+
html, select {
10
10
+
font: var(--T-font);
11
11
+
}
12
12
+
13
13
+
.Row, .Col {
14
14
+
display: flex;
15
15
+
}
16
16
+
.Col {
17
17
+
flex-direction: column;
18
18
+
}
19
19
+
20
20
+
.Col > *, .Row > * {
21
21
+
flex-shrink: 0;
22
22
+
}
23
23
+
.Col > .limit, .Row > .limit {
24
24
+
flex-shrink: 1;
25
25
+
min-height: 0;
26
26
+
}
27
27
+
.Col > .fill, .Row > .fill {
28
28
+
flex-grow: 1;
29
29
+
flex-shrink: 1;
30
30
+
min-height: 0;
31
31
+
}
32
32
+
33
33
+
.Split {
34
34
+
display: flex;
35
35
+
}
36
36
+
.Split > * {
37
37
+
width: 50%;
38
38
+
}
39
39
+
40
40
+
@media all and (max-width: 550px) {
41
41
+
.Split {
42
42
+
flex-direction: column-reverse;
43
43
+
justify-content: left;
44
44
+
}
45
45
+
.Split > * {
46
46
+
width: unset;
47
47
+
}
48
48
+
}
+3
testing/index.html
···
9
9
<script src=draw.js></script>
10
10
<link rel=stylesheet href=style.css>
11
11
12
12
+
<body>
13
13
+
<script src=nav.js></script>
14
14
+
12
15
<button onclick="run()">run tests</button>
13
16
<hr>
14
17
<div id=$output></div>
+39
testing/nav.js
···
1
1
+
//let base = new URL("./", document.baseURI)
2
2
+
let pages = [
3
3
+
["Demo", 'index.html'],
4
4
+
["Tests", 'testing/index.html'],
5
5
+
]
6
6
+
function make_link([title, url]) {
7
7
+
let a = document.createElement('a')
8
8
+
a.href = new URL("../"+url, document.currentScript.src)
9
9
+
a.textContent = title
10
10
+
if (a.href == window.location)
11
11
+
a.classList.add('current')
12
12
+
return a
13
13
+
}
14
14
+
let nav = document.createElement('nav')
15
15
+
nav.append(...pages.map(make_link))
16
16
+
document.currentScript.replaceWith(nav)
17
17
+
18
18
+
let style = document.createElement('style')
19
19
+
style.textContent = `
20
20
+
nav {
21
21
+
display: flex;
22
22
+
gap: 0.5em;
23
23
+
font: 1em sans-serif;
24
24
+
align-items: start;
25
25
+
margin-bottom: 8px;
26
26
+
}
27
27
+
nav > a {
28
28
+
border: 3px solid;
29
29
+
border-color: currentColor transparent;
30
30
+
text-decoration: none;
31
31
+
padding: 0 0.5em;
32
32
+
font-weight: bold;
33
33
+
}
34
34
+
nav > a.current {
35
35
+
color: gray;
36
36
+
border: 3px dotted gray;
37
37
+
}
38
38
+
`
39
39
+
document.head.append(style)
+53
testing/textarea.js
···
1
1
+
{
2
2
+
let style = document.createElement('style')
3
3
+
style.textContent = `
4
4
+
textarea-container, textarea-container > textarea {
5
5
+
display: block;
6
6
+
box-sizing: content-box;
7
7
+
min-height: 5em;
8
8
+
height: 0;
9
9
+
font: 1em monospace;
10
10
+
}
11
11
+
12
12
+
textarea-container {
13
13
+
padding: 2px;
14
14
+
border: 2px solid #00C8B4;
15
15
+
border-radius: 2px;
16
16
+
}
17
17
+
18
18
+
textarea-container > textarea {
19
19
+
resize: none;
20
20
+
overflow-y: scroll;
21
21
+
margin: 0;
22
22
+
border: none;
23
23
+
padding: 0;
24
24
+
width: 100%;
25
25
+
26
26
+
appearance: none;
27
27
+
outline-offset: 2px;
28
28
+
}
29
29
+
`
30
30
+
document.head.append(style)
31
31
+
32
32
+
let resize = (t)=>{
33
33
+
t.style.height = "0"
34
34
+
t.parentNode.style.height = `${t.scrollHeight+1}px`
35
35
+
t.style.height = "100%"
36
36
+
}
37
37
+
38
38
+
function setup_textarea(textarea, callback) {
39
39
+
resize(textarea)
40
40
+
41
41
+
let lock = false
42
42
+
textarea.addEventListener('input', e=>{
43
43
+
resize(textarea)
44
44
+
if (lock)
45
45
+
return
46
46
+
lock = true
47
47
+
window.setTimeout(()=>{
48
48
+
lock = false
49
49
+
callback(e)
50
50
+
})
51
51
+
}, {passive: true, capture: true})
52
52
+
}
53
53
+
}
+5
-4
testing/tree.css
···
6
6
background: lavender;
7
7
border: 2px solid purple;
8
8
border-radius: 10px 10px 0 0;
9
9
-
padding: 1px 3px;
9
9
+
padding: 1px 5px;
10
10
vertical-align: top;
11
11
border-collapse: collapse;
12
12
border-left-color: black;
···
46
46
width: auto;
47
47
}
48
48
49
49
+
49
50
tree-node.one > node-content {
50
51
display: flex;
51
52
flex-direction: row;
···
79
80
80
81
tree-node.text {
81
82
display: inline-block;
82
82
-
background: lavender;
83
83
+
background: beige;
83
84
border: 2px solid purple;
84
85
border-radius: 10px;
85
86
padding: 1px 3px;
86
87
font-family: serif;
87
88
}
88
89
89
89
-
tree-node:not(tree-node *) > node-content {
90
90
+
/*tree-node:not(tree-node *) > node-content {
90
91
background: none;
91
91
-
}
92
92
+
}*/
-168
testing/tree.html
···
1
1
-
<!doctype html><html lang=en-QS><meta charset=utf-8>
2
2
-
<meta name=viewport content="width=device-width, initial-scale=1">
3
3
-
<title>Markup2 Tree Viewer</title>
4
4
-
5
5
-
<base href=..>
6
6
-
<script src=langs.js></script>
7
7
-
<script src=parse.js></script>
8
8
-
<script src=legacy.js></script>
9
9
-
<script src=render.js></script>
10
10
-
<script src=runtime.js></script>
11
11
-
<script src=helpers.js></script>
12
12
-
13
13
-
<link rel=stylesheet href=markup.css>
14
14
-
15
15
-
<script src=testing/tree.js></script>
16
16
-
<link rel=stylesheet href=testing/tree.css>
17
17
-
18
18
-
<style>
19
19
-
html { word-break: break-word; }
20
20
-
21
21
-
html, body {
22
22
-
position:fixed; top:0;left:0;right:0;bottom:0;
23
23
-
background: var(--T-bg, white);
24
24
-
}
25
25
-
26
26
-
html, select { font: var(--T-font); }
27
27
-
28
28
-
table.times, table.times td, table.times th {
29
29
-
border: 1px solid currentColor;
30
30
-
border-spacing: 0;
31
31
-
}
32
32
-
table.times td, table.times th {
33
33
-
padding: 2px 5px;
34
34
-
word-break: normal; overflow-wrap: break-word;
35
35
-
}
36
36
-
table.times th {
37
37
-
font-weight: bold;
38
38
-
color: white;
39
39
-
background: black;
40
40
-
}
41
41
-
table-overflow {
42
42
-
overflow-x: auto;
43
43
-
}
44
44
-
45
45
-
#\$output {
46
46
-
border: 3px solid black;
47
47
-
padding: 2px;
48
48
-
overflow-y: auto;
49
49
-
}
50
50
-
51
51
-
body {
52
52
-
display: flex; /* grid. rowheights: min-content auto, colwidths: 1fr 1fr on mobile, uh stack them liiike.. just do a normal block scrolling layout (should textarea/output ever scroll?) or maybe display one at a time? just have an options dropdown?*/
53
53
-
}
54
54
-
body > * {
55
55
-
width: 50%;
56
56
-
}
57
57
-
.Col { display: flex; flex-direction: column; }
58
58
-
.Col > * { flex-shrink: 0; }
59
59
-
.Col > .limit { flex-shrink: 1; min-height: 0; }
60
60
-
</style>
61
61
-
62
62
-
<input-pane class='Col'>
63
63
-
<select id=$lang>
64
64
-
<option> 12y2
65
65
-
<option> 12y
66
66
-
<option> bbcode
67
67
-
<option> plaintext
68
68
-
</select>
69
69
-
70
70
-
<textarea-container class='limit'>
71
71
-
<textarea id=$input></textarea>
72
72
-
</textarea-container>
73
73
-
</input-pane>
74
74
-
75
75
-
<output-pane class='Col'>
76
76
-
<table-overflow><table class=times>
77
77
-
<tr>
78
78
-
<th> <th> parse <th> render <th> layout <th> total
79
79
-
<tr>
80
80
-
<th> time (ms)
81
81
-
<td> <time id=$time1 datetime=Z></time>
82
82
-
<td> <time id=$time2 datetime=Z></time>
83
83
-
<td> <time id=$time3 datetime=Z></time>
84
84
-
<td> <time id=$time4 datetime=Z></time>
85
85
-
</table></table-overflow>
86
86
-
<span id=$count></span>
87
87
-
<div id=$output class='Markup limit'></div>
88
88
-
</output-pane>
89
89
-
90
90
-
<script>
91
91
-
let batch = (cb,w=0)=>e=>w++||requestAnimationFrame(_=>cb(e,w=0))
92
92
-
93
93
-
function show_time(elem, ms) {
94
94
-
elem.dateTime = (ms/1000).toFixed(4)+' s'
95
95
-
elem.textContent = ms.toFixed(1)
96
96
-
}
97
97
-
98
98
-
function update() {
99
99
-
//Markup.convert_lang($input.value, $lang.value, $output)
100
100
-
let t0 = performance.now()
101
101
-
let tree = Markup.langs.parse($input.value, $lang.value)
102
102
-
window.tree = tree
103
103
-
let t1 = performance.now()
104
104
-
$output.replaceChildren(draw_node(tree))
105
105
-
//$output.replaceChildren(Markup.renderer.render(tree))
106
106
-
let t2 = performance.now()
107
107
-
$output.scrollHeight
108
108
-
let t3 = performance.now()
109
109
-
show_time($time1, t1-t0)
110
110
-
show_time($time2, t2-t1)
111
111
-
show_time($time3, t3-t2)
112
112
-
show_time($time4, t3-t0)
113
113
-
}
114
114
-
115
115
-
$input.addEventListener('input', batch(update), {passive:true})
116
116
-
117
117
-
//$input.oninput = update
118
118
-
$lang.onchange = update
119
119
-
update()
120
120
-
</script>
121
121
-
122
122
-
123
123
-
<!-- textarea -->
124
124
-
125
125
-
<style>
126
126
-
textarea-container, textarea-container > textarea {
127
127
-
display: block;
128
128
-
box-sizing: content-box;
129
129
-
min-height: 5em;
130
130
-
height: 0;
131
131
-
font: 1em monospace;
132
132
-
}
133
133
-
134
134
-
textarea-container {
135
135
-
padding: 2px;
136
136
-
border: 2px solid #00C8B4;
137
137
-
border-radius: 2px;
138
138
-
}
139
139
-
140
140
-
textarea-container > textarea {
141
141
-
resize: none;
142
142
-
overflow-y: scroll;
143
143
-
margin: 0;
144
144
-
border: none;
145
145
-
padding: 0;
146
146
-
width: 100%;
147
147
-
148
148
-
appearance: none;
149
149
-
outline-offset: 2px;
150
150
-
}
151
151
-
</style>
152
152
-
153
153
-
<script>
154
154
-
{
155
155
-
let resize = (t)=>{
156
156
-
t.style.height = "0"
157
157
-
t.parentNode.style.height = `${t.scrollHeight+1}px`
158
158
-
t.style.height = "100%"
159
159
-
}
160
160
-
document.addEventListener('input', function(e) {
161
161
-
let t = e.target
162
162
-
if (t instanceof HTMLTextAreaElement && t.parentNode.tagName=='TEXTAREA-CONTAINER')
163
163
-
resize(t)
164
164
-
}, {passive: true})
165
165
-
for (let t of document.querySelectorAll("textarea-container > textarea"))
166
166
-
resize(t)
167
167
-
}
168
168
-
</script>
+2
-2
testing/tree.js
···
57
57
}.bind(𐀶`<tree-node class='text'>`),
58
58
}
59
59
60
60
-
function draw_node(node) {
60
60
+
function draw_tree(node) {
61
61
let elem = CREATE.node(node)
62
62
if (node.content)
63
63
for (let n of node.content)
64
64
-
elem.append(draw_node(n))
64
64
+
elem.append(draw_tree(n))
65
65
return elem.getRootNode()
66
66
}