@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,793 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 处理器_装饰版
|
|
3
|
+
*
|
|
4
|
+
* html <-> html
|
|
5
|
+
* md_str <-> html
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import DOMPurify from "dompurify"
|
|
9
|
+
import { ABConvert_IOEnum, ABConvert } from "./ABConvert"
|
|
10
|
+
import { ABConvertManager } from "../ABConvertManager"
|
|
11
|
+
import { ABCSetting } from "../ABSetting"
|
|
12
|
+
|
|
13
|
+
export const DECOProcessor = 0 // 用于模块化,防报错,其实没啥用
|
|
14
|
+
|
|
15
|
+
const _abc_md = ABConvert.factory({
|
|
16
|
+
id: "md",
|
|
17
|
+
name: "md",
|
|
18
|
+
process_param: ABConvert_IOEnum.text,
|
|
19
|
+
process_return: ABConvert_IOEnum.el,
|
|
20
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
21
|
+
const subEl = document.createElement("div"); el.appendChild(subEl);
|
|
22
|
+
ABConvertManager.getInstance().m_renderMarkdownFn(content, subEl)
|
|
23
|
+
return el
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const _abc_text = ABConvert.factory({
|
|
28
|
+
id: "text",
|
|
29
|
+
name: "纯文本",
|
|
30
|
+
detail: "其实一般会更推荐用code()代替,那个更精确",
|
|
31
|
+
process_param: ABConvert_IOEnum.text,
|
|
32
|
+
process_return: ABConvert_IOEnum.el,
|
|
33
|
+
process: (el, header, content: string): HTMLElement=>{
|
|
34
|
+
// 文本元素。pre不好用,这里还是得用<br>换行最好
|
|
35
|
+
// `<p>${content.split("\n").map(line=>{return "<span>"+line+"</span>"}).join("<br/>")}</p>`
|
|
36
|
+
el.innerHTML = DOMPurify.sanitize(`<p>${content.replace(/ /g, " ").split("\n").join("<br/>")}</p>`)
|
|
37
|
+
return el
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const _abc_fold = ABConvert.factory({
|
|
42
|
+
id: "fold",
|
|
43
|
+
name: "折叠",
|
|
44
|
+
process_param: ABConvert_IOEnum.el,
|
|
45
|
+
process_return: ABConvert_IOEnum.el,
|
|
46
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{
|
|
47
|
+
if(content.children.length!=1) return content
|
|
48
|
+
const sub_el = content.children[0] as HTMLElement
|
|
49
|
+
sub_el.remove()
|
|
50
|
+
sub_el.setAttribute("is_hide", "true")
|
|
51
|
+
sub_el.classList.add("ab-deco-fold-content")
|
|
52
|
+
sub_el.style.display = "none"
|
|
53
|
+
const mid_el = document.createElement("div"); content.appendChild(mid_el); mid_el.classList.add("ab-deco-fold");
|
|
54
|
+
const sub_button = document.createElement("div"); mid_el.appendChild(sub_button); sub_button.classList.add("ab-deco-fold-button"); sub_button.textContent = "展开";
|
|
55
|
+
const fn_fold = ()=>{
|
|
56
|
+
const is_hide = sub_el.getAttribute("is_hide")
|
|
57
|
+
if (is_hide && is_hide=="false") {
|
|
58
|
+
sub_el.setAttribute("is_hide", "true");
|
|
59
|
+
sub_el.style.display = "none"
|
|
60
|
+
sub_button.textContent = "展开"
|
|
61
|
+
}
|
|
62
|
+
else if(is_hide && is_hide=="true") {
|
|
63
|
+
sub_el.setAttribute("is_hide", "false");
|
|
64
|
+
sub_el.style.display = ""
|
|
65
|
+
sub_button.textContent = "折叠"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// 二选一。仅ob环境,mdit环境不支持
|
|
69
|
+
if (ABCSetting.env.startsWith("obsidian")) {
|
|
70
|
+
sub_button.onclick = fn_fold
|
|
71
|
+
}
|
|
72
|
+
// mdit (vuepress、app) 选用
|
|
73
|
+
else {
|
|
74
|
+
sub_button.setAttribute("onclick", `
|
|
75
|
+
const sub_button = this;
|
|
76
|
+
const sub_el = this.nextElementSibling;
|
|
77
|
+
|
|
78
|
+
const is_hide = sub_el.getAttribute("is_hide")
|
|
79
|
+
if (is_hide && is_hide=="false") {
|
|
80
|
+
sub_el.setAttribute("is_hide", "true");
|
|
81
|
+
sub_el.style.display = "none"
|
|
82
|
+
sub_button.textContent = "展开"
|
|
83
|
+
}
|
|
84
|
+
else if(is_hide && is_hide=="true") {
|
|
85
|
+
sub_el.setAttribute("is_hide", "false");
|
|
86
|
+
sub_el.style.display = ""
|
|
87
|
+
sub_button.textContent = "折叠"
|
|
88
|
+
}
|
|
89
|
+
`);
|
|
90
|
+
}
|
|
91
|
+
mid_el.appendChild(sub_button)
|
|
92
|
+
mid_el.appendChild(sub_el)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
// 特殊:如果折叠内容是列表格。将该处理器的折叠行为修改该按钮的折叠功能
|
|
96
|
+
const isListTable = sub_el.classList.contains("ab-list-table-parent")
|
|
97
|
+
const listTable_btn = sub_el.querySelector(".ab-table-fold")
|
|
98
|
+
if (isListTable && listTable_btn) {
|
|
99
|
+
// 二选一。仅ob环境,mdit环境不支持
|
|
100
|
+
if (ABCSetting.env.startsWith("obsidian")) {
|
|
101
|
+
// 1. 回溯原折叠
|
|
102
|
+
fn_fold()
|
|
103
|
+
sub_button.textContent = "折叠/展开"
|
|
104
|
+
// 2. 使用新折叠
|
|
105
|
+
const fn_fold2 = ()=>{
|
|
106
|
+
const clickEvent = new MouseEvent("click", {
|
|
107
|
+
view: window,
|
|
108
|
+
bubbles: true,
|
|
109
|
+
cancelable: true
|
|
110
|
+
});
|
|
111
|
+
listTable_btn.dispatchEvent(clickEvent);
|
|
112
|
+
}
|
|
113
|
+
fn_fold2()
|
|
114
|
+
// 3. 按钮功能替换
|
|
115
|
+
sub_button.onclick = fn_fold2
|
|
116
|
+
}
|
|
117
|
+
// mdit (vuepress、app) 选用
|
|
118
|
+
// TODO
|
|
119
|
+
else {}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return content
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
const _abc_scroll = ABConvert.factory({
|
|
127
|
+
id: "scroll",
|
|
128
|
+
name: "滚动",
|
|
129
|
+
match: /^scroll(X)?(\((\d+)\))?$/,
|
|
130
|
+
default: "scroll(460)",
|
|
131
|
+
detail: "默认是纵向滚动。可以指定溢出滚动的范围,可以使用scrollX进行横向滚动",
|
|
132
|
+
process_param: ABConvert_IOEnum.el,
|
|
133
|
+
process_return: ABConvert_IOEnum.el,
|
|
134
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{
|
|
135
|
+
// 参数 - 最大宽/高
|
|
136
|
+
const matchs = header.match(/^scroll(X)?(\((\d+)\))?$/)
|
|
137
|
+
if (!matchs) return content
|
|
138
|
+
let arg1 = 0 // default flag
|
|
139
|
+
if (matchs[2] && matchs[3]) {
|
|
140
|
+
arg1 = Number(matchs[3])
|
|
141
|
+
if (isNaN(arg1)) return content
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 修改元素
|
|
145
|
+
if(content.children.length != 1) return content
|
|
146
|
+
const sub_el = content.children[0]
|
|
147
|
+
sub_el.remove() // 应该非必要吧
|
|
148
|
+
const mid_el = document.createElement("div"); content.appendChild(mid_el); mid_el.classList.add("ab-deco-scroll");
|
|
149
|
+
mid_el.appendChild(sub_el)
|
|
150
|
+
|
|
151
|
+
// 参数 - X/Y
|
|
152
|
+
if (!matchs[1]){
|
|
153
|
+
mid_el.classList.add("ab-deco-scroll-y")
|
|
154
|
+
mid_el.setAttribute("style", `max-height: ${arg1 !== 0 ? arg1+'px' : '460px'}`)
|
|
155
|
+
} else {
|
|
156
|
+
mid_el.classList.add("ab-deco-scroll-x")
|
|
157
|
+
mid_el.setAttribute("style", `max-height: ${arg1 !== 0 ? arg1+'px' : '100%'}`)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return content
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
const _abc_overfold = ABConvert.factory({
|
|
165
|
+
id: "overfold",
|
|
166
|
+
name: "超出折叠",
|
|
167
|
+
match: /^overfold(\((\d+)\))?$/,
|
|
168
|
+
default: "overfold(380)",
|
|
169
|
+
process_param: ABConvert_IOEnum.el,
|
|
170
|
+
process_return: ABConvert_IOEnum.el,
|
|
171
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{
|
|
172
|
+
// 找参数
|
|
173
|
+
const matchs = header.match(/^overfold(\((\d+)\))?$/)
|
|
174
|
+
if (!matchs) return content
|
|
175
|
+
let arg1:number
|
|
176
|
+
if (!matchs[1]) arg1=460 // 默认值
|
|
177
|
+
else{
|
|
178
|
+
if (!matchs[2]) return content
|
|
179
|
+
arg1 = Number(matchs[2])
|
|
180
|
+
if (isNaN(arg1)) return content
|
|
181
|
+
}
|
|
182
|
+
// 修改元素
|
|
183
|
+
if(content.children.length!=1) return content
|
|
184
|
+
const sub_el = content.children[0]
|
|
185
|
+
sub_el.remove()
|
|
186
|
+
const mid_el = document.createElement("div"); content.appendChild(mid_el); mid_el.classList.add("ab-deco-overfold");
|
|
187
|
+
const sub_button = document.createElement("div"); mid_el.appendChild(sub_button); sub_button.classList.add("ab-deco-overfold-button"); sub_button.textContent = "展开";
|
|
188
|
+
sub_el.classList.add("ab-deco-overfold-content")
|
|
189
|
+
mid_el.appendChild(sub_el)
|
|
190
|
+
mid_el.appendChild(sub_button)
|
|
191
|
+
|
|
192
|
+
mid_el.setAttribute("style", `max-height: ${arg1}px`)
|
|
193
|
+
mid_el.setAttribute("is-fold", "true")
|
|
194
|
+
sub_button.onclick = ()=>{
|
|
195
|
+
const is_fold = mid_el.getAttribute("is-fold")
|
|
196
|
+
if (!is_fold) return
|
|
197
|
+
if (is_fold=="true") {
|
|
198
|
+
mid_el.setAttribute("style", "")
|
|
199
|
+
mid_el.setAttribute("is-fold", "false")
|
|
200
|
+
sub_button.textContent = "折叠"
|
|
201
|
+
}
|
|
202
|
+
else{
|
|
203
|
+
mid_el.setAttribute("style", `max-height: ${arg1}px`)
|
|
204
|
+
mid_el.setAttribute("is-fold", "true")
|
|
205
|
+
sub_button.textContent = "展开"
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return content
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
/// 可以匹配如:
|
|
214
|
+
/// width(25%,25%,50%)
|
|
215
|
+
/// width(100px,10rem,10.5)
|
|
216
|
+
/// width(100)
|
|
217
|
+
const _abc_width = ABConvert.factory({
|
|
218
|
+
id: "width",
|
|
219
|
+
name: "宽度控制",
|
|
220
|
+
match: /^width\(((?:\d*\.?\d+(?:%|px|rem)?,\s*)*\d*\.?\d+(?:%|px|rem)?)\)$/,
|
|
221
|
+
detail: "用于控制表格或分栏的每列的宽度",
|
|
222
|
+
process_param: ABConvert_IOEnum.el,
|
|
223
|
+
process_return: ABConvert_IOEnum.el,
|
|
224
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{
|
|
225
|
+
const matchs = header.match(/^width\(((?:\d*\.?\d+(?:%|px|rem)?,\s*)*\d*\.?\d+(?:%|px|rem)?)\)$/)
|
|
226
|
+
if (!matchs || content.children.length!=1) return content
|
|
227
|
+
|
|
228
|
+
// 支持 % 和 px 两种单位,默认单位是 px
|
|
229
|
+
const args = matchs[1].split(",").map(arg =>
|
|
230
|
+
/^\d*\.?\d+$/.test(arg.trim()) ? `${arg.trim()}%` : arg.trim()
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
// 检查容器是否包含需要处理的类名, 根据不同的容器, 处理方式不同
|
|
234
|
+
// b1. ab-col版本
|
|
235
|
+
// 支持渲染混合单位参数
|
|
236
|
+
if (content.children[0].classList.contains('ab-col')) {
|
|
237
|
+
const sub_els = content.children[0].children
|
|
238
|
+
if(sub_els.length==0) return content
|
|
239
|
+
// 允许参数数量与分栏数量不一致,多的部分会被忽略
|
|
240
|
+
for(let i=0;i<Math.min(sub_els.length, args.length);i++){
|
|
241
|
+
const sub_el = sub_els[i] as HTMLElement
|
|
242
|
+
if(args[i].endsWith("%")) sub_el.style.flex = `0 1 ${args[i]}`
|
|
243
|
+
else {
|
|
244
|
+
sub_el.style.width = args[i]
|
|
245
|
+
sub_el.style.flex = `0 0 auto`
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return content
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* b2. table版本
|
|
253
|
+
* table目前无法很好渲染混合单位的参数(px和rem可以混合)
|
|
254
|
+
* 用settimeout延迟获取table宽度可解决,但是会延长渲染时间
|
|
255
|
+
* 可以尝试改用grid布局
|
|
256
|
+
*/
|
|
257
|
+
// 使用非百分比单位尽量保证参数数量与列数一致,使用百分比单位表格会被按比例拉伸到行宽
|
|
258
|
+
const table: HTMLElement|null = content.querySelector('table')
|
|
259
|
+
if (table !== null) {
|
|
260
|
+
table.style.tableLayout = 'fixed'
|
|
261
|
+
// 检查是否存在 % 单位的参数,使用100%,否则使用fit-content
|
|
262
|
+
table.style.width = args.some(arg => arg.endsWith('%')) ? '100%' : 'fit-content'
|
|
263
|
+
// setTimeout(() => {
|
|
264
|
+
// console.log('Table width:', table.offsetWidth);
|
|
265
|
+
// console.log('Computed width:', window.getComputedStyle(table).width);
|
|
266
|
+
// }, 10);
|
|
267
|
+
table.querySelectorAll('tr').forEach(row => {
|
|
268
|
+
for (let i = 0; i < Math.min(row.children.length, args.length); i++) {
|
|
269
|
+
const cell = row.children[i] as HTMLElement
|
|
270
|
+
cell.style.width = cell.style.minWidth = cell.style.maxWidth = args[i]
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
return content
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// b3. 不符合
|
|
277
|
+
return content
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
const _abc_addClass = ABConvert.factory({
|
|
282
|
+
id: "addClass",
|
|
283
|
+
name: "增加class",
|
|
284
|
+
detail: "给当前块增加一个类名。支持正常使用空格来添加多个class, 不需要加dot符, 就像在class=''里写的那样",
|
|
285
|
+
match: /^addClass\((.*)\)$/,
|
|
286
|
+
process_param: ABConvert_IOEnum.el,
|
|
287
|
+
process_return: ABConvert_IOEnum.el,
|
|
288
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{
|
|
289
|
+
const matchs = header.match(/^addClass\((.*)\)$/)
|
|
290
|
+
if (!matchs || !matchs[1]) return content
|
|
291
|
+
if(content.children.length != 1) return content
|
|
292
|
+
const sub_el = content.children[0]
|
|
293
|
+
|
|
294
|
+
const args = matchs[1].split(' ')
|
|
295
|
+
for (const arg of args) {
|
|
296
|
+
sub_el.classList.add(arg)
|
|
297
|
+
}
|
|
298
|
+
return content
|
|
299
|
+
}
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
const _abc_addStyle = ABConvert.factory({
|
|
303
|
+
id: "addStyle",
|
|
304
|
+
name: "增加style",
|
|
305
|
+
detail: "给当前块增加一个样式, 注意最外的括号往内要留一个空格, 避免rotate这种用括号时冲突。添加多个则正常使用分号",
|
|
306
|
+
match: /^addStyle\(\s(.*)\s\)$/, // 中间可能有括号,要加空格保证不误识别
|
|
307
|
+
process_param: ABConvert_IOEnum.el,
|
|
308
|
+
process_return: ABConvert_IOEnum.el,
|
|
309
|
+
process: (el, header, content: HTMLElement): HTMLElement => {
|
|
310
|
+
const matchs = header.match(/^addStyle\(\s(.*)\s\)$/)
|
|
311
|
+
if (!matchs || !matchs[1]) return content
|
|
312
|
+
if (content.children.length != 1) return content
|
|
313
|
+
const sub_el = content.children[0]
|
|
314
|
+
// sub_el.setAttribute("style", String(matchs[1])) // setStyle
|
|
315
|
+
;(sub_el as HTMLElement).style.cssText += String(matchs[1])
|
|
316
|
+
return content
|
|
317
|
+
}
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
const _abc_addDiv = ABConvert.factory({
|
|
321
|
+
id: "addDiv",
|
|
322
|
+
name: "增加div和class",
|
|
323
|
+
detail: "给当前块增加一个父类,需要给这个父类一个类名",
|
|
324
|
+
match: /^addDiv\((.*)\)$/,
|
|
325
|
+
process_param: ABConvert_IOEnum.el,
|
|
326
|
+
process_return: ABConvert_IOEnum.el,
|
|
327
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{
|
|
328
|
+
const matchs = header.match(/^addDiv\((.*)\)$/)
|
|
329
|
+
if (!matchs || !matchs[1]) return content
|
|
330
|
+
|
|
331
|
+
// 修改元素
|
|
332
|
+
if(content.children.length != 1) return content
|
|
333
|
+
const sub_el = content.children[0]
|
|
334
|
+
|
|
335
|
+
sub_el.remove()
|
|
336
|
+
const mid_el = document.createElement("div"); content.appendChild(mid_el);
|
|
337
|
+
const args = matchs[1].split(' ')
|
|
338
|
+
for (const arg of args) {
|
|
339
|
+
mid_el.classList.add(arg)
|
|
340
|
+
}
|
|
341
|
+
mid_el.appendChild(sub_el)
|
|
342
|
+
return content
|
|
343
|
+
}
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
const _abc_title = ABConvert.factory({
|
|
347
|
+
id: "title",
|
|
348
|
+
name: "标题",
|
|
349
|
+
match: /^#(.*)/,
|
|
350
|
+
detail: "若直接处理代码或表格块,则会有特殊风格",
|
|
351
|
+
process_param: ABConvert_IOEnum.el,
|
|
352
|
+
process_return: ABConvert_IOEnum.el,
|
|
353
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{ // content有特殊class,不能更换。要在他下面套壳
|
|
354
|
+
const matchs = header.match(/^#(.*)/)
|
|
355
|
+
if (!matchs || !matchs[1]) return content
|
|
356
|
+
const arg1 = matchs[1]
|
|
357
|
+
|
|
358
|
+
// 修改元素 - 把旧元素取出文档树
|
|
359
|
+
const el_content = document.createElement("div");
|
|
360
|
+
while (content.firstChild) {
|
|
361
|
+
const item = content.firstChild;
|
|
362
|
+
content.removeChild(item)
|
|
363
|
+
el_content.appendChild(item)
|
|
364
|
+
}
|
|
365
|
+
// 修改元素 - 重新构建结构
|
|
366
|
+
const el_root = document.createElement("div"); content.appendChild(el_root); el_root.classList.add("ab-deco-title");
|
|
367
|
+
const el_title = document.createElement("div"); el_root.appendChild(el_title); el_title.classList.add("ab-deco-title-title");
|
|
368
|
+
const el_title_p = document.createElement("p"); el_title.appendChild(el_title_p); el_title_p.textContent = arg1;
|
|
369
|
+
el_root.appendChild(el_content); el_content.classList.add("ab-deco-title-content");
|
|
370
|
+
|
|
371
|
+
// 判断元素类型修改,以修改title风格 // TODO 话说混合应该用第一个还是直接none?先用第一个吧,因为说不定后面的是工具栏之类的
|
|
372
|
+
let el_content_sub = el_content.childNodes[0]; if (!el_content_sub) return content;
|
|
373
|
+
if (el_content_sub instanceof HTMLDivElement && el_content.childNodes.length == 1 && el_content.childNodes[0].childNodes[0]) { el_content_sub = el_content.childNodes[0].childNodes[0] } // 如果是重渲染,则再往下一层
|
|
374
|
+
let title_type = "none"
|
|
375
|
+
if (el_content_sub instanceof HTMLQuoteElement){title_type = "quote"
|
|
376
|
+
// 这里借用callout的样式
|
|
377
|
+
el_root.classList.add("callout")
|
|
378
|
+
el_title.classList.add("callout-title");
|
|
379
|
+
el_content.classList.add("callout-content");
|
|
380
|
+
// 去除原来的引用块样式
|
|
381
|
+
const el_content_sub_parent = el_content_sub.parentNode; if (!el_content_sub_parent) return content
|
|
382
|
+
while (el_content_sub.firstChild) {
|
|
383
|
+
el_content_sub_parent.insertBefore(el_content_sub.firstChild, el_content_sub);
|
|
384
|
+
}
|
|
385
|
+
el_content_sub_parent.removeChild(el_content_sub)
|
|
386
|
+
}
|
|
387
|
+
else if (el_content_sub instanceof HTMLTableElement){title_type = "table"}
|
|
388
|
+
else if (el_content_sub instanceof HTMLUListElement){title_type = "ul"}
|
|
389
|
+
else if (el_content_sub instanceof HTMLPreElement){title_type = "pre"}
|
|
390
|
+
// ;(()=>{
|
|
391
|
+
// let color:string = window.getComputedStyle(el_content_sub ,null).getPropertyValue('background-color');
|
|
392
|
+
// if (color) el_title.setAttribute("style", `background-color:${color}`)
|
|
393
|
+
// else {
|
|
394
|
+
// color = window.getComputedStyle(el_content_sub ,null).getPropertyValue('background');
|
|
395
|
+
// el_title.setAttribute("style", `background:${color}`)
|
|
396
|
+
// }
|
|
397
|
+
// })//()
|
|
398
|
+
el_title.setAttribute("title-type", title_type)
|
|
399
|
+
return content
|
|
400
|
+
}
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
const _abc_transposition = ABConvert.factory({
|
|
404
|
+
id: "transposition",
|
|
405
|
+
name: "表格转置",
|
|
406
|
+
match: "transposition",
|
|
407
|
+
detail: "将表格进行转置,就像矩阵转置那样。该版本不支持有跨行跨列单元格。若复杂表格,请换用trs版本",
|
|
408
|
+
process_param: ABConvert_IOEnum.el,
|
|
409
|
+
process_return: ABConvert_IOEnum.el,
|
|
410
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{
|
|
411
|
+
|
|
412
|
+
// 1. 数据准备 - 旧表格简单解析 (暂时仅支持规范列表,不支持跨行跨列或缺格)
|
|
413
|
+
const origi_table: HTMLTableElement | null = content.querySelector('table'); if (!origi_table) return content; // 注意table不一定是content直系儿子
|
|
414
|
+
const origi_rows = origi_table.rows;
|
|
415
|
+
const origi_rowCount: number = origi_rows.length; // 行数
|
|
416
|
+
const origi_colCount: number = origi_rows[0].cells.length; // 列数 (只取第一行的列数)
|
|
417
|
+
|
|
418
|
+
// 2. 准备表格元素
|
|
419
|
+
const trans_table = document.createElement('table'); origi_table.classList.add("ab-transposition", "ab-table");
|
|
420
|
+
origi_table.classList.forEach(className => { // 并应用原表格的样式
|
|
421
|
+
trans_table.classList.add(className);
|
|
422
|
+
});
|
|
423
|
+
// const trans_header = document.createElement('thead'); trans_table.appendChild(trans_header); // 转置不支持表头
|
|
424
|
+
const trans_body = document.createElement('tbody'); trans_table.appendChild(trans_body);
|
|
425
|
+
|
|
426
|
+
// 3. 数据填充表格
|
|
427
|
+
for (let col = 0; col < origi_colCount; col++) {
|
|
428
|
+
const newRow = trans_body.insertRow();
|
|
429
|
+
for (let row = 0; row < origi_rowCount; row++) {
|
|
430
|
+
const oldCell = origi_rows[row].cells[col]; if (!oldCell) continue; // 需要注意的是:如果是obsidian的可视化编辑表格,tbody前两个tr会是空的,很怪
|
|
431
|
+
const newCell = newRow.insertCell();
|
|
432
|
+
newCell.innerHTML = oldCell.innerHTML;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// 4. 元素替换
|
|
437
|
+
origi_table.innerHTML = trans_table.innerHTML;
|
|
438
|
+
return content;
|
|
439
|
+
}
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
const _abc_transpose = ABConvert.factory({
|
|
443
|
+
id: "transpose",
|
|
444
|
+
name: "表格转置",
|
|
445
|
+
match: "trs",
|
|
446
|
+
detail: "将表格进行转置,就像矩阵转置那样。该版本支持有跨行跨列单元格",
|
|
447
|
+
process_param: ABConvert_IOEnum.el,
|
|
448
|
+
process_return: ABConvert_IOEnum.el,
|
|
449
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{
|
|
450
|
+
// 1. table 2 tableMap
|
|
451
|
+
const origi_table: HTMLTableElement | null = content.querySelector('table'); if (!origi_table) return content; // 注意table不一定是content直系儿子
|
|
452
|
+
let { tableMap, origi_rowCount, origi_colCount } = table2tableMap(origi_table)
|
|
453
|
+
|
|
454
|
+
// 2. 自定义处理,map转置
|
|
455
|
+
const tableMap2: TableMap = new Array(origi_colCount).fill(null).map(() => new Array(origi_rowCount).fill(null));
|
|
456
|
+
for (let i = 0; i < origi_rowCount; i++) {
|
|
457
|
+
for (let j = 0; j < origi_colCount; j++) {
|
|
458
|
+
const origi_cell = tableMap[i][j]
|
|
459
|
+
if (!origi_cell) continue;
|
|
460
|
+
else if (origi_cell == "<") {
|
|
461
|
+
tableMap2[j][i] = "^"
|
|
462
|
+
}
|
|
463
|
+
else if (origi_cell == "^") {
|
|
464
|
+
tableMap2[j][i] = "<"
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
let content = origi_cell.html
|
|
468
|
+
if (content.innerHTML == '<' || content.innerHTML == '<') content.innerHTML = '^'
|
|
469
|
+
else if (content.innerHTML == '^') content.innerHTML = '<'
|
|
470
|
+
tableMap2[j][i] = {
|
|
471
|
+
html: origi_cell.html,
|
|
472
|
+
rowSpan: origi_cell.colSpan || 1,
|
|
473
|
+
colSpan: origi_cell.rowSpan || 1,
|
|
474
|
+
rowIndex: origi_cell.colIndex,
|
|
475
|
+
colIndex: origi_cell.rowIndex,
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
const tmp = origi_colCount
|
|
481
|
+
origi_colCount = origi_rowCount
|
|
482
|
+
origi_rowCount = tmp
|
|
483
|
+
|
|
484
|
+
// 3. tableMap 2 table
|
|
485
|
+
const trans_table = tableMap2table(tableMap2, origi_rowCount, origi_colCount)
|
|
486
|
+
|
|
487
|
+
// 4. 元素替换
|
|
488
|
+
origi_table.classList.forEach(className => { // 应用原表格的样式
|
|
489
|
+
trans_table.classList.add(className);
|
|
490
|
+
});
|
|
491
|
+
trans_table.classList.add("ab-transposition", "ab-table");
|
|
492
|
+
origi_table.innerHTML = trans_table.innerHTML;
|
|
493
|
+
return content;
|
|
494
|
+
}
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
// 实现上与表格转置大差不差
|
|
498
|
+
const _abc_exTable = ABConvert.factory({
|
|
499
|
+
id: "exTable",
|
|
500
|
+
name: "表格扩展",
|
|
501
|
+
match: "exTable",
|
|
502
|
+
detail: "将表格应用sheet-table语法 (使用 `</^` 标注合并单元格)",
|
|
503
|
+
process_param: ABConvert_IOEnum.el,
|
|
504
|
+
process_return: ABConvert_IOEnum.el,
|
|
505
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{
|
|
506
|
+
// 1. table 2 tableMap
|
|
507
|
+
const origi_table: HTMLTableElement | null = content.querySelector('table'); if (!origi_table) return content; // 注意table不一定是content直系儿子
|
|
508
|
+
let { tableMap, origi_rowCount, origi_colCount } = table2tableMap(origi_table, true)
|
|
509
|
+
|
|
510
|
+
// 2. 自定义处理
|
|
511
|
+
const map_table2 = tableMap
|
|
512
|
+
|
|
513
|
+
// 3. tableMap 2 table
|
|
514
|
+
const trans_table = tableMap2table(map_table2, origi_rowCount, origi_colCount)
|
|
515
|
+
|
|
516
|
+
// 4. 元素替换
|
|
517
|
+
origi_table.classList.forEach(className => { // 应用原表格的样式
|
|
518
|
+
trans_table.classList.add(className);
|
|
519
|
+
});
|
|
520
|
+
trans_table.classList.add("ab-extable", "ab-table");
|
|
521
|
+
origi_table.innerHTML = trans_table.innerHTML;
|
|
522
|
+
return content;
|
|
523
|
+
}
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
/// 表格严格化/normalized
|
|
527
|
+
const _abc_strictTable = ABConvert.factory({
|
|
528
|
+
id: "strictTable",
|
|
529
|
+
name: "正规化表格",
|
|
530
|
+
match: "strictTable",
|
|
531
|
+
detail: "补全表格的尾丢失项,list2table|trs时,可以有效避免bug",
|
|
532
|
+
process_param: ABConvert_IOEnum.el,
|
|
533
|
+
process_return: ABConvert_IOEnum.el,
|
|
534
|
+
process: (el, header, content: HTMLElement): HTMLElement=>{
|
|
535
|
+
// 1. table 2 tableMap
|
|
536
|
+
const origi_table: HTMLTableElement | null = content.querySelector('table'); if (!origi_table) return content; // 注意table不一定是content直系儿子
|
|
537
|
+
let { tableMap, origi_rowCount, origi_colCount } = table2tableMap(origi_table)
|
|
538
|
+
|
|
539
|
+
// 2. 自定义处理,填充末尾缺失格
|
|
540
|
+
for (let i = 0; i < origi_rowCount; i++) {
|
|
541
|
+
for (let j = 0; j < origi_colCount; j++) {
|
|
542
|
+
const origi_cell = tableMap[i][j]
|
|
543
|
+
if (!origi_cell) {
|
|
544
|
+
tableMap[i][j] = {
|
|
545
|
+
html: document.createElement("td"), // 空单元格
|
|
546
|
+
rowSpan: 1,
|
|
547
|
+
colSpan: 1,
|
|
548
|
+
rowIndex: i,
|
|
549
|
+
colIndex: j,
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// 3. tableMap 2 table
|
|
556
|
+
const trans_table = tableMap2table(tableMap, origi_rowCount, origi_colCount)
|
|
557
|
+
|
|
558
|
+
// 4. 元素替换
|
|
559
|
+
origi_table.classList.forEach(className => { // 应用原表格的样式
|
|
560
|
+
trans_table.classList.add(className);
|
|
561
|
+
});
|
|
562
|
+
trans_table.classList.add("ab-extable", "ab-table");
|
|
563
|
+
origi_table.innerHTML = trans_table.innerHTML;
|
|
564
|
+
return content;
|
|
565
|
+
}
|
|
566
|
+
})
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* 架构:
|
|
570
|
+
*
|
|
571
|
+
* 这里我们把每个单元格的位置和尺寸用四个变量描述:rowSpan, colSpan, rowIndex, colIndex
|
|
572
|
+
*
|
|
573
|
+
* 注意区分以下几个变量:
|
|
574
|
+
* - 这四个是绝对的:rowSpan、colSpan、rowIndex、colIndex
|
|
575
|
+
* - 这两个是相对的(起点不一定从0开始):relRow、relCol
|
|
576
|
+
* 例如对于下表来说,C的 (rowIndex, colIndex)是(1,1),但 (relRow, relCol)是(1,0)
|
|
577
|
+
* | A | B |
|
|
578
|
+
* | ^ | C |
|
|
579
|
+
* - 这两个不是纯粹的位置描述:table_rowCount、table_colCount。他们有可能大于rowIndex、colIndex的取值
|
|
580
|
+
* 行数的值应该等于单元格中(rowIndex+rowSpan)最大的值
|
|
581
|
+
*/
|
|
582
|
+
export type type_tableCell = {
|
|
583
|
+
html: HTMLTableCellElement,
|
|
584
|
+
text?: string, // 给可视化编辑版本用的
|
|
585
|
+
rowSpan: number,
|
|
586
|
+
colSpan: number,
|
|
587
|
+
rowIndex: number,
|
|
588
|
+
colIndex: number,
|
|
589
|
+
}
|
|
590
|
+
export type TableMap = (type_tableCell|null|"<"|"^")[][]
|
|
591
|
+
|
|
592
|
+
export function table2tableMap(
|
|
593
|
+
origi_table: HTMLTableElement, useMergeFlag: boolean = false
|
|
594
|
+
): {tableMap: TableMap, origi_rowCount: number, origi_colCount: number} {
|
|
595
|
+
// 解析tableMap的行列数 (支持rowspan和colspan)
|
|
596
|
+
const origi_rows = origi_table.rows
|
|
597
|
+
let origi_rowCount: number = origi_rows.length // 最大行数 (算span范围扩展)
|
|
598
|
+
let origi_colCount: number = 0 // 最大列数 (算span范围扩展)
|
|
599
|
+
{
|
|
600
|
+
// 注意不要随便简化这里,容易出错
|
|
601
|
+
// 例如下面的例子:
|
|
602
|
+
//
|
|
603
|
+
// - r1c1 // 第一行relCol2
|
|
604
|
+
// - r1c2
|
|
605
|
+
// - r2c2 // 第二行relCol2,但其colCount应为3
|
|
606
|
+
// - r2c3
|
|
607
|
+
// - r3c3
|
|
608
|
+
// - ^
|
|
609
|
+
// 或写成tableMap的形式:
|
|
610
|
+
// |r1c1|r1c2|
|
|
611
|
+
// | ^ |r2c2|r2c3|
|
|
612
|
+
// | ^ | ^ |r3c3|
|
|
613
|
+
// | ^ |
|
|
614
|
+
//
|
|
615
|
+
// - 在spanRow/sapnCol模型中,认为只有三行,且他们的列数为: 2 2 1 (这里用relRow和relCol来描述)
|
|
616
|
+
// - 而在tableMap模型中,认为有四行,且他们的列数为: 2 3 3 1 (这里用rowIndex和colIndex来描述)
|
|
617
|
+
let map_colCount: number[] = [] // 记录每行的最大列数 (tableMap的列数)
|
|
618
|
+
for (let relRow = 0; relRow < origi_rowCount; relRow++) {
|
|
619
|
+
for (const cell of origi_rows[relRow].cells) {
|
|
620
|
+
// 遍历每个单元格,然后填充map_colCount
|
|
621
|
+
const colSpan = cell.colSpan || 1;
|
|
622
|
+
const rowSpan = cell.rowSpan || 1;
|
|
623
|
+
for (let relRowSpan = relRow; relRowSpan < relRow+rowSpan; relRowSpan++) {
|
|
624
|
+
if (!map_colCount[relRowSpan]) map_colCount[relRowSpan] = colSpan
|
|
625
|
+
else map_colCount[relRowSpan] += colSpan
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
origi_rowCount = map_colCount.length
|
|
630
|
+
origi_colCount = Math.max(...map_colCount)
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// 表格解析到tableMap
|
|
634
|
+
// 创建一个二维数组来记录旧表格, size: [origi_rowCount][origi_colCount]
|
|
635
|
+
// 要分析带span的表格,必须用到占位符才有解。`^` 和 `<` 都是占位符,不过目前不区分作用
|
|
636
|
+
const tableMap: TableMap = new Array(origi_rowCount).fill(null).map(() => new Array(origi_colCount).fill(null));
|
|
637
|
+
for (let relRow = 0; relRow < origi_rowCount; relRow++) {
|
|
638
|
+
for (let relCol = 0; relCol < origi_rows[relRow].cells.length; relCol++) {
|
|
639
|
+
const cell: HTMLTableCellElement = origi_rows[relRow].cells[relCol];
|
|
640
|
+
|
|
641
|
+
// 调整当前格位置
|
|
642
|
+
const rowIndex = relRow;
|
|
643
|
+
let colIndex = relCol;
|
|
644
|
+
while(true) {
|
|
645
|
+
if (colIndex >= tableMap[rowIndex].length) {
|
|
646
|
+
console.error(`表格解析错误: colIndex超出范围: [${rowIndex}][${colIndex}] overflow tableMap[${origi_rowCount-1}][${origi_colCount-1}]`, tableMap);
|
|
647
|
+
throw new Error("表格解析错误: colIndex超出范围")
|
|
648
|
+
}
|
|
649
|
+
if (!tableMap[rowIndex][colIndex]) { break } // 位置正确 (null)
|
|
650
|
+
else colIndex++ // 继续找位置
|
|
651
|
+
}
|
|
652
|
+
// 填充下占位
|
|
653
|
+
if (cell.rowSpan>1) {
|
|
654
|
+
for (let i = 1; i < cell.rowSpan; i++) {
|
|
655
|
+
if (rowIndex+i >= tableMap.length) { break; } // 允许范围溢出
|
|
656
|
+
tableMap[rowIndex+i][colIndex] = "^"
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
// 填充右占位
|
|
660
|
+
if (cell.colSpan>1) {
|
|
661
|
+
for (let i = 1; i < cell.rowSpan; i++) {
|
|
662
|
+
if (colIndex+i >= tableMap[rowIndex].length) { break; } // 允许范围溢出
|
|
663
|
+
tableMap[rowIndex][colIndex+i] = "<"
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
// 填充本格
|
|
667
|
+
if (useMergeFlag) {
|
|
668
|
+
// MergeFlag分支,遇到合并符号时,会向上/向下找到目标单元格并修改
|
|
669
|
+
// 注意区分是程序填充 ^/< 和人为填充 ^/< 是有区别的,也可以区分得出来
|
|
670
|
+
// b1. `^` 符号且为左边界,则向上找到上边界
|
|
671
|
+
if (cell.rowSpan == 1 && cell.colSpan == 1 && cell.textContent == "^") {
|
|
672
|
+
tableMap[rowIndex][colIndex] = "^"
|
|
673
|
+
for (let i=rowIndex-1; i>=0; i--) {
|
|
674
|
+
const item = tableMap[i][colIndex]
|
|
675
|
+
if (!item) break
|
|
676
|
+
if (item == "<") break
|
|
677
|
+
if (item == "^") continue
|
|
678
|
+
if (item.html.textContent == "<") break
|
|
679
|
+
if (item.html.textContent != "^" || i==0) {
|
|
680
|
+
item.rowSpan += 1
|
|
681
|
+
break
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
// b2. `<` 符号且为上边界,则向左找到左边界
|
|
686
|
+
else if (cell.rowSpan == 1 && cell.colSpan == 1 && cell.textContent == "<") {
|
|
687
|
+
tableMap[rowIndex][colIndex] = "<"
|
|
688
|
+
for (let j=colIndex-1; j>=0; j--) {
|
|
689
|
+
const item = tableMap[rowIndex][j]
|
|
690
|
+
if (!item) break
|
|
691
|
+
if (item == "^") break
|
|
692
|
+
if (item == "<") continue
|
|
693
|
+
if (item.html.textContent == "^") break
|
|
694
|
+
if (item.html.textContent != "<" || j==0) {
|
|
695
|
+
item.colSpan += 1
|
|
696
|
+
break
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
// b3. 正常填充
|
|
701
|
+
else {
|
|
702
|
+
tableMap[rowIndex][colIndex] = {
|
|
703
|
+
html: cell,
|
|
704
|
+
rowSpan: cell.rowSpan,
|
|
705
|
+
colSpan: cell.colSpan,
|
|
706
|
+
rowIndex: rowIndex,
|
|
707
|
+
colIndex: colIndex,
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
} else {
|
|
711
|
+
tableMap[rowIndex][colIndex] = {
|
|
712
|
+
html: cell,
|
|
713
|
+
rowSpan: cell.rowSpan,
|
|
714
|
+
colSpan: cell.colSpan,
|
|
715
|
+
rowIndex: rowIndex,
|
|
716
|
+
colIndex: colIndex,
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
return {
|
|
723
|
+
tableMap, origi_rowCount, origi_colCount
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
export function tableMap2table(tableMap: TableMap, origi_rowCount: number, origi_colCount: number): HTMLTableElement {
|
|
728
|
+
// 新表格
|
|
729
|
+
const trans_table = document.createElement('table');
|
|
730
|
+
// const trans_header = document.createElement('thead'); trans_table.appendChild(trans_header); // 转置不支持表头
|
|
731
|
+
const trans_body = document.createElement('tbody'); trans_table.appendChild(trans_body);
|
|
732
|
+
|
|
733
|
+
// 数据填充
|
|
734
|
+
for (let i = 0; i < origi_rowCount; i++) {
|
|
735
|
+
const newRow = trans_body.insertRow();
|
|
736
|
+
for (let j = 0; j < origi_colCount; j++) {
|
|
737
|
+
const cell = tableMap[i][j]
|
|
738
|
+
if (!cell) continue;
|
|
739
|
+
if (cell == "<" || cell == "^") continue; // 填写和flag是能区分的
|
|
740
|
+
const newCell = newRow.insertCell();
|
|
741
|
+
newCell.innerHTML = cell.html.innerHTML;
|
|
742
|
+
newCell.rowSpan = cell.rowSpan;
|
|
743
|
+
newCell.colSpan = cell.colSpan;
|
|
744
|
+
newCell.setAttribute("rowIndex", String(cell.rowIndex));
|
|
745
|
+
newCell.setAttribute("colIndex", String(cell.colIndex));
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
return trans_table
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// 简易打印,调试用
|
|
753
|
+
function tableMapPrint(tableMap: TableMap) {
|
|
754
|
+
let content: string = ''
|
|
755
|
+
for (let i = 0; i < tableMap.length; i++) {
|
|
756
|
+
let row = i+"|";
|
|
757
|
+
for (let j = 0; j < tableMap[i].length; j++) {
|
|
758
|
+
const cell = tableMap[i][j];
|
|
759
|
+
if (cell === null) row += " . |";
|
|
760
|
+
else if (cell === "<") row += " < |";
|
|
761
|
+
else if (cell === "^") row += " ^ |";
|
|
762
|
+
else row += ` ${cell.html.textContent?.trim() || ""} |`;
|
|
763
|
+
}
|
|
764
|
+
content += row + '\n'
|
|
765
|
+
}
|
|
766
|
+
console.log('tableMap\n' + content)
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// 打印为md表格形式
|
|
770
|
+
// TODO 无对齐、至少两行
|
|
771
|
+
export function tableMap2md(tableMap: TableMap, showLineCount: boolean = false): string {
|
|
772
|
+
let content: string = ''
|
|
773
|
+
for (let i = 0; i < tableMap.length; i++) { // 行
|
|
774
|
+
let row = '' // 这一行的内容
|
|
775
|
+
if (i == 1) { // 插入表格标识
|
|
776
|
+
if (showLineCount) row += ' '
|
|
777
|
+
row = "|---".repeat(tableMap[i].length) + "|\n" // 若引起ob内部表格事件导致有问题,改为 "|暂时不合法"
|
|
778
|
+
}
|
|
779
|
+
if (showLineCount) row += i + ' '
|
|
780
|
+
row += "|"
|
|
781
|
+
for (let j = 0; j < tableMap[i].length; j++) { // 列
|
|
782
|
+
const cell = tableMap[i][j]
|
|
783
|
+
if (cell === null) row += " . |"
|
|
784
|
+
else if (cell === "<") row += " < |"
|
|
785
|
+
else if (cell === "^") row += " ^ |"
|
|
786
|
+
else {
|
|
787
|
+
row += cell.text ? ` ${cell.text.replace(/\n/g, '<br>')} |` : ` ${cell.html.textContent?.trim() || ""} |`
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
content += row + '\n'
|
|
791
|
+
}
|
|
792
|
+
return content
|
|
793
|
+
}
|