@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,497 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 处理器_两列列表版
|
|
3
|
+
*
|
|
4
|
+
* - md_str <-> 列表数据
|
|
5
|
+
* - 列表数据 <-> html
|
|
6
|
+
* - 表格数据 -> 列表数据
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ABCSetting, ABReg } from '../ABSetting'
|
|
10
|
+
import {ABConvert_IOEnum, ABConvert, type ABConvert_SpecSimp} from "./ABConvert"
|
|
11
|
+
import {ABConvertManager} from "../ABConvertManager"
|
|
12
|
+
import type {ListItem, List_ListItem} from "./abc_list"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 二列列表,特征是level只有0和1
|
|
17
|
+
*
|
|
18
|
+
* @detail
|
|
19
|
+
* 通常用于:
|
|
20
|
+
* - 二层一叉树
|
|
21
|
+
* - dirTree的初处理
|
|
22
|
+
* - Tabs
|
|
23
|
+
* - TimeLine
|
|
24
|
+
* - 仿列表
|
|
25
|
+
* - ...
|
|
26
|
+
* - 二层多叉树
|
|
27
|
+
* - fc-table (首列重要树)
|
|
28
|
+
* - ...
|
|
29
|
+
*
|
|
30
|
+
* 特别是对于mdit-container的 `:::+@` 来说,这种方式是更为方便的
|
|
31
|
+
*/
|
|
32
|
+
export interface C2ListItem extends ListItem {
|
|
33
|
+
level: 0|1;
|
|
34
|
+
}[]
|
|
35
|
+
export type List_C2ListItem = C2ListItem[]
|
|
36
|
+
|
|
37
|
+
/// 一些列表相关的工具集
|
|
38
|
+
export class C2ListProcess{
|
|
39
|
+
|
|
40
|
+
// ----------------------- str -> listData ------------------------
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 多层树转二层一叉树
|
|
44
|
+
*
|
|
45
|
+
* @detail
|
|
46
|
+
* 特点是level只有0和1两种
|
|
47
|
+
*
|
|
48
|
+
* example:
|
|
49
|
+
* - 1
|
|
50
|
+
* - 2
|
|
51
|
+
* - 3
|
|
52
|
+
* - 2
|
|
53
|
+
* to:
|
|
54
|
+
* - 1
|
|
55
|
+
* - 2\n - 3\n - 2
|
|
56
|
+
*/
|
|
57
|
+
static data_mL_2_2L1B(
|
|
58
|
+
list_itemInfo: List_ListItem
|
|
59
|
+
): List_C2ListItem{
|
|
60
|
+
const list_itemInfo2: List_C2ListItem = []
|
|
61
|
+
const level1:0 = 0
|
|
62
|
+
const level2:1 = 1
|
|
63
|
+
let flag_leve2 = false // 表示触发过level2,当遇到level1会重置
|
|
64
|
+
for (const itemInfo of list_itemInfo) {
|
|
65
|
+
if (level1>=itemInfo.level){ // 是level1
|
|
66
|
+
list_itemInfo2.push({
|
|
67
|
+
content: itemInfo.content.trim(),
|
|
68
|
+
level: level1
|
|
69
|
+
})
|
|
70
|
+
flag_leve2 = false
|
|
71
|
+
continue
|
|
72
|
+
}
|
|
73
|
+
if (true){ // 是level2/level2+/level2-
|
|
74
|
+
if (!flag_leve2){ // 新建
|
|
75
|
+
list_itemInfo2.push({
|
|
76
|
+
content: itemInfo.content.trim(),
|
|
77
|
+
level: level2
|
|
78
|
+
})
|
|
79
|
+
flag_leve2 = true
|
|
80
|
+
continue
|
|
81
|
+
}
|
|
82
|
+
else { // 内换行
|
|
83
|
+
const old_itemInfo = list_itemInfo2.pop()
|
|
84
|
+
if(old_itemInfo){
|
|
85
|
+
let new_content = itemInfo.content.trim()
|
|
86
|
+
if (itemInfo.level>level2) new_content = "- "+new_content
|
|
87
|
+
for (let i=0; i<(itemInfo.level-level2); i++) new_content = " "+new_content;
|
|
88
|
+
new_content = old_itemInfo.content+"\n"+new_content
|
|
89
|
+
list_itemInfo2.push({
|
|
90
|
+
content: new_content,
|
|
91
|
+
level: level2
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return list_itemInfo2
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 多层树转二层树
|
|
102
|
+
*
|
|
103
|
+
* @detail
|
|
104
|
+
* 特点是level只有0和1两种
|
|
105
|
+
*
|
|
106
|
+
* example:
|
|
107
|
+
* - 1
|
|
108
|
+
* - 2
|
|
109
|
+
* - 3
|
|
110
|
+
* - 2
|
|
111
|
+
* to:
|
|
112
|
+
* - 1
|
|
113
|
+
* - 2\n - 3
|
|
114
|
+
* - 2
|
|
115
|
+
*/
|
|
116
|
+
static data_mL_2_2L(
|
|
117
|
+
list_itemInfo: List_ListItem
|
|
118
|
+
): List_C2ListItem{
|
|
119
|
+
const list_itemInfo2: List_C2ListItem = []
|
|
120
|
+
const level1:0 = 0
|
|
121
|
+
const level2:1 = 1
|
|
122
|
+
for (const itemInfo of list_itemInfo) {
|
|
123
|
+
if (level1>=itemInfo.level){ // 是level1
|
|
124
|
+
list_itemInfo2.push({
|
|
125
|
+
content: itemInfo.content.trim(),
|
|
126
|
+
level: level1
|
|
127
|
+
})
|
|
128
|
+
continue
|
|
129
|
+
}
|
|
130
|
+
if (level2>=itemInfo.level){ // 是level2/level2-
|
|
131
|
+
list_itemInfo2.push({
|
|
132
|
+
content: itemInfo.content.trim(),
|
|
133
|
+
level: level2
|
|
134
|
+
})
|
|
135
|
+
continue
|
|
136
|
+
}
|
|
137
|
+
else{ // level2+,内换行 //
|
|
138
|
+
const old_itemInfo = list_itemInfo2.pop()
|
|
139
|
+
if(old_itemInfo){
|
|
140
|
+
let new_content = itemInfo.content.trim()
|
|
141
|
+
if (itemInfo.level>level2) new_content = "- "+new_content
|
|
142
|
+
for (let i=0; i<(itemInfo.level-level2); i++) new_content = " "+new_content;
|
|
143
|
+
new_content = old_itemInfo.content+"\n"+new_content
|
|
144
|
+
list_itemInfo2.push({
|
|
145
|
+
content: new_content,
|
|
146
|
+
level: level2
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return list_itemInfo2
|
|
152
|
+
|
|
153
|
+
/*
|
|
154
|
+
let list_itemInfo2: {content: string;level: number;}[] = []
|
|
155
|
+
let level1 = -1
|
|
156
|
+
let level2 = -1
|
|
157
|
+
for (let itemInfo of list_itemInfo) {
|
|
158
|
+
let this_level: number // 一共三种可能:0、1、(1+)表
|
|
159
|
+
if (level1<0) {level1=itemInfo.level; this_level = level1} // 未配置level1
|
|
160
|
+
else if (level1>=itemInfo.level) this_level = level1 // 是level1
|
|
161
|
+
else if (level2<0) {level2=itemInfo.level; this_level = level2} // 未配置level2
|
|
162
|
+
else if (level2>=itemInfo.level) this_level = level2 // 是level2
|
|
163
|
+
else { // (level2<itemInfo.level) // 依然是level2,但进行内换行,并把列表符和缩进给加回去
|
|
164
|
+
let old_itemInfo = list_itemInfo2.pop()
|
|
165
|
+
if(old_itemInfo){
|
|
166
|
+
let new_content = "- "+itemInfo.content.trim()
|
|
167
|
+
for (let i=0; i<(itemInfo.level-level2); i++) new_content = " "+new_content;
|
|
168
|
+
new_content = old_itemInfo.content+"\n"+new_content
|
|
169
|
+
list_itemInfo2.push({
|
|
170
|
+
content: new_content,
|
|
171
|
+
level: level2
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
continue
|
|
175
|
+
}
|
|
176
|
+
list_itemInfo2.push({
|
|
177
|
+
content: itemInfo.content.trim(),
|
|
178
|
+
level: level2
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
console.log("前后数据", list_itemInfo, list_itemInfo2)
|
|
182
|
+
return list_itemInfo2*/
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* 列表转二列列表数据
|
|
187
|
+
*
|
|
188
|
+
* @detail
|
|
189
|
+
* 为什么要直接转,而不能list2data|data2c2data来复用
|
|
190
|
+
* 因为会损失信息
|
|
191
|
+
*
|
|
192
|
+
* @param text 列表的md文本
|
|
193
|
+
* @param modeG 识别内换行符号。内换行符被替换为换行+前缀,比listdata的处理简单些,后面不需要再提高level // TODO 这部分逻辑应该抽离出来做成独立的处理器
|
|
194
|
+
*/
|
|
195
|
+
static list2c2data(text: string, modeG=true){
|
|
196
|
+
const list_itemInfo:List_C2ListItem = []
|
|
197
|
+
const list_text = text.trimStart().split("\n")
|
|
198
|
+
|
|
199
|
+
// 获取最大的标题级别
|
|
200
|
+
const first_match = list_text[0].match(ABReg.reg_list_noprefix)
|
|
201
|
+
if (!first_match || first_match[1]) {
|
|
202
|
+
console.error("不是列表内容:", list_text[0])
|
|
203
|
+
return list_itemInfo
|
|
204
|
+
}
|
|
205
|
+
const root_list_level:number = first_match[1].length // 第一个列表(也是缩进最小)的 `- ` 前空格数
|
|
206
|
+
|
|
207
|
+
// 循环填充
|
|
208
|
+
let current_content:string = "" // level1的子内容
|
|
209
|
+
let current_content_prefix:string = "" // level1的子内容的前缀
|
|
210
|
+
for (let line of list_text) {
|
|
211
|
+
const match_list = line.match(ABReg.reg_list_noprefix)
|
|
212
|
+
if (match_list && !match_list[1] && match_list[1].length<=root_list_level){ // b1. 遇到同等标题,level0新项出现
|
|
213
|
+
add_current_content()
|
|
214
|
+
let content = match_list[4]
|
|
215
|
+
// 替换掉内换行符
|
|
216
|
+
if (modeG) {
|
|
217
|
+
const inlines = match_list[4].split(ABReg.inline_split)
|
|
218
|
+
if (inlines.length > 1) {
|
|
219
|
+
const second_part = content.indexOf(inlines[1])
|
|
220
|
+
current_content += content.slice(second_part) + "\n"
|
|
221
|
+
current_content_prefix = " " // (TODO风险) 通过内换行符,则新的行前缀为双空格 (用户可能用tab的1和四空格的4,但不影响)
|
|
222
|
+
content = inlines[0]
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// 新项
|
|
226
|
+
list_itemInfo.push({
|
|
227
|
+
content: content,
|
|
228
|
+
level: 0
|
|
229
|
+
})
|
|
230
|
+
} else { // b2. 子内容
|
|
231
|
+
if (current_content.trim()=="") { // 第一行的子内容前缀提取
|
|
232
|
+
if (match_list && match_list[1]) current_content_prefix = match_list[1] // 有 `- `,则为 `- ` 前的字符数
|
|
233
|
+
else current_content_prefix = " " // (TODO风险) 无 `- `,则设前缀字符数为2 (用户可能用tab的1和四空格的4,但少消除2个一般不会影响,主要避免前缀4空格自动转化为缩进代码块)
|
|
234
|
+
}
|
|
235
|
+
if (line.startsWith("\t")) line = line.substring(1);
|
|
236
|
+
else if (line.startsWith(current_content_prefix)) { // 子内容前缀去除
|
|
237
|
+
line = line.substring(current_content_prefix.length);
|
|
238
|
+
}
|
|
239
|
+
current_content += line+"\n" // 子内容拼接
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
add_current_content()
|
|
243
|
+
return list_itemInfo
|
|
244
|
+
|
|
245
|
+
function add_current_content(){ // 刷新写入缓存的尾调用
|
|
246
|
+
if (current_content.trim()=="") return
|
|
247
|
+
list_itemInfo.push({
|
|
248
|
+
content: current_content,
|
|
249
|
+
level: 1
|
|
250
|
+
})
|
|
251
|
+
current_content = ""
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* 标题大纲转列表数据
|
|
257
|
+
*
|
|
258
|
+
* @detail
|
|
259
|
+
* 为什么要直接转,而不能title2list来复用
|
|
260
|
+
* 因为title2list会损失标题信息
|
|
261
|
+
*/
|
|
262
|
+
static title2c2data(text: string){
|
|
263
|
+
const list_itemInfo:List_C2ListItem = []
|
|
264
|
+
const list_text = text.trimStart().split("\n")
|
|
265
|
+
|
|
266
|
+
// 获取最大的标题级别
|
|
267
|
+
const first_match = list_text[0].match(ABReg.reg_heading_noprefix)
|
|
268
|
+
if (!first_match || first_match[1]) {
|
|
269
|
+
console.error("不是标题内容:", list_text[0])
|
|
270
|
+
return list_itemInfo
|
|
271
|
+
}
|
|
272
|
+
const root_title_level:number = first_match[3].length-1 // 第一个标题(也是最大级别的标题的)的`#`的个数
|
|
273
|
+
|
|
274
|
+
// 循环填充
|
|
275
|
+
let current_content:string = ""
|
|
276
|
+
let codeBlockFlag = ''
|
|
277
|
+
for (const line of list_text) {
|
|
278
|
+
// heading和mdit类型 需要跳过代码块内的结束标志
|
|
279
|
+
if (codeBlockFlag == '') {
|
|
280
|
+
const match = line.match(ABReg.reg_code)
|
|
281
|
+
if (match && match[3]) {
|
|
282
|
+
codeBlockFlag = match[1]+match[3]
|
|
283
|
+
current_content += line+"\n"; continue
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
if (line.indexOf(codeBlockFlag) == 0) codeBlockFlag = ''
|
|
288
|
+
current_content += line+"\n"; continue
|
|
289
|
+
|
|
290
|
+
}
|
|
291
|
+
//
|
|
292
|
+
const match_heading = line.match(ABReg.reg_heading_noprefix)
|
|
293
|
+
if (match_heading && !match_heading[1] && (match_heading[3].length-1)<=root_title_level){ // 遇到同等标题
|
|
294
|
+
add_current_content()
|
|
295
|
+
list_itemInfo.push({
|
|
296
|
+
content: match_heading[4],
|
|
297
|
+
level: 0
|
|
298
|
+
})
|
|
299
|
+
} else {
|
|
300
|
+
current_content += line+"\n"
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
add_current_content()
|
|
304
|
+
return list_itemInfo
|
|
305
|
+
|
|
306
|
+
function add_current_content(){ // 刷新写入缓存的尾调用
|
|
307
|
+
if (current_content.trim()=="") return
|
|
308
|
+
list_itemInfo.push({
|
|
309
|
+
content: current_content,
|
|
310
|
+
level: 1
|
|
311
|
+
})
|
|
312
|
+
current_content = ""
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 两列列表数据转标签栏
|
|
318
|
+
*/
|
|
319
|
+
static c2data2tab(
|
|
320
|
+
list_itemInfo: List_C2ListItem,
|
|
321
|
+
div: HTMLDivElement,
|
|
322
|
+
modeT: boolean
|
|
323
|
+
){
|
|
324
|
+
const tab = document.createElement("div"); div.appendChild(tab); tab.classList.add("ab-tab-root");
|
|
325
|
+
if (modeT) tab.setAttribute("modeT", "true")
|
|
326
|
+
const nav = document.createElement("div"); tab.appendChild(nav); nav.classList.add("ab-tab-nav");
|
|
327
|
+
const content = document.createElement("div"); tab.appendChild(content); content.classList.add("ab-tab-content")
|
|
328
|
+
let current_dom:HTMLElement|null = null
|
|
329
|
+
for (let i=0; i<list_itemInfo.length; i++){
|
|
330
|
+
const item = list_itemInfo[i]
|
|
331
|
+
// b1. item标题,顺便创建空内容
|
|
332
|
+
if (item.level==0) {
|
|
333
|
+
const nav_item = document.createElement("button"); nav.appendChild(nav_item); nav_item.classList.add("ab-tab-nav-item");
|
|
334
|
+
nav_item.setAttribute("is_activate", i==0?"true":"false");
|
|
335
|
+
nav_item.setAttribute("data_index", i.toString()); // data_index 用于方便从数组中删除
|
|
336
|
+
nav_item.textContent = item.content.slice(0,20);
|
|
337
|
+
|
|
338
|
+
current_dom = document.createElement("div"); content.appendChild(current_dom); current_dom.classList.add("ab-tab-content-item");
|
|
339
|
+
current_dom.setAttribute("style", i==0?"display:block":"display:none"); current_dom.setAttribute("is_activate", i==0?"true":"false");
|
|
340
|
+
}
|
|
341
|
+
// b2. item内容,在空内容的基础上填充
|
|
342
|
+
else if (current_dom) {
|
|
343
|
+
current_dom.setAttribute("data_index", i.toString()); // data_index 用于方便从数组中删除
|
|
344
|
+
ABConvertManager.getInstance().m_renderMarkdownFn(item.content, current_dom)
|
|
345
|
+
current_dom = null
|
|
346
|
+
}
|
|
347
|
+
// b3. item内容之前没有item标题,不合法,跳过
|
|
348
|
+
else {
|
|
349
|
+
continue
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// 动态部分
|
|
354
|
+
// 元素全部创建完再来绑按钮事件,不然会有问题
|
|
355
|
+
const lis:NodeListOf<HTMLButtonElement> = tab.querySelectorAll(":scope>.ab-tab-nav>.ab-tab-nav-item")
|
|
356
|
+
const contents = tab.querySelectorAll(":scope>.ab-tab-content>.ab-tab-content-item")
|
|
357
|
+
if (lis.length!=contents.length) console.warn("ab-tab-nav-item和ab-tab-content-item的数量不一致")
|
|
358
|
+
for (let i=0; i<lis.length; i++){
|
|
359
|
+
// 1. 二选一,常规绑定
|
|
360
|
+
// ob选用
|
|
361
|
+
if (ABCSetting.env.startsWith("obsidian")) {
|
|
362
|
+
lis[i].onclick = ()=>{
|
|
363
|
+
for (let j=0; j<contents.length; j++){
|
|
364
|
+
lis[j].setAttribute("is_activate", "false")
|
|
365
|
+
contents[j].setAttribute("is_activate", "false")
|
|
366
|
+
contents[j].setAttribute("style", "display:none")
|
|
367
|
+
}
|
|
368
|
+
lis[i].setAttribute("is_activate", "true")
|
|
369
|
+
contents[i].setAttribute("is_activate", "true")
|
|
370
|
+
contents[i].setAttribute("style", "display:block")
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// 2. 二选一,嵌入内联onclick
|
|
374
|
+
// mdit (vuepress、app) 选用
|
|
375
|
+
else {
|
|
376
|
+
lis[i].setAttribute("onclick",`
|
|
377
|
+
const i = ${i}
|
|
378
|
+
const tab_current = this
|
|
379
|
+
const tab_nav = this.parentNode
|
|
380
|
+
const tab_root = tab_nav.parentNode
|
|
381
|
+
const tab_content = tab_root.querySelector(":scope>.ab-tab-content")
|
|
382
|
+
const tab_nav_items = tab_nav.querySelectorAll(":scope>.ab-tab-nav-item")
|
|
383
|
+
const tab_content_items = tab_content.querySelectorAll(":scope>.ab-tab-content-item")
|
|
384
|
+
for (let j=0; j<tab_content_items.length; j++){
|
|
385
|
+
tab_nav_items[j].setAttribute("is_activate", "false")
|
|
386
|
+
tab_content_items[j].setAttribute("is_activate", "false")
|
|
387
|
+
tab_content_items[j].setAttribute("style", "display:none")
|
|
388
|
+
}
|
|
389
|
+
tab_current.setAttribute("is_activate", "true")
|
|
390
|
+
tab_content_items[i].setAttribute("is_activate", "true")
|
|
391
|
+
tab_content_items[i].setAttribute("style", "display:block")
|
|
392
|
+
`)
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return div
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/// 将二列列表转 `容器-元素` 结构
|
|
400
|
+
static c2data2items(c2listdata:List_C2ListItem, el:HTMLElement): HTMLElement {
|
|
401
|
+
const el_items = document.createElement("div"); el.appendChild(el_items); el_items.classList.add("ab-items")
|
|
402
|
+
let el_item:HTMLElement|null = null;
|
|
403
|
+
for (const item of c2listdata) {
|
|
404
|
+
// b1. item标题
|
|
405
|
+
if (item.level == 0) {
|
|
406
|
+
el_item = document.createElement("div"); el_items.appendChild(el_item); el_item.classList.add("ab-items-item")
|
|
407
|
+
const el_title = document.createElement("div"); el_item.appendChild(el_title); el_title.classList.add("ab-items-title")
|
|
408
|
+
ABConvertManager.getInstance().m_renderMarkdownFn(item.content, el_title)
|
|
409
|
+
}
|
|
410
|
+
// b2. item内容
|
|
411
|
+
else if (el_item) {
|
|
412
|
+
const el_content = document.createElement("div"); el_item.appendChild(el_content); el_content.classList.add("ab-items-content")
|
|
413
|
+
ABConvertManager.getInstance().m_renderMarkdownFn(item.content, el_content)
|
|
414
|
+
}
|
|
415
|
+
// b3. item内容之前没有item标题,不合法,跳过
|
|
416
|
+
else {
|
|
417
|
+
continue
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return el
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const _abc_list2c2listdata = ABConvert.factory({
|
|
425
|
+
id: "list2c2listdata",
|
|
426
|
+
name: "列表转c2listdata",
|
|
427
|
+
match: "list2c2listdata",
|
|
428
|
+
default: "list2c2listdata",
|
|
429
|
+
process_param: ABConvert_IOEnum.text,
|
|
430
|
+
process_return: ABConvert_IOEnum.c2list_stream,
|
|
431
|
+
process: (el, header, content: string): List_C2ListItem=>{
|
|
432
|
+
return C2ListProcess.list2c2data(content)
|
|
433
|
+
}
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
const _abc_title2c2listdata = ABConvert.factory({
|
|
437
|
+
id: "title2c2listdata",
|
|
438
|
+
name: "标题转c2listdata",
|
|
439
|
+
match: "title2c2listdata",
|
|
440
|
+
default: "title2c2listdata",
|
|
441
|
+
process_param: ABConvert_IOEnum.text,
|
|
442
|
+
process_return: ABConvert_IOEnum.c2list_stream,
|
|
443
|
+
process: (el, header, content: string): List_C2ListItem=>{
|
|
444
|
+
return C2ListProcess.title2c2data(content)
|
|
445
|
+
}
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
const _abc_c2listdata2tab = ABConvert.factory({
|
|
449
|
+
id: "c2listdata2tab",
|
|
450
|
+
name: "c2listdata转标签",
|
|
451
|
+
match: "c2listdata2tab",
|
|
452
|
+
default: "c2listdata2tab",
|
|
453
|
+
process_param: ABConvert_IOEnum.c2list_stream,
|
|
454
|
+
process_return: ABConvert_IOEnum.el,
|
|
455
|
+
process: (el, header, content: List_C2ListItem): HTMLElement=>{
|
|
456
|
+
return C2ListProcess.c2data2tab(content, el, false)
|
|
457
|
+
}
|
|
458
|
+
})
|
|
459
|
+
|
|
460
|
+
const _abc_c2listdata2items = ABConvert.factory({
|
|
461
|
+
id: "c2listdata2items",
|
|
462
|
+
name: "c2listdata转容器结构",
|
|
463
|
+
match: "c2listdata2items",
|
|
464
|
+
default: "c2listdata2items",
|
|
465
|
+
process_param: ABConvert_IOEnum.c2list_stream,
|
|
466
|
+
process_return: ABConvert_IOEnum.el,
|
|
467
|
+
process: (el, header, content: List_C2ListItem): HTMLElement=>{
|
|
468
|
+
return C2ListProcess.c2data2items(content, el)
|
|
469
|
+
}
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
const _abc_c2listdata2easytimeline = ABConvert.factory({
|
|
473
|
+
id: "c2listdata2easytimeline",
|
|
474
|
+
name: "适配到easy_timeline",
|
|
475
|
+
match: "c2listdata2easytimeline",
|
|
476
|
+
detail: "适配到easy_timeline格式,需要安装easy timeline插件",
|
|
477
|
+
process_param: ABConvert_IOEnum.c2list_stream,
|
|
478
|
+
process_return: ABConvert_IOEnum.text,
|
|
479
|
+
process: (el, header, content: List_C2ListItem): string=>{
|
|
480
|
+
let all_line = ""
|
|
481
|
+
let line = ""
|
|
482
|
+
for (const item of content) {
|
|
483
|
+
if (item.level == 0) {
|
|
484
|
+
if (line != "") all_line += line + '\n\n'
|
|
485
|
+
line = item.content + '. '
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
if (line == "") line = " . "
|
|
489
|
+
line += item.content
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
// 尾调用
|
|
493
|
+
if (line != "") all_line += line
|
|
494
|
+
|
|
495
|
+
return "````timeline\n"+all_line+"\n````"
|
|
496
|
+
}
|
|
497
|
+
})
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 转换器_代码块版
|
|
3
|
+
*
|
|
4
|
+
* md_str <-> md_str
|
|
5
|
+
*
|
|
6
|
+
* 和 abc_text 类别类似,区别在于,源/目标数据为代码/代码块
|
|
7
|
+
*
|
|
8
|
+
* 注意该类别内容经常伴随两个关键重要别名一起使用:
|
|
9
|
+
* ```ts
|
|
10
|
+
* {regex: "|list2code|", replacement: "|xList|code(js)|"},
|
|
11
|
+
* {regex: "|code2list|", replacement: "|Xcode|region2indent|addList|"},
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { ABReg } from "../ABSetting"
|
|
16
|
+
import { ABConvert, ABConvert_IOEnum } from "./ABConvert"
|
|
17
|
+
|
|
18
|
+
const _abc_region2indent = ABConvert.factory({
|
|
19
|
+
id: "region2indent",
|
|
20
|
+
name: "代码注释转缩进",
|
|
21
|
+
detail: "代码块注释转缩进 (识别 `//` 和 `#` 的region注释对),通常配合code2list使用。默认补充两缩进",
|
|
22
|
+
process_param: ABConvert_IOEnum.text,
|
|
23
|
+
process_return: ABConvert_IOEnum.text,
|
|
24
|
+
process: (el, header, content: string): string=>{
|
|
25
|
+
const lists = content.trimEnd().split("\n")
|
|
26
|
+
let newContent = ''
|
|
27
|
+
// let indent_map: {endFlag: string, indent: string}[] = [] // 缩进表。记录停止标识、区块内需要补充的缩进 (弃用,region自身无关缩进,缩进内容固定加层数*两空格)
|
|
28
|
+
// let indent_map: string[] = [] // 缩进表。下标表示在第几层嵌套,内容表示缩进内容
|
|
29
|
+
let startFlagNumber = 0
|
|
30
|
+
const regionReg: RegExp = /^([ \t]*)(#|\/\/)\s*#?(region|endregion)(.*)/
|
|
31
|
+
for (let i=0; i < lists.length; i++) {
|
|
32
|
+
const item = lists[i]
|
|
33
|
+
const match = item.match(regionReg)
|
|
34
|
+
|
|
35
|
+
// b1. 非region项
|
|
36
|
+
if (!match) {
|
|
37
|
+
newContent += '\n' + ' '.repeat(startFlagNumber) + item
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
// b2. region项
|
|
41
|
+
else {
|
|
42
|
+
if (match[3] == 'region') {
|
|
43
|
+
newContent += '\n' + ' '.repeat(startFlagNumber) + match[4].trimStart()
|
|
44
|
+
startFlagNumber++
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
startFlagNumber--
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return newContent.slice(1) // 去除头部 `\n`
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const _abc_mdit2code = ABConvert.factory({
|
|
57
|
+
id: "mdit2code",
|
|
58
|
+
name: "mdit转代码块",
|
|
59
|
+
detail: "mdit转代码块 (允许嵌套)。注意 `:*n` 会转化为 `~*(n+3)`, `@aaa bbb` 会转换为 `# bbb` (h1标题)",
|
|
60
|
+
process_param: ABConvert_IOEnum.text,
|
|
61
|
+
process_return: ABConvert_IOEnum.text,
|
|
62
|
+
process: (el, header, content: string): string=>{
|
|
63
|
+
const lists = content.trimEnd().split("\n")
|
|
64
|
+
let newContent = ''
|
|
65
|
+
// 不使用缩进表和缩进计数,不进行语法检查
|
|
66
|
+
|
|
67
|
+
for (let i=0; i < lists.length; i++) {
|
|
68
|
+
const item = lists[i]
|
|
69
|
+
const match = item.match(ABReg.reg_mdit_head)
|
|
70
|
+
const match2 = item.trim().match(/^@(\S*?)\s(.*?)$/)
|
|
71
|
+
|
|
72
|
+
// b1. `^@` 项
|
|
73
|
+
if (match2) {
|
|
74
|
+
newContent += '\n' + '# ' + match2[2]
|
|
75
|
+
}
|
|
76
|
+
// b1. `:::` 项
|
|
77
|
+
else if (match) {
|
|
78
|
+
const flag = '~'.repeat(match[3].length + 3)
|
|
79
|
+
if (match[4].trim() !== "") newContent += '\n' + flag + 'anyblock\n[' + match[4].trimStart() + ']' // 头
|
|
80
|
+
else newContent += '\n' + flag // 尾
|
|
81
|
+
continue
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
// b3. 普通
|
|
85
|
+
else {
|
|
86
|
+
newContent += '\n' + item
|
|
87
|
+
continue
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return newContent.slice(1) // 去除头部 `\n`
|
|
92
|
+
}
|
|
93
|
+
})
|