-
Notifications
You must be signed in to change notification settings - Fork 77
Expand file tree
/
Copy pathRHS.ts
More file actions
94 lines (79 loc) · 2.64 KB
/
Copy pathRHS.ts
File metadata and controls
94 lines (79 loc) · 2.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import type Spec from './Spec';
import type Production from './Production';
import Builder from './Builder';
export default class RHS extends Builder {
/** @internal */ production: Production;
/** @internal */ constraints: string | null;
/** @internal */ alternativeId: string | null;
constructor(spec: Spec, prod: Production, node: HTMLElement) {
super(spec, node);
this.production = prod;
this.node = node;
this.constraints = node.getAttribute('constraints');
this.alternativeId = node.getAttribute('a');
}
build() {
if (this.node.textContent === '') {
this.node.textContent = '[empty]';
return;
}
if (this.constraints) {
const cs = this.spec.doc.createElement('emu-constraints');
cs.textContent = '[' + this.constraints + ']';
this.node.insertBefore(cs, this.node.childNodes[0]);
}
this.terminalify(this.node);
}
terminalify(parentNode: Element) {
// we store effects to perform later so the iteration doesn't get messed up
const surrogateTags = ['INS', 'DEL', 'MARK'];
const pairs: { parent: Element; child: Text }[] = [];
for (const node of parentNode.childNodes) {
if (node.nodeType === 3) {
pairs.push({ parent: parentNode, child: node as Text });
} else if (surrogateTags.includes(node.nodeName)) {
for (const child of node.childNodes) {
if (child.nodeType === 3) {
pairs.push({ parent: node as Element, child: child as Text });
}
}
}
}
let first = true;
for (const { parent, child } of pairs) {
if (!first && !/^\s+$/.test(child.textContent ?? '')) {
if (parent === parentNode) {
parentNode.insertBefore(this.spec.doc.createTextNode(' '), child);
} else {
// put the space outside of `<ins>` (etc) tags
parentNode.insertBefore(this.spec.doc.createTextNode(' '), parent);
}
}
first = false;
this.wrapTerminal(parent, child);
}
}
private wrapTerminal(parentNode: Element, node: Text) {
const textContent = node.textContent!;
const text = textContent.trim();
if (text === '' && textContent.length > 0) {
// preserve intermediate whitespace
return;
}
const pieces = text.split(/\s/);
let first = true;
pieces.forEach(p => {
if (p.length === 0) {
return;
}
const est = this.spec.doc.createElement('emu-t');
est.textContent = p;
parentNode.insertBefore(est, node);
if (!first) {
parentNode.insertBefore(this.spec.doc.createTextNode(' '), est);
}
first = false;
});
parentNode.removeChild(node);
}
}