@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 ADDED
@@ -0,0 +1,298 @@
1
+ /**
2
+ * AnyBlock 别名模块
3
+ *
4
+ * @detail
5
+ *
6
+ * 从职责设计上,该模块分为:
7
+ * - 前处理部分
8
+ * - 后处理部分
9
+ * - 连接自动适配器部分
10
+ *
11
+ * 但从实现上,这里只有第一部分的 “前处理部分”
12
+ *
13
+ * 后两个部分和conveter模块暂时耦合较高,没办法分离
14
+ *
15
+ * 需要注意:别名替换的最后需要删除自己所对应的选择器前缀
16
+ *
17
+ * TODO 思考:别名系统是否可以做成想Converter那样通用的东西,感觉可以深挖
18
+ *
19
+ * 1. obsidian 有 Highlightr-Plugin 插件能全局识别,可以参考
20
+ * 2. 每个栏目可选:匹配则向下传递/终止
21
+ * 3. 局部而非全文,以节约性能损耗 (例如专用于ab块header的转化),当然这个可以通过匹配到header再调用API解决
22
+ * 4. 复杂的变换、替换 (hightlightr所不具备的功能) 这也是 ==该插件叫别名系统而非匹配系统的原因==
23
+ * 5. 正则的子串填空 (类似于搜索拐杖和旧版AB的别名器那样)
24
+ */
25
+
26
+ import {ABReg} from "./ABSetting"
27
+
28
+ /**
29
+ * 指令头转义补全,可配合自然语言转指令
30
+ *
31
+ * @detail
32
+ *
33
+ * De-dependency: 取消对该函数的调用即可
34
+ *
35
+ * 将自然语言指令头,转化为指令头
36
+ *
37
+ * 是否绑定到处理器?旧版本通过alias选项设置,但V3版本不要
38
+ *
39
+ * - 优点
40
+ * - 而是作为一个单独的模块,与实际解耦
41
+ * - 符合原则:关于用于语法糖操作,都应存在一个单独的语法糖模块进行处理,而不应与业务代码耦合
42
+ * - 缺点
43
+ * - 新的处理器声明自然语言触发的语法糖。但是可以通过同时增加 “新的处理器” + “新的自然语言替换” 来解决
44
+ *
45
+ * TODO:
46
+ * - 这些别名系统,需要能够显示出来,应该要用json括一下
47
+ * - 性能优化,如果匹配了再replace,且提前退出
48
+ * - 仅匹配开头会不会性能好点
49
+ *
50
+ * @returns
51
+ * new header
52
+ */
53
+ export function autoABAlias (header:string, selectorName:string, content:string): string{
54
+ // 1. 别名模块 - 严格化。目的是方便仅使用正则而不用splic("|")就能判断识别的是完整的词而不是词的一部分
55
+ if (!header.trimEnd().endsWith("|")) header = header + "|"
56
+ if (!header.trimStart().startsWith("|")) header = "|" + header
57
+
58
+ // 2. 别名模块 - 标注选择类型
59
+ if (selectorName == "mdit") { // `:::`不在正文里,这个判断不到:if (ABReg.reg_mdit_head_noprefix.test(content.trimStart()))
60
+ header = "|:::_140lne" + header.trimStart()
61
+ }
62
+ else if (selectorName == "list" || ABReg.reg_list_noprefix.test(content.trimStart())) {
63
+ header = "|list_140lne" + header
64
+ }
65
+ else if (selectorName == "heading" || ABReg.reg_heading_noprefix.test(content.trimStart())) {
66
+ header = "|heading_140lne" + header
67
+ }
68
+ else if (selectorName == "code" || ABReg.reg_code_noprefix.test(content.trimStart())) {
69
+ header = "|code_140lne" + header
70
+ }
71
+ else if (selectorName == "quote" || ABReg.reg_quote_noprefix.test(content.trimStart())) {
72
+ header = "|quote_140lne" + header
73
+ }
74
+ else if (selectorName == "table" || ABReg.reg_table_noprefix.test(content.trimStart())) {
75
+ header = "|table_140lne" + header
76
+ }
77
+
78
+ // 3. 别名模块 - 别名替换
79
+ for (const item of get_ABAlias_iter()) {
80
+ header = header.replace(item.regex, item.replacement)
81
+ }
82
+ for (const item of ABAlias_json_withSub) { // 特别组,被替换为带子串表示的结果
83
+ header = header.replace(item.regex, (_match, ...groups) => {
84
+ return item.replacement.replace(/\$(\d+)/g, (_, number) => groups[number - 1]??""); // 根据捕获组替换。如果某个组是未定义,那么为空
85
+ });
86
+ }
87
+ for (const item of ABAlias_json_end) { // 保证ABAlias_json内容被扩展后,该部分的替换规则仍处于最后
88
+ header = header.replace(item.regex, item.replacement)
89
+ }
90
+
91
+ return header
92
+ }
93
+
94
+ interface ABAlias_json {
95
+ regex: RegExp|string,
96
+ replacement: string
97
+ }
98
+
99
+ // 允许带参数的部分
100
+ // ~~(这部分的遍历会更耗时间。为了性能考虑,单独拿出来)~~ 并不会影响遍历,只有执行时有一点消耗
101
+ const ABAlias_json_withSub: ABAlias_json[] = [
102
+ // 分下类,排下序
103
+ // `gfm` 就支持五种: note, tip, important, warning, caution
104
+ // `vuepress` 比gfm多了个: info
105
+ // `obsidian` 不完全是gfm超集,其important和tip一样,caution和warning一样
106
+ // note
107
+ // abstract, summary, tldr
108
+ // info
109
+ // todo
110
+ // tip. hint, Important
111
+ // succcess, check, done
112
+ // question, help, faq
113
+ // warning, caution, attention
114
+ // failure, fail, missing
115
+ // danger, error
116
+ // bug
117
+ // example
118
+ // quote, cite
119
+ // `其他` 避免错字, 我之前加过 warn, tips。后面又删了
120
+ { regex: /\|(note|warning|caution|attention|error|info|danger|tip|hint|example|abstract|summary|tldr|quote|cite|todo|success|check|done|important|question|help|faq|failure|fail|missing|bug)([+-]?)(\s.*)?\|/, replacement: "|add([!$1]$2$3)|addQuote|" },
121
+ { regex: /\|(callout|alert) ([^+-\s]+)([+-]?)\s?(.*)\|/, replacement: "|add([!$2]$3 $4)|addQuote|" }, // 注意避免和原上/上面的callout语法冲突,以及自身递归
122
+ ]
123
+
124
+ // mdit块
125
+ const ABAlias_json_mdit: ABAlias_json[] = [
126
+ {regex: /\|:::_140lne\|(2?tabs?|标签页?)\|/, replacement: "|mditTabs|"},
127
+ {regex: "|:::_140lne|demo|", replacement: "|mditDemo|"},
128
+ {regex: "|:::_140lne|abDemo|", replacement: "|mditABDemo|"},
129
+ {regex: /\|:::_140lne\|(2?col|分栏)\|/, replacement: "|mditCol|"},
130
+ {regex: /\|:::_140lne\|(2?card|卡片)\|/, replacement: "|mditCard|"},
131
+ {regex: /\|:::_140lne\|(2?chat|聊天)\|/, replacement: "|mditChat|code(chat)|"},
132
+ ]
133
+
134
+ // 标题块
135
+ const ABAlias_json_title: ABAlias_json[] = [
136
+ {regex: "|title2list|", replacement: "|title2listdata|listdata2strict|listdata2list|"},
137
+
138
+ // title - list&title
139
+ {regex: /\|heading_140lne\|2?(timeline|时间线)\|/, replacement: "|title2timeline|"},
140
+ {regex: /\|heading_140lne\|2?(tabs?|标签页?)\||\|title2tabs?\|/, replacement: "|title2c2listdata|c2listdata2tab|"},
141
+ {regex: /\|heading_140lne\|2?(col|分栏)\||\|title2col\|/, replacement: "|title2c2listdata|c2listdata2items|addClass(ab-col)|"},
142
+ {regex: /\|heading_140lne\|2?(card|卡片)\||\|title2card\|/, replacement: "|title2c2listdata|c2listdata2items|addClass(ab-card)|addClass(ab-lay-vfall)|"},
143
+ {regex: /\|heading_140lne\|2?(nodes?|节点)\||\|(title2node|title2abMindmap)\|/, replacement: "|title2listdata|listdata2strict|listdata2nodes|"},
144
+
145
+ // list - 多叉多层树
146
+ {regex: /\|heading_140lne\|2?(mermaid|flow|流程图)\|/, replacement: "|title2list" + "|list2mermaid|"},
147
+ {regex: /\|heading_140lne\|2?(mehrmaid|mdmermaid)\|/, replacement: "|title2list" + "|list2mehrmaidText|code(mehrmaid)|"},
148
+ {regex: /\|heading_140lne\|2?(puml)?(plantuml|mindmap|脑图|思维导图)\|/, replacement: "|title2list" + "|list2pumlMindmap|"},
149
+ {regex: /\|heading_140lne\|2?(markmap|mdMindmap|md脑图|md思维导图)\|/, replacement: "|title2list" + "|list2markmap|"},
150
+ {regex: /\|heading_140lne\|2?(wbs|(工作)?分解(图|结构))\|/, replacement: "|title2list" + "|list2pumlWBS|"},
151
+ {regex: /\|heading_140lne\|2?(table|multiWayTable|multiCrossTable|表格?|多叉表格?|跨行表格?)\|/, replacement: "|title2list" + "|list2table|"},
152
+
153
+ // list - lt树 (属于多层一叉树)
154
+ {regex: /\|heading_140lne\|2?(lt|listTable|treeTable|listGrid|treeGrid|列表格|树形表格?)\|/, replacement: "|title2list" + "|list2lt|"},
155
+ {regex: /\|heading_140lne\|2?(list|列表)\|/, replacement: "|title2list" + "|list2lt|addClass(ab-listtable-likelist)|"},
156
+ {regex: /\|heading_140lne\|2?(dir|dirTree|目录树?|目录结构)\|/, replacement: "|title2list" + "|list2dt|"},
157
+
158
+ // list - 二层树
159
+ {regex: /\|heading_140lne\|(fakeList|仿列表)\|/, replacement: "|title2list" + "|list2table|addClass(ab-table-fc)|addClass(ab-table-likelist)|"},
160
+ ]
161
+
162
+ // 列表块
163
+ const ABAlias_json_list: ABAlias_json[] = [
164
+ // 特殊
165
+ {regex: "|listXinline|", replacement: "|list2listdata|listdata2strict|listdata2list|"},
166
+ {regex: "|list2task|", replacement: "|list2listdata|listdata2task|listdata2list|"},
167
+ {regex: "|task2", replacement: "|list2listdata|listdata2task|listdata2list|list2"},
168
+
169
+ // list - list&title
170
+ {regex: /\|list_140lne\|2?(timeline|时间线)\|/, replacement: "|list2timeline|"},
171
+ {regex: /\|list_140lne\|2?(tabs?|标签页?)\||\|list2tabs?\|/, replacement: "|list2c2listdata|c2listdata2tab|"},
172
+ {regex: /\|list_140lne\|2?(col|分栏)\||\|list2col\|/, replacement: "|list2c2listdata|c2listdata2items|addClass(ab-col)|"},
173
+ {regex: /\|list_140lne\|2?(card|卡片)\||\|list2card\|/, replacement: "|list2c2listdata|c2listdata2items|addClass(ab-card)|addClass(ab-lay-vfall)|"},
174
+ {regex: /\|list_140lne\|2?(nodes?|节点)\||\|(list2node|list2abMindmap)\|/, replacement: "|list2listdata|listdata2strict|listdata2nodes|"},
175
+
176
+ // list - 多叉多层树
177
+ {regex: /\|list_140lne\|2?(mermaid|flow|流程图)\|/, replacement: "|list2mermaid|"},
178
+ {regex: /\|list_140lne\|2?(mehrmaid|mdmermaid)\|/, replacement: "|list2mehrmaidText|code(mehrmaid)|"},
179
+ {regex: /\|list_140lne\|2?(puml)?(plantuml|mindmap|脑图|思维导图)\|/, replacement: "|list2pumlMindmap|"},
180
+ {regex: /\|list_140lne\|2?(markmap|mdMindmap|md脑图|md思维导图)\|/, replacement: "|list2markmap|"},
181
+ {regex: /\|list_140lne\|2?(wbs|(工作)?分解(图|结构))\|/, replacement: "|list2pumlWBS|"},
182
+ {regex: /\|list_140lne\|2?(table|multiWayTable|multiCrossTable|表格?|多叉表格?|跨行表格?)\|/, replacement: "|list2table|"},
183
+
184
+ // list - lt树 (属于多层一叉树)
185
+ {regex: /\|list_140lne\|2?(lt|listTable|treeTable|listGrid|treeGrid|列表格|树形表格?)\|/, replacement: "|list2lt|"},
186
+ {regex: /\|list_140lne\|2?(list|列表)\|/, replacement: "|list2lt|addClass(ab-listtable-likelist)|"},
187
+ {regex: /\|list_140lne\|2?(dir|dirTree|目录树?|目录结构)\|/, replacement: "|list2dt|"},
188
+
189
+ // list - 二层树
190
+ {regex: /\|list_140lne\|(fakeList|仿列表)\|/, replacement: "|list2table|addClass(ab-table-fc)|addClass(ab-table-likelist)|"},
191
+ ]
192
+
193
+ // 代码块
194
+ const ABAlias_json_code: ABAlias_json[] = [
195
+ {regex: "|code_140lne|X|", replacement: "|xCode|"},
196
+ {regex: "|code_140lne|x|", replacement: "|xCode|"},
197
+ {regex: "|code2list|", replacement: "|xCode|region2indent|addList|"},
198
+ {regex: "|echarts|", replacement: "|xCode|code(echarts)|"}, // 配合 any-block/obsidian-charts 使用
199
+ {regex: "|list2code|", replacement: "|xList|code(js)|"},
200
+ ]
201
+
202
+ // 引用块
203
+ const ABAlias_json_quote: ABAlias_json[] = [
204
+ // {regex: "|quote_140lne|X|", replacement: "|xQuote|"},
205
+ // {regex: "|quote_140lne|x|", replacement: "|xQuote|"},
206
+ ]
207
+
208
+ // 表格块
209
+ const ABAlias_json_table: ABAlias_json[] = [
210
+ ]
211
+
212
+ // 通用,一般是装饰处理器 (易误选,通常最后才执行)
213
+ const ABAlias_json_general: ABAlias_json[] = [
214
+ {regex: "|echarts|", replacement: "|xCode|code(echarts)|"}, // 配合 any-block/obsidian-charts 使用
215
+
216
+ {regex: "|黑幕|", replacement: "|addClass(ab-deco-heimu)|"},
217
+ {regex: "|折叠|", replacement: "|fold|"},
218
+ {regex: "|滚动|", replacement: "|scroll|"},
219
+ {regex: "|超出折叠|", replacement: "|overfold|"},
220
+ {regex: "|转置|", replacement: "|transpose|"},
221
+ {regex: "|T|", replacement: "|transpose|"},
222
+ // 便捷样式
223
+ {regex: "|红字|", replacement: "|addClass(ab-custom-text-red)|"},
224
+ {regex: "|橙字|", replacement: "|addClass(ab-custom-text-orange)|"},
225
+ {regex: "|黄字|", replacement: "|addClass(ab-custom-text-yellow)|"},
226
+ {regex: "|绿字|", replacement: "|addClass(ab-custom-text-green)|"},
227
+ {regex: "|青字|", replacement: "|addClass(ab-custom-text-cyan)|"},
228
+ {regex: "|蓝字|", replacement: "|addClass(ab-custom-text-blue)|"},
229
+ {regex: "|紫字|", replacement: "|addClass(ab-custom-text-purple)|"},
230
+ {regex: "|白字|", replacement: "|addClass(ab-custom-text-white)|"},
231
+ {regex: "|黑字|", replacement: "|addClass(ab-custom-text-black)|"},
232
+ {regex: "|红底|", replacement: "|addClass(ab-custom-bg-red)|"},
233
+ {regex: "|橙底|", replacement: "|addClass(ab-custom-bg-orange)|"},
234
+ {regex: "|黄底|", replacement: "|addClass(ab-custom-bg-yellow)|"},
235
+ {regex: "|绿底|", replacement: "|addClass(ab-custom-bg-green)|"},
236
+ {regex: "|青底|", replacement: "|addClass(ab-custom-bg-cyan)|"},
237
+ {regex: "|蓝底|", replacement: "|addClass(ab-custom-bg-blue)|"},
238
+ {regex: "|紫底|", replacement: "|addClass(ab-custom-bg-purple)|"},
239
+ {regex: "|白底|", replacement: "|addClass(ab-custom-bg-white)|"},
240
+ {regex: "|黑底|", replacement: "|addClass(ab-custom-bg-black)|"},
241
+ {regex: "|靠上|", replacement: "|addClass(ab-custom-dire-top)|"},
242
+ {regex: "|靠下|", replacement: "|addClass(ab-custom-dire-down)|"},
243
+ {regex: "|靠左|", replacement: "|addClass(ab-custom-dire-left)|"},
244
+ {regex: "|靠右|", replacement: "|addClass(ab-custom-dire-right)|"},
245
+ {regex: "|居中|", replacement: "|addClass(ab-custom-dire-center)|"},
246
+ {regex: "|水平居中|", replacement: "|addClass(ab-custom-dire-hcenter)|"},
247
+ {regex: "|垂直居中|", replacement: "|addClass(ab-custom-dire-vcenter)|"},
248
+ {regex: "|两端对齐|", replacement: "|addClass(ab-custom-dire-justify)|"},
249
+ {regex: "|大字|", replacement: "|addClass(ab-custom-font-large)|"},
250
+ {regex: "|超大字|", replacement: "|addClass(ab-custom-font-largex)|"},
251
+ {regex: "|超超大字|", replacement: "|addClass(ab-custom-font-largexx)|"},
252
+ {regex: "|小字|", replacement: "|addClass(ab-custom-font-small)|"},
253
+ {regex: "|超小字|", replacement: "|addClass(ab-custom-font-smallx)|"},
254
+ {regex: "|超超小字|", replacement: "|addClass(ab-custom-font-smallxx)|"},
255
+ {regex: "|加粗|", replacement: "|addClass(ab-custom-font-bold)|"},
256
+ ]
257
+
258
+ //
259
+ // 暂时只支持在开头处替换 (?)
260
+ //
261
+ export const ABAlias_user: ABAlias_json[] = []
262
+
263
+ export const ABAlias_pro: ABAlias_json[] = []
264
+
265
+ export const ABAlias_default: ABAlias_json[] = [
266
+ ...ABAlias_json_mdit,
267
+ ...ABAlias_json_title,
268
+ ...ABAlias_json_list,
269
+ ...ABAlias_json_code,
270
+ ...ABAlias_json_quote,
271
+ ...ABAlias_json_table,
272
+ ...ABAlias_json_general, // 这个放最后
273
+ ]
274
+
275
+ /**
276
+ * 用于遍历所有的数组
277
+ *
278
+ * 会被 info_alias 显示。自定义别名、pro 版别名 也会插入到这
279
+ * 优先级系统: 用户 > pro > ABAlias_json_withSub > 默认,汇总时则写
280
+ *
281
+ * 旧写法: 函数动态组装 [...ABAlias_user, ...ABAlias_pro, ...ABAlias_default]
282
+ * 新写法: 返回迭代器,零拷贝,更节省性能
283
+ */
284
+ export function* get_ABAlias_iter() {
285
+ yield* ABAlias_user
286
+ yield* ABAlias_pro
287
+ yield* ABAlias_default
288
+ }
289
+
290
+ // 最后被替换
291
+ const ABAlias_json_end: ABAlias_json[] = [
292
+ {regex: "|:::_140lne", replacement: ""},
293
+ {regex: "|heading_140lne", replacement: ""},
294
+ {regex: "|list_140lne", replacement: ""},
295
+ {regex: "|code_140lne", replacement: ""},
296
+ {regex: "|qutoe_140lne", replacement: ""},
297
+ {regex: "|table_140lne", replacement: ""},
298
+ ]
@@ -0,0 +1,307 @@
1
+ /**
2
+ * 一些AB块的后触发事件
3
+ *
4
+ * @detail
5
+ * 普通的AB块Dom结构生成后就不需要再动了,而有的AB块需要被完全渲染后再进行一些操作。
6
+ *
7
+ * 这些操作统一注册在此处
8
+ */
9
+
10
+ /**
11
+ * 一些AB块的后触发事件 - css加载完触发
12
+ *
13
+ * @param d 这里有两种可能:
14
+ * - 一是局部刷新,d就是局部的div,此时d必须是 `.ab-replace`,且满足预设结构
15
+ * - 二是全局刷新,当页面加载完成后会自动调一次,d就是document
16
+ * @param isCycle 是否循环定时启动。部分事件允许循环,消耗资源也较小,而部分事件不允许
17
+ * false为初始化启动,或手动按刷新按钮的情况
18
+ */
19
+ export function abConvertEvent(d: Element|Document, isCycle: boolean = false) {
20
+ // 超宽div事件 (仅obsidian),这个事件应该优先处理
21
+ // 寻找 .ab-note .ab-super-width
22
+ if (d.querySelector('.ab-super-width')) {
23
+ // 局部 (仅obsidian)
24
+ const els_note: NodeListOf<Element> = d.querySelectorAll(".ab-note");
25
+ for (const el_note of els_note) {
26
+ if (el_note.classList.contains("ab-super-width") || el_note.querySelector(".ab-super-width")) {
27
+ const el_replace: ParentNode | null | undefined = el_note.parentNode;
28
+ if (el_replace && (el_replace as HTMLElement).classList.contains("ab-replace")) {
29
+ (el_replace as HTMLElement).classList.add("ab-super-width-p");
30
+ }
31
+ }
32
+ }
33
+ // 全局 (仅obsidian),注意这里在docuemnt而非d上寻找
34
+ const els_view: NodeListOf<Element> = document.querySelectorAll(".app-container .workspace-leaf"); // 支持多窗口
35
+ for (const el_view of els_view) {
36
+ (el_view as HTMLElement).style.setProperty('--ab-width-outer', ((el_view as HTMLElement).offsetWidth - 40).toString() + "px"); // 40/2是边距 (必须大于滚动条)
37
+ }
38
+ }
39
+
40
+ // list2nodes,圆弧调整事件
41
+ if (d.querySelector('.ab-nodes-node')) {
42
+ const els_min = document.querySelectorAll(".ab-nodes.min .ab-nodes-node");
43
+ const list_children = d.querySelectorAll(".ab-nodes-node")
44
+ for (const children of list_children) {
45
+ // 元素准备
46
+ const el_content = children.querySelector(".ab-nodes-content") as HTMLElement; if (!el_content) continue
47
+ const el_child = children.querySelector(".ab-nodes-children") as HTMLElement; if (!el_child) continue
48
+ const el_bracket = el_child.querySelector(".ab-nodes-bracket") as HTMLElement; if (!el_bracket) continue
49
+ const el_bracket2 = el_child.querySelector(".ab-nodes-bracket2") as HTMLElement; if (!el_bracket2) continue
50
+ const els_child = el_child.childNodes;
51
+ if (els_child.length < 3) {
52
+ el_bracket.style.setProperty("display", "none")
53
+ el_bracket2.style.setProperty("display", "none")
54
+ continue
55
+ }
56
+ const el_child_first = els_child[2] as HTMLElement;
57
+ const el_child_last = els_child[els_child.length - 1] as HTMLElement;
58
+ const el_child_first_content = el_child_first.querySelector(".ab-nodes-content") as HTMLElement
59
+ const el_child_last_content = el_child_last.querySelector(".ab-nodes-content") as HTMLElement
60
+
61
+ // 参数准备
62
+ // 有两种情况,如果height非零则高度等于 (height) (通常1-1结构会是这种情况),若无则高度等于 (100%-heightToReduce)
63
+ let height = 0;
64
+ let heightToReduce = (el_child_first.offsetHeight + el_child_last.offsetHeight) / 2;
65
+
66
+ // 修改伪类
67
+ if (els_child.length == 3) { // 结构:1-1
68
+ height = (el_child_first_content.offsetHeight-20) > 20 ? (el_child_first_content.offsetHeight-20) : 20
69
+ el_bracket2.style.cssText = `
70
+ height: ${height}px;
71
+ top: calc(50% - ${height/2}px);
72
+ `
73
+ } else { // 结构:1-n
74
+ el_bracket2.style.cssText = `
75
+ height: calc(100% - ${heightToReduce}px);
76
+ top: ${el_child_first.offsetHeight/2}px;
77
+ `
78
+ }
79
+
80
+ // 修改伪类 - min样式版 (注意:不要因为用cssText覆盖而把样式给漏了)
81
+ if (Array.prototype.includes.call(els_min, children)) {
82
+ if (els_child.length == 3) { // 结构:1-1,有圆点
83
+ el_bracket.style.cssText = `
84
+ display: block;
85
+ top: calc(50% + ${el_content.offsetHeight/2}px - 3px);
86
+ clip-path: circle(40% at 50% 40%);
87
+ `
88
+ } else { // 结构:1-n,无圆点,是延长线
89
+ el_bracket.setAttribute("display", "none")
90
+ // el_bracket.style.cssText = `
91
+ // display: block;
92
+ // height: 1px;
93
+ // top: calc(50% + ${el_content.offsetHeight/2}px - 1px);
94
+ // width: 18px; /* 可以溢出点 */
95
+ // left: -20px;
96
+ // border-bottom: 1px solid var(--node-color);
97
+ // clip-path: none;
98
+ // `
99
+ }
100
+
101
+ if (els_child.length == 3 && el_content.offsetHeight == el_child_first_content.offsetHeight) { // 结构:1-1且高度相同,则用横线代替括号
102
+ el_bracket2.style.cssText = `
103
+ height: 1px;
104
+ top: calc(50% + ${el_content.offsetHeight/2}px - 1px);
105
+ width: 18px; /* 可以溢出点 */
106
+ border-radius: 0;
107
+ border: none;
108
+ border-bottom: 1px solid var(--node-color);
109
+ `
110
+ }
111
+ else { // 否则在原有基础上微调即可
112
+ // el_bracket2.style.setProperty("border-radius", "2px 0 0 2px")
113
+ // if (height==0) {
114
+ // el_bracket2.style.setProperty("height", `calc(100% - ${heightToReduce}px + 12px)`); // 原基础+12 (应该要加 el_child_last_content 的半高)
115
+ // } else {
116
+ // el_bracket2.style.setProperty("height", `${height+10}px`); // 原基础+10
117
+ // }
118
+ if (els_child.length == 3) {
119
+ height = el_child_last_content.offsetHeight/2 - el_content.offsetHeight/2;
120
+ el_bracket2.style.setProperty("height", `${height}px`);
121
+ el_bracket2.style.setProperty("top", `calc(50% + ${el_content.offsetHeight/2}px)`);
122
+ el_bracket2.style.setProperty("border-radius", `0 0 0 10px`);
123
+ el_bracket2.style.setProperty("border-top", `0`);
124
+ } else {
125
+ heightToReduce = el_child_first.offsetHeight/2 + el_child_first_content.offsetHeight/2 + el_child_last.offsetHeight/2 - el_child_last_content.offsetHeight/2;
126
+ el_bracket2.style.setProperty("height", `calc(100% - ${heightToReduce}px + 1px)`);
127
+ el_bracket2.style.setProperty("top", `${el_child_first.offsetHeight/2 + el_child_first_content.offsetHeight/2 - 1}px`);
128
+ }
129
+ el_bracket2.style.setProperty("width", "20px");
130
+ }
131
+
132
+ // 下面的内容弃用。存在问题:用canvas的思路应该是不对的,应该参考mehrmaid用svg,还能包裹div
133
+ /*else {
134
+ el_bracket2.style.setProperty("height", `100%`);
135
+ el_bracket2.style.setProperty("top", `0`);
136
+ el_bracket2.style.setProperty("width", `38px`); // 可以溢出点
137
+ el_bracket2.style.setProperty("left", `-20px`);
138
+ el_bracket.style.setProperty("display", "none");
139
+
140
+ const el_canvas: HTMLCanvasElement = document.createElement("canvas"); el_bracket2.appendChild(el_canvas);
141
+ el_canvas.style.setProperty("width", "100%")
142
+ el_canvas.style.setProperty("height", "100%")
143
+ const rect_canvas = el_canvas.getBoundingClientRect()
144
+ const rect_bracket = el_bracket2.getBoundingClientRect()
145
+ const point_bracket = {
146
+ x: rect_bracket.right - rect_canvas.left,
147
+ y: rect_bracket.bottom - rect_canvas.top
148
+ };
149
+ for (let childNode of childNodes) { // TODO 应该跳过前两个,前两个是括号
150
+ const rect_childNode = (childNode as HTMLElement).getBoundingClientRect()
151
+ const point_childNode = {
152
+ x: rect_childNode.right - rect_canvas.left,
153
+ y: rect_childNode.bottom - rect_canvas.top
154
+ }
155
+ // 连线
156
+ const ctx = el_canvas.getContext('2d');
157
+ if (!ctx) continue;
158
+ console.log(".ab-nodes.min 获取 canvas ctx 成功", rect_canvas, rect_bracket, rect_childNode) // canvas和bracket是重合的其实……
159
+ // ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除画布
160
+ ctx.beginPath(); // 开始绘制连线
161
+ ctx.moveTo(point_bracket.x - point_bracket.x, point_bracket.y - point_bracket.x);
162
+ ctx.lineTo(point_childNode.x - point_bracket.x, point_childNode.y - point_bracket.x);
163
+ ctx.strokeStyle = 'green';
164
+ ctx.lineWidth = 2;
165
+ ctx.stroke();
166
+ }
167
+ }*/
168
+ }
169
+ }
170
+ }
171
+
172
+ // tips: 这里说一下items布局的问题,TODO 是有计划将布局方式分开成一个独立的处理器,而部分布局需要js
173
+ // 普通纵向瀑布流: 纯css、有序纵向瀑布流: js
174
+ // 横向瀑布流: 纯css、高精度横向瀑布流: 未实现js
175
+
176
+ // list2card,纵向瀑布流 (等宽瀑布流) 顺序重调事件
177
+ // (通过flag,自动避免重新调用,手动刷新也不会重新调用)
178
+ if (d.querySelector('.ab-items.ab-lay-vfall:not(.js-waterfall):not(.ab-lay-hfall):not(.ab-lay-grid)')) {
179
+ const root_el_list = d.querySelectorAll(".ab-items.ab-lay-vfall:not(.js-waterfall):not(.ab-lay-hfall):not(.ab-lay-grid)")
180
+ for (const root_el of root_el_list) {
181
+ // 1. 准备原元素
182
+ root_el.classList.add("js-waterfall") // 避免:触发两次时,第二次触发会以第一次触发的顺序为基准,再进行调整
183
+ const list_children = root_el.querySelectorAll(".ab-items-item")
184
+ // 计算列数和列宽
185
+ const columnCountTmp = parseInt(window.getComputedStyle(root_el).getPropertyValue('column-count'))
186
+ let columnCount: number;
187
+ if (columnCountTmp && !isNaN(columnCountTmp) && columnCountTmp>0) {
188
+ columnCount = columnCountTmp;
189
+ } else if (root_el.classList.contains("ab-col-auto") && list_children.length<=4) {
190
+ columnCount = list_children.length;
191
+ root_el.classList.add("ab-col"+columnCount)
192
+ }
193
+ else {
194
+ columnCount = 4;
195
+ root_el.classList.add("ab-col"+columnCount)
196
+ }
197
+ // const columnWidth = root_el.clientWidth / columnCount;
198
+
199
+ // 2. 准备高度缓存、元素缓存
200
+ const height_cache:number[] = []; // 缓存每列的当前高度,每次将新元素添加到高度最底的列中
201
+ const el_cache:HTMLElement[][] = [];
202
+ for (let i = 0; i < columnCount; i++) {
203
+ height_cache.push(0);
204
+ el_cache.push([])
205
+ }
206
+
207
+ // 3. 得到顺序数组
208
+ for (const children of list_children) {
209
+ const minValue: number = Math.min.apply(null, height_cache);
210
+ const minIndex: number = height_cache.indexOf(minValue)
211
+ const heightTmp = parseInt(window.getComputedStyle(children).getPropertyValue("height"))
212
+ height_cache[minIndex] += (heightTmp && !isNaN(heightTmp) && heightTmp>0) ? heightTmp : 10;
213
+ el_cache[minIndex].push(children as HTMLElement)
214
+ }
215
+
216
+ // 3.2. 修复特殊情况下的异常:
217
+ // 特殊情况指:当分N列时,若 (length%N != 0 || length%N != N-1),存在问题
218
+ // 或写成这样好理解些:当 (length%(N-1) != N || length%(N-1) != N-1),最后一列会缺好几个时,存在问题
219
+ const fillNumber = columnCount-list_children.length%columnCount
220
+ if (fillNumber!=4) {
221
+ for (let i=0; i<fillNumber; i++) {
222
+ const children = document.createElement("div"); children.classList.add(".ab-items-item.placeholder"); children.setAttribute("style", "height: 20px")
223
+ const minValue: number = Math.min.apply(null, height_cache);
224
+ const minIndex: number = height_cache.indexOf(minValue)
225
+ height_cache[minIndex] += 20
226
+ el_cache[minIndex].push(children as HTMLElement)
227
+ }
228
+ }
229
+
230
+ // 4. 按顺序重新填入元素
231
+ root_el.innerHTML = ""
232
+ for (let i=0; i<columnCount; i++) {
233
+ for (const j of el_cache[i]) {
234
+ root_el.appendChild(j)
235
+ }
236
+ }
237
+ }
238
+ }
239
+
240
+ // xxx2markmap,高度重调事件
241
+ if (!isCycle && d.querySelector('.ab-markmap-div')) {
242
+ const divEl = d as Element;
243
+ let markmapId = '';
244
+ if (divEl.tagName === 'DIV') {
245
+ markmapId = divEl.querySelector('.ab-markmap-div')?.id || '';
246
+ }
247
+ let mindmaps: NodeListOf<HTMLElement>;
248
+ if (markmapId) {
249
+ mindmaps = document.querySelectorAll('#' + markmapId);
250
+ } else {
251
+ mindmaps = document.querySelectorAll('.ab-markmap-div'); // 注意一下这里的选择器
252
+ }
253
+
254
+ for(const el_div of mindmaps) {
255
+ const el_svg: SVGGraphicsElement|null = el_div.querySelector("svg")
256
+ const el_g: SVGGraphicsElement|null|undefined = el_svg?.querySelector("g")
257
+ if (el_svg && el_g) {
258
+ // 获取缩放倍数
259
+ // const transformValue = el_g.getAttribute('transform');
260
+ // if (transformValue && transformValue.indexOf('scale') > -1) {
261
+ // const scaleMatch = transformValue.match(/scale\(([^)]+)\)/);
262
+ // if (scaleMatch) {
263
+ // const scale_old = parseFloat(scaleMatch[1]);
264
+ // ...
265
+ // }
266
+ // }
267
+ const scale_new = el_g.getBBox().height/el_div.offsetWidth;
268
+ el_svg.setAttribute("style", `height:${el_g.getBBox().height*scale_new+40}px`); // 重调容器大小
269
+ // el_g.setAttribute("transform", `translate(20.0,80.0) scale(${scale_new})`) // 重调位置和缩放
270
+ markmap_event(d) // 好像调位置有问题,只能重渲染了……
271
+ }
272
+ }
273
+ }
274
+ }
275
+
276
+ /**
277
+ * 一些AB块的后触发事件 - dom加载完触发 - markmap
278
+ */
279
+ export function markmap_event(d: Element|Document) {
280
+ // xxx2markmap,渲染事件
281
+ if (d.querySelector('.ab-markmap-svg')) {
282
+ console.log(" - markmap_event")
283
+ let script_el: HTMLScriptElement|null = document.querySelector('script[script-id="ab-markmap-script"]');
284
+ if (script_el) script_el.remove();
285
+ const divEl = d as Element;
286
+ let markmapId = '';
287
+ if (divEl.tagName === 'DIV') {
288
+ markmapId = divEl.querySelector('.ab-markmap-svg')?.id || '';
289
+ }
290
+ script_el = document.createElement('script'); document.head.appendChild(script_el);
291
+ script_el.type = "module";
292
+ script_el.setAttribute("script-id", "ab-markmap-script");
293
+ script_el.textContent = `
294
+ import { Markmap, } from 'https://jspm.dev/markmap-view';
295
+ const markmapId = "${markmapId || ''}";
296
+ let mindmaps;
297
+ if (markmapId) {
298
+ mindmaps = document.querySelectorAll('#' + markmapId);
299
+ } else {
300
+ mindmaps = document.querySelectorAll('.ab-markmap-svg'); // 注意一下这里的选择器
301
+ }
302
+ for(const mindmap of mindmaps) {
303
+ mindmap.innerHTML = "";
304
+ Markmap.create(mindmap,null,JSON.parse(mindmap.getAttribute('data-json')));
305
+ }`;
306
+ }
307
+ }