@anyblock/any-block-core 3.4.6
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/ABAlias.ts +298 -0
- package/ABConvertEvent.ts +307 -0
- package/ABConvertManager.ts +266 -0
- package/ABSetting.ts +114 -0
- package/LICENSE +661 -0
- package/README.md +162 -0
- package/converter/ABConvert.ts +158 -0
- package/converter/GeneratorDataTable.ts +40 -0
- package/converter/abc_c2list.ts +497 -0
- package/converter/abc_code.ts +93 -0
- package/converter/abc_deco.ts +793 -0
- package/converter/abc_dir_tree.ts +467 -0
- package/converter/abc_echarts.ts +539 -0
- package/converter/abc_ex.ts +112 -0
- package/converter/abc_list.ts +650 -0
- package/converter/abc_markmap.ts +119 -0
- package/converter/abc_mdit_container.ts +161 -0
- package/converter/abc_mermaid.ts +343 -0
- package/converter/abc_plantuml.ts +109 -0
- package/converter/abc_plantuml_tools.ts +236 -0
- package/converter/abc_table.ts +242 -0
- package/converter/abc_text.ts +237 -0
- package/demo.ts +236 -0
- package/index.min.ts +26 -0
- package/index.ts +26 -0
- package/locales/en.ts +88 -0
- package/locales/helper.ts +27 -0
- package/locales/zh-cn.ts +88 -0
- package/package.json +22 -0
- package/setting.ts +0 -0
- package/style/styles.css +1218 -0
- package/style/styles.min.css +1 -0
- package/style/styles.scss +1244 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 转换器_目录树
|
|
3
|
+
*
|
|
4
|
+
* md_str <-> md_str
|
|
5
|
+
* md_str <-> html
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import DOMPurify from "dompurify"
|
|
9
|
+
import {ABConvert_IOEnum, ABConvert, type ABConvert_SpecSimp} from "./ABConvert"
|
|
10
|
+
import {ListProcess, type List_ListItem} from "./abc_list"
|
|
11
|
+
|
|
12
|
+
import plantumlEncoder from "plantuml-encoder"
|
|
13
|
+
|
|
14
|
+
import { list2ActivityDiagramText } from "./abc_plantuml_tools"
|
|
15
|
+
|
|
16
|
+
const _abc_list2jsontext = ABConvert.factory({
|
|
17
|
+
id: "json2pumlJson",
|
|
18
|
+
name: "json到可视化",
|
|
19
|
+
process_param: ABConvert_IOEnum.text,
|
|
20
|
+
process_return: ABConvert_IOEnum.el,
|
|
21
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
22
|
+
content = "@startjson\n" + content + "\n@endjson\n"
|
|
23
|
+
render_pumlText(content, el)
|
|
24
|
+
return el
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const _abc_list2pumlWBS = ABConvert.factory({
|
|
29
|
+
id: "list2pumlWBS",
|
|
30
|
+
name: "列表到puml工作分解结构",
|
|
31
|
+
process_param: ABConvert_IOEnum.text,
|
|
32
|
+
process_return: ABConvert_IOEnum.el,
|
|
33
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
34
|
+
let listdata:List_ListItem = ListProcess.list2data(content)
|
|
35
|
+
listdata = ListProcess.data2strict(listdata)
|
|
36
|
+
let newContent = "@startwbs\n"
|
|
37
|
+
for (let item of listdata) {
|
|
38
|
+
if (item.content.startsWith("< "))
|
|
39
|
+
newContent += "*".repeat(item.level+1) + "< " + item.content.slice(2,) + "\n"
|
|
40
|
+
else
|
|
41
|
+
newContent += "*".repeat(item.level+1) + " " + item.content + "\n"
|
|
42
|
+
}
|
|
43
|
+
newContent += "@endwbs"
|
|
44
|
+
|
|
45
|
+
render_pumlText(newContent, el)
|
|
46
|
+
return el
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const _abc_list2pumlMindmap = ABConvert.factory({
|
|
51
|
+
id: "list2pumlMindmap",
|
|
52
|
+
name: "列表到puml思维导图",
|
|
53
|
+
process_param: ABConvert_IOEnum.text,
|
|
54
|
+
process_return: ABConvert_IOEnum.el,
|
|
55
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
56
|
+
let listdata:List_ListItem = ListProcess.list2data(content)
|
|
57
|
+
listdata = ListProcess.data2strict(listdata)
|
|
58
|
+
let newContent = "@startmindmap\n"
|
|
59
|
+
for (let item of listdata) {
|
|
60
|
+
newContent += "*".repeat(item.level+1) + " " + item.content + "\n"
|
|
61
|
+
}
|
|
62
|
+
newContent += "@endmindmap"
|
|
63
|
+
|
|
64
|
+
render_pumlText(newContent, el)
|
|
65
|
+
return el
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const _abc_list2ActivityDiagramText = ABConvert.factory({
|
|
70
|
+
id: "list2pumlActivityDiagramText",
|
|
71
|
+
name: "列表到puml活动图文本",
|
|
72
|
+
process_param: ABConvert_IOEnum.text,
|
|
73
|
+
process_return: ABConvert_IOEnum.text,
|
|
74
|
+
process: (el, header, content: string): string => {
|
|
75
|
+
return list2ActivityDiagramText(ListProcess.data2strict(ListProcess.list2data(content)))
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const _abc_list2ActivityDiagram = ABConvert.factory({
|
|
80
|
+
id: "list2pumlActivityDiagram",
|
|
81
|
+
name: "列表到puml活动图",
|
|
82
|
+
process_param: ABConvert_IOEnum.text,
|
|
83
|
+
process_return: ABConvert_IOEnum.el,
|
|
84
|
+
process: (el, header, content: string): HTMLElement => {
|
|
85
|
+
const puml = list2ActivityDiagramText(ListProcess.data2strict(ListProcess.list2data(content)))
|
|
86
|
+
render_pumlText(puml, el)
|
|
87
|
+
return el
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
export async function render_pumlText(text: string, div: HTMLElement) {
|
|
92
|
+
// 1. 四选一。自己渲 (优缺点见abc_mermaid的相似方法)
|
|
93
|
+
// 当前mdit和ob使用
|
|
94
|
+
var encoded = plantumlEncoder.encode(text)
|
|
95
|
+
let url = 'http://www.plantuml.com/plantuml/img/' + encoded
|
|
96
|
+
div.innerHTML = DOMPurify.sanitize(`<img src="${url}">`)
|
|
97
|
+
|
|
98
|
+
// 2. 四选一。这里给环境渲染 (优缺点见abc_mermaid的相似方法)
|
|
99
|
+
//ABConvertManager.getInstance().m_renderMarkdownFn("```plantuml\n"+text+"```", div)
|
|
100
|
+
|
|
101
|
+
// 3. 四选一。这里不渲,交给上一层让上一层渲 (优缺点见abc_mermaid的相似方法)
|
|
102
|
+
//div.classList.add("ab-raw")
|
|
103
|
+
//div.innerHTML = DOMPurify.sanitize(`<div class="ab-raw-data" type-data="plantuml" content-data='${text}'></div>`)
|
|
104
|
+
|
|
105
|
+
// 4. 四选一。纯动态/手动渲染 (优缺点见abc_mermaid的相似方法)
|
|
106
|
+
// ...
|
|
107
|
+
|
|
108
|
+
return div
|
|
109
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import type { List_ListItem } from "./abc_list"
|
|
2
|
+
|
|
3
|
+
// start flag
|
|
4
|
+
const KEYWORD_IF = "if "
|
|
5
|
+
const KEYWORD_SWITCH = "switch "
|
|
6
|
+
const KEYWORD_SWITCH2 = "match " // python use `match, case, case _` instead of `switch, case, default`
|
|
7
|
+
const KEYWORD_WHILE = "while "
|
|
8
|
+
const KEYWORD_GROUP = "group "
|
|
9
|
+
const KEYWORD_PARTITION = "partition "
|
|
10
|
+
const KEYWORD_LANE = "lane "
|
|
11
|
+
// middle/end flag
|
|
12
|
+
const KEYWORD_ELIF = "elif "
|
|
13
|
+
const KEYWORD_ELSEIF = "else if "
|
|
14
|
+
const KEYWORD_ELSE = "else"
|
|
15
|
+
const KEYWORD_DEFAULT = "default"
|
|
16
|
+
const KEYWORD_DEFAULT2 = "case _" // python use `match, case, case _` instead of `switch, case, default`
|
|
17
|
+
const KEYWORD_CASE = "case "
|
|
18
|
+
// other flag
|
|
19
|
+
const BLOCK_START = ":"
|
|
20
|
+
const INDENT = " ";
|
|
21
|
+
|
|
22
|
+
class Stat {
|
|
23
|
+
content: string;
|
|
24
|
+
level: number;
|
|
25
|
+
constructor(content: string, level: number) {
|
|
26
|
+
this.content = content.trim();
|
|
27
|
+
this.level = level;
|
|
28
|
+
}
|
|
29
|
+
// 判断是否为保留字
|
|
30
|
+
isReservedWord(): boolean {
|
|
31
|
+
return this.content === "start" || this.content === "stop" || this.content === "kill" ||
|
|
32
|
+
this.content === "detach" || this.content === "break" || this.content === "end" ||
|
|
33
|
+
this.content === "fork" || this.content === "fork again" || this.content === "end fork" ||
|
|
34
|
+
this.content === "end merge";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
isStatementOfType(...stateType: string[]): boolean {
|
|
38
|
+
return stateType.some(type => this.content.startsWith(type)) && this.content.endsWith(BLOCK_START);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
takeTagOfStat(type: string): string {
|
|
42
|
+
const condition = this.content.substring(type.length, this.content.length - BLOCK_START.length).trim();
|
|
43
|
+
return condition;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type ProcessResult = {
|
|
48
|
+
result: string,
|
|
49
|
+
nextIndex: number
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const statementTypes = {
|
|
53
|
+
[KEYWORD_IF]: processIfStatement,
|
|
54
|
+
[KEYWORD_SWITCH]: processSwitchStatement,
|
|
55
|
+
[KEYWORD_SWITCH2]: processSwitchStatement,
|
|
56
|
+
[KEYWORD_WHILE]: processWhileStatement,
|
|
57
|
+
[KEYWORD_GROUP]: processGroupStatement,
|
|
58
|
+
[KEYWORD_PARTITION]: processPartitionStatement,
|
|
59
|
+
[KEYWORD_LANE]: processSwimLane
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Process main content, recursively process all items
|
|
63
|
+
function processBlock(stats: Stat[], index: number, parentLevel: number): ProcessResult {
|
|
64
|
+
let result = "";
|
|
65
|
+
let next = index;
|
|
66
|
+
while (next < stats.length && (parentLevel === -1 || stats[next].level > parentLevel)) {
|
|
67
|
+
const stat = stats[next];
|
|
68
|
+
|
|
69
|
+
if (stat.isReservedWord()) {
|
|
70
|
+
result += stat.content + "\n";
|
|
71
|
+
next++;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let processed = false;
|
|
76
|
+
for (const [statType, processor] of Object.entries(statementTypes)) {
|
|
77
|
+
if (stat.isStatementOfType(statType)) {
|
|
78
|
+
const { result: processedResult, nextIndex: nextNext } = processor(stats, next, statType);
|
|
79
|
+
result += processedResult;
|
|
80
|
+
next = nextNext;
|
|
81
|
+
processed = true;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (processed) continue;
|
|
87
|
+
|
|
88
|
+
if (stat.content.length > 0) {
|
|
89
|
+
result += `:${stat.content};` + "\n";
|
|
90
|
+
}
|
|
91
|
+
next++;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { result, nextIndex: next }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 处理if语句
|
|
98
|
+
function processIfStatement(stats: Stat[], index: number): { result: string, nextIndex: number } {
|
|
99
|
+
let result = KEYWORD_IF;
|
|
100
|
+
const stat = stats[index];
|
|
101
|
+
const condition = stat.takeTagOfStat(KEYWORD_IF);
|
|
102
|
+
let nextIndex = index + 1;
|
|
103
|
+
|
|
104
|
+
// if body
|
|
105
|
+
if (nextIndex < stats.length && stats[nextIndex].level > stat.level) {
|
|
106
|
+
result += `(${condition}) then (yes)\n`;
|
|
107
|
+
const { result: result2, nextIndex: nextIndex2 } = processBlock(stats, nextIndex, stat.level);
|
|
108
|
+
result += indentContent(result2);
|
|
109
|
+
nextIndex = nextIndex2;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Process else and else if branches
|
|
113
|
+
while (nextIndex < stats.length && stats[nextIndex].level === stat.level && stats[nextIndex].isStatementOfType(KEYWORD_ELIF, KEYWORD_ELSEIF, KEYWORD_ELSE)) {
|
|
114
|
+
const branch = stats[nextIndex];
|
|
115
|
+
if (branch.isStatementOfType(KEYWORD_ELSEIF)) { // KEYWORD_ELSEIF must be ahead of ELSE
|
|
116
|
+
const condition = branch.takeTagOfStat(KEYWORD_ELSEIF);
|
|
117
|
+
result += `else if(${condition}) then (yes)\n`;
|
|
118
|
+
} else if (branch.isStatementOfType(KEYWORD_ELIF)) {
|
|
119
|
+
const condition = branch.takeTagOfStat(KEYWORD_ELIF);
|
|
120
|
+
result += `else if(${condition}) then (yes)\n`;
|
|
121
|
+
} else if (branch.isStatementOfType(KEYWORD_ELSE)) {
|
|
122
|
+
result += `else (else)\n`;
|
|
123
|
+
}
|
|
124
|
+
const { result: result2, nextIndex: nextIndex2 } = processBlock(stats, nextIndex + 1, stat.level);
|
|
125
|
+
result += indentContent(result2);
|
|
126
|
+
nextIndex = nextIndex2;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
result += "endif\n";
|
|
130
|
+
return { result, nextIndex };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 处理switch语句
|
|
134
|
+
function processSwitchStatement(stats: Stat[], index: number, statType: string): { result: string, nextIndex: number } {
|
|
135
|
+
let result = `switch `;
|
|
136
|
+
const stat = stats[index];
|
|
137
|
+
const condition = stat.takeTagOfStat(statType);
|
|
138
|
+
let nextIndex = index + 1;
|
|
139
|
+
|
|
140
|
+
result += `(${condition})\n`;
|
|
141
|
+
|
|
142
|
+
let hasDefault = false;
|
|
143
|
+
// Process case/default statements
|
|
144
|
+
while (nextIndex < stats.length && stats[nextIndex].level >= stat.level && stats[nextIndex].isStatementOfType(KEYWORD_CASE, KEYWORD_DEFAULT)) {
|
|
145
|
+
const nextStat = stats[nextIndex];
|
|
146
|
+
nextIndex++;
|
|
147
|
+
if (nextStat.isStatementOfType(KEYWORD_DEFAULT) || nextStat.isStatementOfType(KEYWORD_DEFAULT2)) { // KEYWORD_DEFAULT2 must be ahead of KEYWORD_CASE
|
|
148
|
+
result += `case (default)\n`;
|
|
149
|
+
hasDefault = true;
|
|
150
|
+
const { result: defaultResult, nextIndex: defaultNextIndex } = processBlock(stats, nextIndex, nextStat.level);
|
|
151
|
+
result += indentContent(defaultResult);
|
|
152
|
+
nextIndex = defaultNextIndex;
|
|
153
|
+
} else if (nextStat.isStatementOfType(KEYWORD_CASE)) {
|
|
154
|
+
const caseTag = nextStat.takeTagOfStat(KEYWORD_CASE);
|
|
155
|
+
result += `case (${caseTag})\n`;
|
|
156
|
+
const { result: caseResult, nextIndex: caseNextIndex } = processBlock(stats, nextIndex, nextStat.level);
|
|
157
|
+
result += indentContent(caseResult);
|
|
158
|
+
nextIndex = caseNextIndex;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (!hasDefault) {
|
|
162
|
+
result += "case (default)\n";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
result += "endswitch\n";
|
|
166
|
+
return { result, nextIndex };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// 处理while语句
|
|
170
|
+
function processWhileStatement(stats: Stat[], index: number): { result: string, nextIndex: number } {
|
|
171
|
+
const stat = stats[index];
|
|
172
|
+
const condition = stat.takeTagOfStat(KEYWORD_WHILE);
|
|
173
|
+
let result = `${KEYWORD_WHILE}(${condition}) is (true)\n`;
|
|
174
|
+
let nextIndex = index + 1;
|
|
175
|
+
|
|
176
|
+
// Process while body
|
|
177
|
+
const { result: bodyResult, nextIndex: bodyNextIndex } = processBlock(stats, nextIndex, stat.level);
|
|
178
|
+
result += indentContent(bodyResult);
|
|
179
|
+
nextIndex = bodyNextIndex;
|
|
180
|
+
|
|
181
|
+
result += "endwhile\n";
|
|
182
|
+
return { result, nextIndex };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 处理group语句
|
|
186
|
+
function processGroupStatement(stats: Stat[], index: number): { result: string, nextIndex: number } {
|
|
187
|
+
const stat = stats[index];
|
|
188
|
+
const groupName = stat.takeTagOfStat(KEYWORD_GROUP);
|
|
189
|
+
let result = `${KEYWORD_GROUP}${groupName}\n`;
|
|
190
|
+
let nextIndex = index + 1;
|
|
191
|
+
|
|
192
|
+
// Process group body
|
|
193
|
+
const { result: bodyResult, nextIndex: bodyNextIndex } = processBlock(stats, nextIndex, stat.level);
|
|
194
|
+
result += indentContent(bodyResult);
|
|
195
|
+
nextIndex = bodyNextIndex;
|
|
196
|
+
|
|
197
|
+
result += "endgroup\n";
|
|
198
|
+
return { result, nextIndex };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// 处理partition语句
|
|
202
|
+
function processPartitionStatement(stats: Stat[], index: number): { result: string, nextIndex: number } {
|
|
203
|
+
const stat = stats[index];
|
|
204
|
+
const partitionName = stat.takeTagOfStat(KEYWORD_PARTITION);
|
|
205
|
+
let result = `${KEYWORD_PARTITION}${partitionName} {\n`;
|
|
206
|
+
let nextIndex = index + 1;
|
|
207
|
+
|
|
208
|
+
// Process partition body
|
|
209
|
+
const { result: bodyResult, nextIndex: bodyNextIndex } = processBlock(stats, nextIndex, stat.level);
|
|
210
|
+
result += indentContent(bodyResult);
|
|
211
|
+
nextIndex = bodyNextIndex;
|
|
212
|
+
|
|
213
|
+
result += "}\n";
|
|
214
|
+
return { result, nextIndex };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// 处理swim lane
|
|
218
|
+
function processSwimLane(stats: Stat[], index: number): { result: string, nextIndex: number } {
|
|
219
|
+
const stat = stats[index];
|
|
220
|
+
const laneName = stat.takeTagOfStat(KEYWORD_LANE);
|
|
221
|
+
return { result: "|" + laneName + "|\n", nextIndex: index + 1 };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// 为内容添加缩进
|
|
225
|
+
function indentContent(content: string): string {
|
|
226
|
+
return content.split('\n').filter(x => x !== '').map(line => INDENT + line).join('\n') + "\n";
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function list2ActivityDiagramText(listdata: List_ListItem): string {
|
|
230
|
+
let result = "@startuml\n";
|
|
231
|
+
const stats = listdata.map(item => new Stat(item.content.trim(), item.level));
|
|
232
|
+
const { result: bodyResult } = processBlock(stats, 0, -1);
|
|
233
|
+
result += bodyResult;
|
|
234
|
+
result += "@enduml";
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 处理器_表格版
|
|
3
|
+
*
|
|
4
|
+
* - md_str <-> 表格数据
|
|
5
|
+
* - 表格数据 <-> html
|
|
6
|
+
* - 列表数据 -> 表格数据
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ABReg } from '../ABSetting'
|
|
10
|
+
import {ABConvert_IOEnum, ABConvert, type ABConvert_SpecSimp} from "./ABConvert"
|
|
11
|
+
import {ABConvertManager} from "../ABConvertManager"
|
|
12
|
+
import { type ListItem, type List_ListItem, ListProcess, abc_title2listdata, abc_list2listdata } from "./abc_list"
|
|
13
|
+
import { type C2ListItem, type List_C2ListItem, C2ListProcess } from "./abc_c2list"
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 通用表格数据,一个元素等于是一个单元格项 (th/td)
|
|
17
|
+
*
|
|
18
|
+
* 例如:
|
|
19
|
+
* - a1
|
|
20
|
+
* - a2
|
|
21
|
+
* - a3
|
|
22
|
+
* - b2
|
|
23
|
+
* - b3
|
|
24
|
+
* to
|
|
25
|
+
* |a1|a2|a3|
|
|
26
|
+
* |^ |b2|b3|
|
|
27
|
+
* with
|
|
28
|
+
* {
|
|
29
|
+
* // 前两列是ListItem来的东西
|
|
30
|
+
* // 第2列是用来算第3列的,将第3列算出来后,即数据分析完后,第2列就没有用了
|
|
31
|
+
* {a1, 无用, 2, 1},
|
|
32
|
+
* {a2, 无用, 1, 1},
|
|
33
|
+
* {a3, 无用, 1, 1},
|
|
34
|
+
* {b2, 无用, 1, 2},
|
|
35
|
+
* {b3, 无用, 1, 2},
|
|
36
|
+
* }
|
|
37
|
+
*/
|
|
38
|
+
export interface TableItem extends ListItem{
|
|
39
|
+
tableRowSpan: number, // 跨行数
|
|
40
|
+
//tableColumnSpan: number, // 跨列数
|
|
41
|
+
tableRow: number, // 对应首行序列
|
|
42
|
+
//tableColum: number, // 对应首列序列
|
|
43
|
+
}
|
|
44
|
+
export type List_TableItem = TableItem[]
|
|
45
|
+
|
|
46
|
+
/// 一些表格相关的工具集
|
|
47
|
+
export class TableProcess{
|
|
48
|
+
|
|
49
|
+
/** 列表转二维表格 */
|
|
50
|
+
static list2ut(text: string, div: HTMLDivElement, modeT=false) {
|
|
51
|
+
//【old】
|
|
52
|
+
/*let list_itemInfo = ListProcess.old_ulist2data(text)
|
|
53
|
+
return TableProcess.data2table(list_itemInfo, div)*/
|
|
54
|
+
//【new】
|
|
55
|
+
let data = ListProcess.list2data(text)
|
|
56
|
+
data = ListProcess.data2strict(data)
|
|
57
|
+
data = C2ListProcess.data_mL_2_2L(data)
|
|
58
|
+
data = ListProcess.data_2L_2_mL1B(data)
|
|
59
|
+
return TableProcess.data2table(data, div, modeT)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** 列表转时间线 */
|
|
63
|
+
static list2timeline(text: string, div: HTMLDivElement, modeT=false) {
|
|
64
|
+
let data = C2ListProcess.list2c2data(text)
|
|
65
|
+
div = TableProcess.data2table(data, div, modeT)
|
|
66
|
+
const table = div.querySelector("table")
|
|
67
|
+
if (table) table.classList.add("ab-table-timeline", "ab-table-fc")
|
|
68
|
+
return div
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** 标题转时间线 */
|
|
72
|
+
static title2timeline(text: string, div: HTMLDivElement, modeT=false) {
|
|
73
|
+
let data = C2ListProcess.title2c2data(text)
|
|
74
|
+
div = TableProcess.data2table(data, div, modeT)
|
|
75
|
+
const table = div.querySelector("table")
|
|
76
|
+
if (table) table.classList.add("ab-table-timeline", "ab-table-fc")
|
|
77
|
+
return div
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** 列表数据转表格 */
|
|
81
|
+
static data2table(
|
|
82
|
+
list_itemInfo: List_ListItem,
|
|
83
|
+
div: HTMLDivElement,
|
|
84
|
+
modeT: boolean // 是否转置
|
|
85
|
+
){
|
|
86
|
+
// 组装成表格数据 (列表是深度优先)
|
|
87
|
+
let list_tableInfo:List_TableItem = []
|
|
88
|
+
let prev_line = -1 // 并存储后一行的序列!
|
|
89
|
+
let prev_level = 999 // 上一行的等级
|
|
90
|
+
for (let i=0; i<list_itemInfo.length; i++){
|
|
91
|
+
let item = list_itemInfo[i]
|
|
92
|
+
|
|
93
|
+
// 获取跨行数
|
|
94
|
+
let tableRow = 1
|
|
95
|
+
let row_level = list_itemInfo[i].level
|
|
96
|
+
for (let j=i+1; j<list_itemInfo.length; j++) {
|
|
97
|
+
if (list_itemInfo[j].level > row_level){ // 在右侧,不换行
|
|
98
|
+
row_level = list_itemInfo[j].level
|
|
99
|
+
}
|
|
100
|
+
else if (list_itemInfo[j].level > list_itemInfo[i].level){// 换行但是不换item项的行
|
|
101
|
+
row_level = list_itemInfo[j].level
|
|
102
|
+
tableRow++
|
|
103
|
+
}
|
|
104
|
+
else break // 换item项的行
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 获取所在行数。分换行(创建新行)和不换行,第一行总是创建新行
|
|
108
|
+
// 这里的if表示该换行了
|
|
109
|
+
if (item.level <= prev_level) {
|
|
110
|
+
prev_line++
|
|
111
|
+
}
|
|
112
|
+
prev_level = item.level
|
|
113
|
+
|
|
114
|
+
// 填写
|
|
115
|
+
list_tableInfo.push({
|
|
116
|
+
content: item.content, // 内容
|
|
117
|
+
level: item.level, // 级别
|
|
118
|
+
tableRowSpan: tableRow, // 跨行数
|
|
119
|
+
tableRow: prev_line // 对应首行序列
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// GeneratorBranchTable,原来是svelte
|
|
124
|
+
{
|
|
125
|
+
// 表格数据 组装成表格
|
|
126
|
+
const table = document.createElement("table"); div.appendChild(table); table.classList.add("ab-table", "ab-branch-table")
|
|
127
|
+
if (modeT) table.setAttribute("modeT", "true")
|
|
128
|
+
let thead
|
|
129
|
+
if(list_tableInfo[0].content.indexOf("< ")==0){ // 判断是否有表头
|
|
130
|
+
thead = document.createElement("thead"); table.appendChild(thead);
|
|
131
|
+
list_tableInfo[0].content=list_tableInfo[0].content.replace(/^\<\s/,"")
|
|
132
|
+
}
|
|
133
|
+
const tbody = document.createElement("tbody"); table.appendChild(tbody);
|
|
134
|
+
for (let index_line=0; index_line<prev_line+1; index_line++){ // 遍历表格行,创建tr……
|
|
135
|
+
let is_head
|
|
136
|
+
let tr
|
|
137
|
+
if (index_line==0 && thead){ // 判断是否第一行&&是否有表头
|
|
138
|
+
tr = document.createElement("tr"); thead.appendChild(tr);
|
|
139
|
+
is_head = true
|
|
140
|
+
}
|
|
141
|
+
else{
|
|
142
|
+
is_head = false
|
|
143
|
+
tr = document.createElement("tr"); tbody.appendChild(tr);
|
|
144
|
+
}
|
|
145
|
+
for (let item of list_tableInfo){ // 遍历表格列,创建td
|
|
146
|
+
if (item.tableRow!=index_line) continue
|
|
147
|
+
let td = document.createElement(is_head?"th":"td"); tr.appendChild(td);
|
|
148
|
+
td.setAttribute("rowspan", item.tableRowSpan.toString()); td.setAttribute("col_index", item.level.toString())
|
|
149
|
+
ABConvertManager.getInstance().m_renderMarkdownFn(item.content, td)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return div
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 纯组合,后续用别名模块替代
|
|
159
|
+
const _abc_title2table = ABConvert.factory({
|
|
160
|
+
id: "title2table",
|
|
161
|
+
name: "标题到表格",
|
|
162
|
+
process_param: ABConvert_IOEnum.text,
|
|
163
|
+
process_return: ABConvert_IOEnum.el,
|
|
164
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
165
|
+
const data: List_ListItem = abc_title2listdata.process(el, header, content) as List_ListItem
|
|
166
|
+
return el = TableProcess.data2table(data, el, false) as HTMLDivElement
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
// 纯组合,后续用别名模块替代
|
|
171
|
+
const _abc_list2table = ABConvert.factory({
|
|
172
|
+
id: "list2table",
|
|
173
|
+
name: "列表转表格",
|
|
174
|
+
match: /list2(md)?table(T)?/,
|
|
175
|
+
default: "list2table",
|
|
176
|
+
process_param: ABConvert_IOEnum.text,
|
|
177
|
+
process_return: ABConvert_IOEnum.el,
|
|
178
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
179
|
+
const matchs = header.match(/list2(md)?table(T)?/)
|
|
180
|
+
if (!matchs) return el
|
|
181
|
+
const data: List_ListItem = abc_list2listdata.process(el, header, content) as List_ListItem
|
|
182
|
+
return el = TableProcess.data2table(data, el, matchs[2]=="T") as HTMLDivElement
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
const _abc_list2c2table = ABConvert.factory({
|
|
187
|
+
id: "list2c2t",
|
|
188
|
+
name: "列表转二列表格",
|
|
189
|
+
match: "list2c2t",
|
|
190
|
+
process_param: ABConvert_IOEnum.text,
|
|
191
|
+
process_return: ABConvert_IOEnum.el,
|
|
192
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
193
|
+
let data = C2ListProcess.list2c2data(content)
|
|
194
|
+
TableProcess.data2table(data, el, false)
|
|
195
|
+
return el
|
|
196
|
+
}
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
const _abc_list2ut = ABConvert.factory({
|
|
200
|
+
id: "list2ut",
|
|
201
|
+
name: "列表转二维表格",
|
|
202
|
+
match: /list2(md)?ut(T)?/,
|
|
203
|
+
default: "list2ut",
|
|
204
|
+
process_param: ABConvert_IOEnum.text,
|
|
205
|
+
process_return: ABConvert_IOEnum.el,
|
|
206
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
207
|
+
const matchs = header.match(/list2(md)?ut(T)?/)
|
|
208
|
+
if (!matchs) return el
|
|
209
|
+
TableProcess.list2ut(content, el, matchs[2]=="T")
|
|
210
|
+
return el
|
|
211
|
+
}
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
const _abc_list2timeline = ABConvert.factory({
|
|
215
|
+
id: "list2timeline",
|
|
216
|
+
name: "列表转时间线",
|
|
217
|
+
match: /list2(md)?timeline(T)?/,
|
|
218
|
+
default: "list2mdtimeline",
|
|
219
|
+
process_param: ABConvert_IOEnum.text,
|
|
220
|
+
process_return: ABConvert_IOEnum.el,
|
|
221
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
222
|
+
const matchs = header.match(/list2(md)?timeline(T)?/)
|
|
223
|
+
if (!matchs) return el
|
|
224
|
+
TableProcess.list2timeline(content, el, matchs[2]=="T")
|
|
225
|
+
return el
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
const _abc_title2timeline = ABConvert.factory({
|
|
230
|
+
id: "title2timeline",
|
|
231
|
+
name: "标题转时间线",
|
|
232
|
+
match: /title2(md)?timeline(T)?/,
|
|
233
|
+
default: "title2mdtimeline",
|
|
234
|
+
process_param: ABConvert_IOEnum.text,
|
|
235
|
+
process_return: ABConvert_IOEnum.el,
|
|
236
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
237
|
+
const matchs = header.match(/title2(md)?timeline(T)?/)
|
|
238
|
+
if (!matchs) return el
|
|
239
|
+
TableProcess.title2timeline(content, el, matchs[2]=="T")
|
|
240
|
+
return el
|
|
241
|
+
}
|
|
242
|
+
})
|