Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/infrastructure/markup/blockrule/PhutilRemarkupTableBlockRule.php
12241 views
1
<?php
2
3
final class PhutilRemarkupTableBlockRule extends PhutilRemarkupBlockRule {
4
5
public function getMatchingLineCount(array $lines, $cursor) {
6
$num_lines = 0;
7
8
if (preg_match('/^\s*<table>/i', $lines[$cursor])) {
9
$num_lines++;
10
$cursor++;
11
12
while (isset($lines[$cursor])) {
13
$num_lines++;
14
if (preg_match('@</table>\s*$@i', $lines[$cursor])) {
15
break;
16
}
17
$cursor++;
18
}
19
}
20
21
return $num_lines;
22
}
23
24
public function markupText($text, $children) {
25
$root = id(new PhutilHTMLParser())
26
->parseDocument($text);
27
28
$nodes = $root->selectChildrenWithTags(array('table'));
29
30
$out = array();
31
$seen_table = false;
32
foreach ($nodes as $node) {
33
if ($node->isContentNode()) {
34
$content = $node->getContent();
35
36
if (!strlen(trim($content))) {
37
// Ignore whitespace.
38
continue;
39
}
40
41
// If we find other content, fail the rule. This can happen if the
42
// input is two consecutive table tags on one line with some text
43
// in between them, which we currently forbid.
44
return $text;
45
} else {
46
// If we have multiple table tags, just return the raw text.
47
if ($seen_table) {
48
return $text;
49
}
50
$seen_table = true;
51
52
$out[] = $this->newTable($node);
53
}
54
}
55
56
if ($this->getEngine()->isTextMode()) {
57
return implode('', $out);
58
} else {
59
return phutil_implode_html('', $out);
60
}
61
}
62
63
private function newTable(PhutilDOMNode $table) {
64
$nodes = $table->selectChildrenWithTags(
65
array(
66
'colgroup',
67
'tr',
68
));
69
70
$colgroup = null;
71
$rows = array();
72
73
foreach ($nodes as $node) {
74
if ($node->isContentNode()) {
75
$content = $node->getContent();
76
77
// If this is whitespace, ignore it.
78
if (!strlen(trim($content))) {
79
continue;
80
}
81
82
// If we have nonempty content between the rows, this isn't a valid
83
// table. We can't really do anything reasonable with this, so just
84
// fail out and render the raw text.
85
return $table->newRawString();
86
}
87
88
if ($node->getTagName() === 'colgroup') {
89
// This table has multiple "<colgroup />" tags. Just bail out.
90
if ($colgroup !== null) {
91
return $table->newRawString();
92
}
93
94
// This table has a "<colgroup />" after a "<tr />". We could parse
95
// this, but just reject it out of an abundance of caution.
96
if ($rows) {
97
return $table->newRawString();
98
}
99
100
$colgroup = $node;
101
continue;
102
}
103
104
$rows[] = $node;
105
}
106
107
$row_specs = array();
108
109
foreach ($rows as $row) {
110
$cells = $row->selectChildrenWithTags(array('td', 'th'));
111
112
$cell_specs = array();
113
foreach ($cells as $cell) {
114
if ($cell->isContentNode()) {
115
$content = $node->getContent();
116
117
if ($content === null || !strlen(trim($content))) {
118
continue;
119
}
120
121
return $table->newRawString();
122
}
123
124
// Respect newlines in table cells as literal linebreaks.
125
126
$content = $cell->newRawContentString();
127
$content = trim($content, "\r\n");
128
129
$lines = phutil_split_lines($content, $retain_endings = false);
130
foreach ($lines as $key => $line) {
131
$lines[$key] = $this->applyRules($line);
132
}
133
134
$content = phutil_implode_html(
135
phutil_tag('br'),
136
$lines);
137
138
$cell_specs[] = array(
139
'type' => $cell->getTagName(),
140
'content' => $content,
141
);
142
}
143
144
$row_specs[] = array(
145
'type' => 'tr',
146
'content' => $cell_specs,
147
);
148
}
149
150
return $this->renderRemarkupTable($row_specs);
151
}
152
153
}
154
155