dsh-md-plus 0.4.0 → 0.4.1
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/CHANGELOG.md +14 -1
- package/README.md +3 -3
- package/lib/client.js +174 -29
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
-
## 0.4.
|
|
3
|
+
## 0.4.1 —— 未发布
|
|
4
|
+
|
|
5
|
+
- 修复 DSH 代码块头部只显示占位文案时读不到真实围栏语言、补高亮失效的问题:现在会从宿主的 React fiber 读取真实 `lang`,读不到再退回正文嗅探,并把头部语言名显示成真实语言。
|
|
6
|
+
- 修复 `graph = nx.Graph()`、`pie = 3.14`、`timeline = []` 等普通代码被误判成 mermaid 图的问题:只嗅探第一行有效内容,并排除赋值和调用形态。
|
|
7
|
+
- 修复代码块折叠在 DSH 上不触发:DSH 的代码内容容器是 `display:contents`,插件没有可测量的盒子;现在给代码内容建立真实的块级盒模型。
|
|
8
|
+
- 修复表格吸顶:给表格容器增加纵向滚动上限,表头在容器内滚动时保持可见。
|
|
9
|
+
- 修复卸载/重载后高亮副本、折叠按钮和 `data-md-plus*` 属性残留,避免同一份代码显示两遍,重装后也能重新处理。
|
|
10
|
+
- 修复鼠标滚轮在 1 倍图表上拦截页面滚动:未放大且未按住 Ctrl/Meta 时放行;全屏查看仍可滚轮缩放。
|
|
11
|
+
- 修复切换主题后代码视图中的 mermaid 图不重画的问题。
|
|
12
|
+
- 修复设置面板「恢复默认」把折叠阈值写成 0、代码字号与宿主行高不匹配、字号输入越界后静默回退的问题。
|
|
13
|
+
- 修复 mermaid 渲染失败后仍显示无效缩放/全屏按钮的问题,失败块现在显示「重试」;运行时脚本加载失败也不再永久缓存失败结果。
|
|
14
|
+
- 测试补到 72 条,新增 React fiber 语言识别、mermaid 误判、代码折叠盒模型、卸载清理、滚轮放行、代码视图主题重画、设置默认值等回归用例。
|
|
15
|
+
|
|
16
|
+
## 0.4.0 —— 2026-10-28
|
|
4
17
|
|
|
5
18
|
- Mermaid 全屏工具栏新增「下载 SVG / 下载 PNG」,可以直接把图带进文档或演示文稿。
|
|
6
19
|
- 代码块、表格和 Mermaid 图卡增加长内容折叠:超过阈值显示「展开 / 收起」,避免长日志和长表格撑满聊天。
|
package/README.md
CHANGED
|
@@ -27,18 +27,18 @@ dsh plugin --profile desktop remove dsh-md-plus
|
|
|
27
27
|
```powershell
|
|
28
28
|
npm install # 顺带跑 prepare → build
|
|
29
29
|
npm run build # 产出 lib/ 下四个文件
|
|
30
|
-
npm run check # 语法检查 +
|
|
30
|
+
npm run check # 语法检查 + 72 条测试(先 build 再跑,check 不含 build)
|
|
31
31
|
npm run preview # 生成 preview.html(含真渲出来的 mermaid 图)
|
|
32
32
|
npm run shot # 用 headless Chrome 把 preview.html 截成 docs/preview.png
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
## 已知限制
|
|
36
36
|
|
|
37
|
-
- DSH 0.2.
|
|
37
|
+
- DSH 0.2.1-rc.4 的头部语言名由宿主决定:不认识的围栏只显示占位文案「代码块」。插件会从宿主的 React fiber 里兜底读取真实语言,读不到时才退回正文嗅探;宿主改 React 结构后这条兜底可能失效。
|
|
38
38
|
- `DSH_LANGS` 是 DSH 语言表的快照(108 条)。宿主加语言后这份快照会落后,落后只会多一次无效处理,不会出现双份高亮。
|
|
39
39
|
- mermaid 12 的新图种(`usecase-beta`、`agentflow-beta`)标识符只认字母数字下划线,中文得写进标签:`actor Customer("用户")` 可以,`actor 用户` 会解析失败。
|
|
40
40
|
- 高亮约 6.4 MB、mermaid 约 5.0 MB,按需下载,第一次用到时多花约 100ms 解析。
|
|
41
|
-
- 依赖宿主 `.md-code-block`、`[data-code-block-content]`、`[data-code-block-banner]`、`data-streaming`
|
|
41
|
+
- 依赖宿主 `.md-code-block`、`[data-code-block-content]`、`[data-code-block-banner]`、`data-streaming` 等钩子,以及 React fiber 里的 `lang`;DSH 改版后要同步调整 `src/client.js`。
|
|
42
42
|
|
|
43
43
|
目前只影响代码块、mermaid、表格、正文图片和显示设置,不改 Markdown 的解析结果。
|
|
44
44
|
|
package/lib/client.js
CHANGED
|
@@ -26,6 +26,7 @@ window.__ModuleLoader__.load({
|
|
|
26
26
|
var ZOOM_MIN_EPSILON = 1e-3;
|
|
27
27
|
var EXPAND_CLASS = "md-plus-expand";
|
|
28
28
|
var THEME_CLASS = "md-plus-theme";
|
|
29
|
+
var RETRY_CLASS = "md-plus-retry";
|
|
29
30
|
var THEME_KEY = "dsh-md-plus-mermaid-theme";
|
|
30
31
|
var THEME_ORDER = ["blue", "neutral", "forest", "contrast"];
|
|
31
32
|
var THEME_LABELS = {
|
|
@@ -56,6 +57,8 @@ window.__ModuleLoader__.load({
|
|
|
56
57
|
themePrefix: "\u914D\u8272\uFF1A",
|
|
57
58
|
foldOpen: "\u5C55\u5F00",
|
|
58
59
|
foldClose: "\u6536\u8D77",
|
|
60
|
+
retry: "\u91CD\u8BD5",
|
|
61
|
+
retryAria: "\u91CD\u65B0\u6E32\u67D3\u56FE\u8868",
|
|
59
62
|
renderFailed: "mermaid \u6E32\u67D3\u5931\u8D25\uFF1A",
|
|
60
63
|
diagram: "\u6D41\u7A0B\u56FE",
|
|
61
64
|
diagramAria: "\u6D41\u7A0B\u56FE\u5168\u5C4F\u67E5\u770B",
|
|
@@ -107,6 +110,8 @@ window.__ModuleLoader__.load({
|
|
|
107
110
|
themePrefix: "Theme: ",
|
|
108
111
|
foldOpen: "Expand",
|
|
109
112
|
foldClose: "Collapse",
|
|
113
|
+
retry: "Retry",
|
|
114
|
+
retryAria: "Retry diagram",
|
|
110
115
|
renderFailed: "Mermaid render failed: ",
|
|
111
116
|
diagram: "Diagram",
|
|
112
117
|
diagramAria: "Diagram fullscreen viewer",
|
|
@@ -207,8 +212,13 @@ window.__ModuleLoader__.load({
|
|
|
207
212
|
}
|
|
208
213
|
function applyCodeFontSize() {
|
|
209
214
|
var size = readSettings().codeFontSize;
|
|
210
|
-
if (size > 0)
|
|
211
|
-
|
|
215
|
+
if (size > 0) {
|
|
216
|
+
document.documentElement.style.setProperty("--md-plus-code-font-size", size + "px");
|
|
217
|
+
document.documentElement.style.setProperty("--md-plus-code-line-height", Math.round(size * 1.6) + "px");
|
|
218
|
+
} else {
|
|
219
|
+
document.documentElement.style.removeProperty("--md-plus-code-font-size");
|
|
220
|
+
document.documentElement.style.removeProperty("--md-plus-code-line-height");
|
|
221
|
+
}
|
|
212
222
|
}
|
|
213
223
|
var DSH_LANGS = /* @__PURE__ */ new Set([
|
|
214
224
|
"typescript",
|
|
@@ -321,7 +331,10 @@ window.__ModuleLoader__.load({
|
|
|
321
331
|
"gradle"
|
|
322
332
|
]);
|
|
323
333
|
var MMD_LANGS = /* @__PURE__ */ new Set(["mermaid", "mermaidjs", "mmd"]);
|
|
324
|
-
var
|
|
334
|
+
var MMD_FLOW = /^\s*(flowchart|graph)(?:\s+(?:TD|TB|BT|RL|LR))?\s*;?\s*$/i;
|
|
335
|
+
var MMD_PIE = /^\s*pie(?:\s+title\b.*)?\s*;?\s*$/i;
|
|
336
|
+
var MMD_GIT = /^\s*gitGraph(?:\s+(?:LR|TB|BT|RL))?:?\s*;?\s*$/i;
|
|
337
|
+
var MMD_SINGLE = /^\s*(sequenceDiagram|classDiagram|stateDiagram(?:-v2)?|erDiagram|journey|gantt|mindmap|timeline|quadrantChart|xychart-beta|sankey-beta|block-beta|packet-beta|architecture-beta|usecase-beta|agentflow-beta|C4Context|requirementDiagram|kanban|radar|treemap|venn|ishikawa|wardley|cynefin|treeView|zenuml)\s*;?\s*$/i;
|
|
325
338
|
function icon(paths) {
|
|
326
339
|
var svg = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'>" + paths + "</svg>";
|
|
327
340
|
return 'url("data:image/svg+xml,' + encodeURIComponent(svg) + '")';
|
|
@@ -350,6 +363,9 @@ window.__ModuleLoader__.load({
|
|
|
350
363
|
var ICON_THEME = icon(
|
|
351
364
|
"<path d='M12 3s5 5.5 5 9a5 5 0 0 1-10 0c0-3.5 5-9 5-9z'/><path d='M9.5 12a2.5 2.5 0 0 0 5 0'/>"
|
|
352
365
|
);
|
|
366
|
+
var ICON_RETRY = icon(
|
|
367
|
+
"<path d='M20 11a8 8 0 1 0-2.34 5.66'/><path d='M20 4v7h-7'/>"
|
|
368
|
+
);
|
|
353
369
|
var ICON_GEAR = icon(
|
|
354
370
|
"<circle cx='12' cy='12' r='3'/><path d='M19.4 15a1.7 1.7 0 0 0 .34 1.87l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.7 1.7 0 0 0-1.87-.34 1.7 1.7 0 0 0-1 1.55V21a2 2 0 1 1-4 0v-.09a1.7 1.7 0 0 0-1.11-1.55 1.7 1.7 0 0 0-1.87.34l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.7 1.7 0 0 0 4.6 15a1.7 1.7 0 0 0-1.55-1H3a2 2 0 1 1 0-4h.09a1.7 1.7 0 0 0 1.55-1.11 1.7 1.7 0 0 0-.34-1.87l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.7 1.7 0 0 0 9 4.6a1.7 1.7 0 0 0 1-1.55V3a2 2 0 1 1 4 0v.09a1.7 1.7 0 0 0 1 1.55 1.7 1.7 0 0 0 1.87-.34l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.7 1.7 0 0 0 19.4 9c.14.36.48.6.87.61H21a2 2 0 1 1 0 4h-.09a1.7 1.7 0 0 0-1.55 1z'/>"
|
|
355
371
|
);
|
|
@@ -358,7 +374,7 @@ window.__ModuleLoader__.load({
|
|
|
358
374
|
var TABLE_VARS_DARK = "--md-plus-tbl-line:#2f2f2f;--md-plus-tbl-head:#1f1f1f;--md-plus-tbl-head-fg:#f9fafb;--md-plus-tbl-hover:#1f1f1f";
|
|
359
375
|
var CSS = [
|
|
360
376
|
// ── 卡片:整块一个底色,顶栏不再是独立色带 ──────────────────────
|
|
361
|
-
".md-code-block{--md-plus-mmd-min-height:200px;--md-plus-icon:" + ICON_CODE + ";--md-plus-icon-copy:" + ICON_COPY + ";--md-plus-icon-nowrap:" + ICON_NOWRAP + ";--md-plus-icon-diagram:" + ICON_DIAGRAM + ";--md-plus-icon-zoom-in:" + ICON_ZOOM_IN + ";--md-plus-icon-zoom-out:" + ICON_ZOOM_OUT + ";--md-plus-icon-expand:" + ICON_EXPAND + ";--md-plus-icon-theme:" + ICON_THEME + "}",
|
|
377
|
+
".md-code-block{--md-plus-mmd-min-height:200px;--md-plus-icon:" + ICON_CODE + ";--md-plus-icon-copy:" + ICON_COPY + ";--md-plus-icon-nowrap:" + ICON_NOWRAP + ";--md-plus-icon-diagram:" + ICON_DIAGRAM + ";--md-plus-icon-zoom-in:" + ICON_ZOOM_IN + ";--md-plus-icon-zoom-out:" + ICON_ZOOM_OUT + ";--md-plus-icon-expand:" + ICON_EXPAND + ";--md-plus-icon-theme:" + ICON_THEME + ";--md-plus-icon-retry:" + ICON_RETRY + "}",
|
|
362
378
|
// bannerWrap 的原底色是 --dsw-alias-bg-base(#fff),会跟卡片灰拉开一条带
|
|
363
379
|
".md-code-block > div:has(> " + BANNER + "){background:transparent}",
|
|
364
380
|
// ── 头部:收紧,并把空着的左边填上 ─────────────────────────────
|
|
@@ -375,6 +391,9 @@ window.__ModuleLoader__.load({
|
|
|
375
391
|
// pre 的行高本身就在首行文字上方留了约半行空白;补 6px 后实测间距约 17px
|
|
376
392
|
// (原来给 0 时只有 11px,贴着看太挤)
|
|
377
393
|
".md-code-block pre{padding:6px 16px 16px;font-size:var(--md-plus-code-font-size,inherit)}",
|
|
394
|
+
".md-code-block pre{line-height:var(--md-plus-code-line-height,inherit)}",
|
|
395
|
+
// DSH 0.2.1 把内容容器设成 display:contents,折叠需要真实的盒子才能量高度和裁剪
|
|
396
|
+
".md-code-block > [data-code-block-content]{display:block}",
|
|
378
397
|
// ── 头部按钮:文字换成图标 ──────────────────────────────────────
|
|
379
398
|
".md-code-block " + BANNER + " button{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;padding:0;border:0;border-radius:6px;font-size:0;cursor:pointer;background:transparent;color:var(--dsw-alias-label-tertiary);transition:background-color .12s ease,color .12s ease}",
|
|
380
399
|
// font-size:0 只藏住「复制 / 已复制」的字面,可访问名仍在
|
|
@@ -393,6 +412,7 @@ window.__ModuleLoader__.load({
|
|
|
393
412
|
".md-code-block " + BANNER + " ." + ZOOM_OUT_CLASS + "::before{-webkit-mask:var(--md-plus-icon-zoom-out) center/contain no-repeat;mask:var(--md-plus-icon-zoom-out) center/contain no-repeat}",
|
|
394
413
|
".md-code-block " + BANNER + " ." + EXPAND_CLASS + "::before{-webkit-mask:var(--md-plus-icon-expand) center/contain no-repeat;mask:var(--md-plus-icon-expand) center/contain no-repeat}",
|
|
395
414
|
".md-code-block " + BANNER + " ." + THEME_CLASS + "::before{-webkit-mask:var(--md-plus-icon-theme) center/contain no-repeat;mask:var(--md-plus-icon-theme) center/contain no-repeat}",
|
|
415
|
+
".md-code-block " + BANNER + " ." + RETRY_CLASS + "::before{-webkit-mask:var(--md-plus-icon-retry) center/contain no-repeat;mask:var(--md-plus-icon-retry) center/contain no-repeat}",
|
|
396
416
|
"[" + MMD_ATTR + '="diagram"] .' + TOGGLE_CLASS + "{color:var(--dsw-alias-button-primary-fill,#4c6ef5);background:var(--dsw-alias-interactive-bg-active,rgb(76 110 245 / 12%))}",
|
|
397
417
|
// 已经到最小 / 最大时,对应那颗按钮变淡且不可点
|
|
398
418
|
"[" + ZOOM_ATTR + '="min"] .' + ZOOM_OUT_CLASS + ",[" + ZOOM_ATTR + '="max"] .' + ZOOM_IN_CLASS + "{opacity:.3;pointer-events:none}",
|
|
@@ -460,7 +480,7 @@ window.__ModuleLoader__.load({
|
|
|
460
480
|
// 抓手用结构选择器而不是 DSH 的哈希类名:外层是「唯一子元素是 table 的 div」。
|
|
461
481
|
// 前面挂 [class*="_markdown_"] 有两个作用——只认 markdown 渲染出来的表格,
|
|
462
482
|
// 同时把特异性顶到 (0,1,4),压过 DSH 自己的 .tableScroll th (0,1,1)。
|
|
463
|
-
TABLE + "{position:relative;margin-block:16px;" + TABLE_VARS + "}",
|
|
483
|
+
TABLE + "{position:relative;margin-block:16px;max-height:min(70vh,720px);overflow-y:auto;overscroll-behavior-y:contain;" + TABLE_VARS + "}",
|
|
464
484
|
"body[data-ds-dark-theme] " + TABLE + "{" + TABLE_VARS_DARK + "}",
|
|
465
485
|
// 整张表一个 1px 边框 + 小圆角。
|
|
466
486
|
// 注意必须是 separate:collapse 模式下 Chrome 会忽略单元格的圆角,
|
|
@@ -524,30 +544,121 @@ window.__ModuleLoader__.load({
|
|
|
524
544
|
script.src = url;
|
|
525
545
|
script.async = true;
|
|
526
546
|
script.setAttribute(RUNTIME_ATTR, "1");
|
|
527
|
-
script.addEventListener(
|
|
528
|
-
|
|
547
|
+
script.addEventListener(
|
|
548
|
+
"load",
|
|
549
|
+
() => {
|
|
550
|
+
var api = window[globalName];
|
|
551
|
+
if (api === void 0) scripts.delete(url);
|
|
552
|
+
resolve(api ?? null);
|
|
553
|
+
},
|
|
554
|
+
{ once: true }
|
|
555
|
+
);
|
|
556
|
+
script.addEventListener(
|
|
557
|
+
"error",
|
|
558
|
+
() => {
|
|
559
|
+
scripts.delete(url);
|
|
560
|
+
script.remove();
|
|
561
|
+
resolve(null);
|
|
562
|
+
},
|
|
563
|
+
{ once: true }
|
|
564
|
+
);
|
|
529
565
|
document.head.appendChild(script);
|
|
530
566
|
});
|
|
531
567
|
scripts.set(url, promise);
|
|
532
568
|
return promise;
|
|
533
569
|
}
|
|
534
|
-
function
|
|
570
|
+
function readBannerLabel(block) {
|
|
535
571
|
var banner = block.querySelector(BANNER);
|
|
536
|
-
var info = banner?.firstElementChild;
|
|
572
|
+
var info = banner?.querySelector('[class*="_language_"]') ?? banner?.firstElementChild;
|
|
537
573
|
return (info?.textContent ?? "").trim().toLowerCase();
|
|
538
574
|
}
|
|
575
|
+
var PLACEHOLDER_LABELS = /* @__PURE__ */ new Set(["", "\u4EE3\u7801\u5757", "code block", "code", "plain text", "plaintext", "\u7EAF\u6587\u672C"]);
|
|
576
|
+
var FIBER_KEY = "__reactFiber$";
|
|
577
|
+
function isPlaceholderLabel(label) {
|
|
578
|
+
return PLACEHOLDER_LABELS.has(label);
|
|
579
|
+
}
|
|
580
|
+
function readFiberLang(block) {
|
|
581
|
+
var info = null;
|
|
582
|
+
var nodes = [block, block.querySelector(CONTENT)];
|
|
583
|
+
for (var node of nodes) {
|
|
584
|
+
if (node === null || node === void 0) continue;
|
|
585
|
+
var names;
|
|
586
|
+
try {
|
|
587
|
+
names = Object.getOwnPropertyNames(node);
|
|
588
|
+
} catch {
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
for (var name of names) {
|
|
592
|
+
if (name.lastIndexOf(FIBER_KEY, 0) !== 0) continue;
|
|
593
|
+
var fiber = node[name];
|
|
594
|
+
for (var depth = 0; fiber !== null && fiber !== void 0 && depth < 24; depth += 1) {
|
|
595
|
+
var props = fiber.memoizedProps;
|
|
596
|
+
if (props !== null && typeof props === "object" && Object.prototype.hasOwnProperty.call(props, "lang")) {
|
|
597
|
+
var value = typeof props.lang === "string" ? props.lang.trim().toLowerCase() : "";
|
|
598
|
+
info = { hasLang: value !== "", lang: value };
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
fiber = fiber.return;
|
|
602
|
+
}
|
|
603
|
+
if (info !== null) break;
|
|
604
|
+
}
|
|
605
|
+
if (info !== null) break;
|
|
606
|
+
}
|
|
607
|
+
return info;
|
|
608
|
+
}
|
|
609
|
+
function readLang(block) {
|
|
610
|
+
var label = readBannerLabel(block);
|
|
611
|
+
if (!isPlaceholderLabel(label)) return label;
|
|
612
|
+
var info = readFiberLang(block);
|
|
613
|
+
return info === null ? "" : info.lang;
|
|
614
|
+
}
|
|
615
|
+
function paintLanguageLabel(block, lang) {
|
|
616
|
+
if (lang === "") return;
|
|
617
|
+
var banner = block.querySelector(BANNER);
|
|
618
|
+
var heading = banner?.firstElementChild;
|
|
619
|
+
if (heading === null || heading === void 0) return;
|
|
620
|
+
var target = banner.querySelector('[class*="_language_"]') ?? heading;
|
|
621
|
+
if ((target.textContent ?? "").trim().toLowerCase() === lang) return;
|
|
622
|
+
if (!target.hasAttribute("data-md-plus-original-label")) {
|
|
623
|
+
target.setAttribute("data-md-plus-original-label", target.textContent ?? "");
|
|
624
|
+
}
|
|
625
|
+
target.textContent = lang;
|
|
626
|
+
target.setAttribute("data-md-plus-lang", lang);
|
|
627
|
+
}
|
|
539
628
|
function sniffDiagramType(code) {
|
|
540
|
-
var
|
|
629
|
+
var lines = code.split("\n");
|
|
630
|
+
var start = 0;
|
|
631
|
+
while (start < lines.length) {
|
|
632
|
+
var line = lines[start].trim();
|
|
633
|
+
if (line === "" || line.startsWith("%%")) {
|
|
634
|
+
start += 1;
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
var text = lines.slice(start).join("\n");
|
|
541
640
|
if (text.startsWith("---")) {
|
|
542
641
|
var blank = text.indexOf("\n");
|
|
543
642
|
var close = blank < 0 ? -1 : text.indexOf("\n---", blank);
|
|
544
643
|
text = close < 0 ? "" : text.slice(close + 4);
|
|
545
644
|
}
|
|
546
|
-
var
|
|
547
|
-
|
|
645
|
+
var first = text.split("\n").find((line2) => {
|
|
646
|
+
var value2 = line2.trim();
|
|
647
|
+
return value2 !== "" && !value2.startsWith("%%");
|
|
648
|
+
});
|
|
649
|
+
if (first === void 0) return null;
|
|
650
|
+
var value = first.trim();
|
|
651
|
+
var flow = MMD_FLOW.exec(value);
|
|
652
|
+
if (flow !== null) return flow[1];
|
|
653
|
+
if (MMD_PIE.test(value)) return "pie";
|
|
654
|
+
if (MMD_GIT.test(value)) return "gitGraph";
|
|
655
|
+
var single = MMD_SINGLE.exec(value);
|
|
656
|
+
return single === null ? null : single[1];
|
|
548
657
|
}
|
|
549
658
|
function diagramKind(block) {
|
|
550
|
-
|
|
659
|
+
var lang = readLang(block);
|
|
660
|
+
if (MMD_LANGS.has(lang)) return "diagram";
|
|
661
|
+
if (lang !== "") return null;
|
|
551
662
|
var pre = block.querySelector(CONTENT + " pre");
|
|
552
663
|
if (pre === null) return null;
|
|
553
664
|
return sniffDiagramType(pre.textContent ?? "") === null ? null : "diagram";
|
|
@@ -599,7 +710,8 @@ window.__ModuleLoader__.load({
|
|
|
599
710
|
}
|
|
600
711
|
}
|
|
601
712
|
function redrawDiagrams() {
|
|
602
|
-
for (const block of document.querySelectorAll("[" + MMD_ATTR +
|
|
713
|
+
for (const block of document.querySelectorAll("[" + MMD_ATTR + "]")) {
|
|
714
|
+
if (block.getAttribute(MMD_ATTR) === "failed") continue;
|
|
603
715
|
block.removeAttribute(KEY_ATTR);
|
|
604
716
|
pending.add(block);
|
|
605
717
|
}
|
|
@@ -646,6 +758,19 @@ window.__ModuleLoader__.load({
|
|
|
646
758
|
run: (block) => cycleMermaidTheme(block)
|
|
647
759
|
}
|
|
648
760
|
];
|
|
761
|
+
var FAILED_BUTTONS = [
|
|
762
|
+
{
|
|
763
|
+
cls: RETRY_CLASS,
|
|
764
|
+
titleKey: "retry",
|
|
765
|
+
ariaKey: "retryAria",
|
|
766
|
+
run: (block) => {
|
|
767
|
+
block.removeAttribute(KEY_ATTR);
|
|
768
|
+
block.removeAttribute(MMD_ATTR);
|
|
769
|
+
block.querySelector("." + MMD_CLASS + "-error")?.remove();
|
|
770
|
+
void enhance(block);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
];
|
|
649
774
|
function findNativeWrap(buttons) {
|
|
650
775
|
if (buttons === void 0) return null;
|
|
651
776
|
for (const button of buttons) {
|
|
@@ -661,7 +786,10 @@ window.__ModuleLoader__.load({
|
|
|
661
786
|
var copy = nativeButtons === void 0 || nativeButtons.length === 0 ? null : nativeButtons[nativeButtons.length - 1];
|
|
662
787
|
var action = copy?.parentElement;
|
|
663
788
|
if (action === null || action === void 0) return;
|
|
664
|
-
var
|
|
789
|
+
var label = readBannerLabel(block);
|
|
790
|
+
var lang = readLang(block);
|
|
791
|
+
if (lang !== "" && isPlaceholderLabel(label)) paintLanguageLabel(block, lang);
|
|
792
|
+
var specs = block.getAttribute(MMD_ATTR) === "failed" ? FAILED_BUTTONS : diagramKind(block) !== null ? MMD_BUTTONS : findNativeWrap(nativeButtons) !== null ? [] : PLAIN_BUTTONS;
|
|
665
793
|
for (const existing of action.querySelectorAll("." + BTN_CLASS)) {
|
|
666
794
|
if (specs.some((spec) => existing.classList.contains(spec.cls))) continue;
|
|
667
795
|
existing.remove();
|
|
@@ -675,9 +803,9 @@ window.__ModuleLoader__.load({
|
|
|
675
803
|
created.title = t(spec.titleKey);
|
|
676
804
|
created.setAttribute("aria-label", t(spec.ariaKey));
|
|
677
805
|
if (spec.cls === THEME_CLASS) {
|
|
678
|
-
var
|
|
679
|
-
created.title =
|
|
680
|
-
created.setAttribute("aria-label",
|
|
806
|
+
var themeText = themeLabel(getMermaidTheme());
|
|
807
|
+
created.title = themeText;
|
|
808
|
+
created.setAttribute("aria-label", themeText);
|
|
681
809
|
}
|
|
682
810
|
created.addEventListener("click", () => spec.run(block));
|
|
683
811
|
action.insertBefore(created, copy);
|
|
@@ -702,11 +830,12 @@ window.__ModuleLoader__.load({
|
|
|
702
830
|
var pre = content.querySelector("pre");
|
|
703
831
|
if (pre === null || pre.classList.contains("shiki")) return;
|
|
704
832
|
var lang = readLang(block);
|
|
705
|
-
if (lang
|
|
833
|
+
if (lang !== "" && isPlaceholderLabel(readBannerLabel(block))) paintLanguageLabel(block, lang);
|
|
706
834
|
if (diagramKind(block) !== null) {
|
|
707
835
|
await renderDiagram(block, content, pre);
|
|
708
836
|
return;
|
|
709
837
|
}
|
|
838
|
+
if (lang === "") return;
|
|
710
839
|
if (DSH_LANGS.has(lang)) return;
|
|
711
840
|
var api = await loadScript(HL_URL, HL_GLOBAL);
|
|
712
841
|
if (api === null || !api.supports(lang)) return;
|
|
@@ -812,6 +941,7 @@ window.__ModuleLoader__.load({
|
|
|
812
941
|
zooms.delete(block);
|
|
813
942
|
paint(block);
|
|
814
943
|
scheduleFold(viewport, foldLimit("diagram"));
|
|
944
|
+
decorate(block);
|
|
815
945
|
}
|
|
816
946
|
var zooms = /* @__PURE__ */ new WeakMap();
|
|
817
947
|
function zoomState(block) {
|
|
@@ -862,11 +992,12 @@ window.__ModuleLoader__.load({
|
|
|
862
992
|
clampPan(block, state);
|
|
863
993
|
paint(block);
|
|
864
994
|
}
|
|
865
|
-
function bindViewport(block, viewport, resetView) {
|
|
995
|
+
function bindViewport(block, viewport, resetView, alwaysZoom) {
|
|
866
996
|
var drag = null;
|
|
867
997
|
viewport.addEventListener(
|
|
868
998
|
"wheel",
|
|
869
999
|
(event) => {
|
|
1000
|
+
if (!alwaysZoom && !event.ctrlKey && !event.metaKey && zoomState(block).scale <= 1.001) return;
|
|
870
1001
|
event.preventDefault();
|
|
871
1002
|
zoomBy(block, event.deltaY < 0 ? ZOOM_STEP : 1 / ZOOM_STEP, event.clientX, event.clientY);
|
|
872
1003
|
},
|
|
@@ -1214,21 +1345,26 @@ window.__ModuleLoader__.load({
|
|
|
1214
1345
|
closeSettings();
|
|
1215
1346
|
}
|
|
1216
1347
|
}
|
|
1217
|
-
function readNumber(input, fallback) {
|
|
1348
|
+
function readNumber(input, fallback, max) {
|
|
1349
|
+
var value = Number(input.value);
|
|
1350
|
+
return Number.isFinite(value) && value >= 0 ? Math.min(max ?? 4e3, Math.round(value)) : fallback;
|
|
1351
|
+
}
|
|
1352
|
+
function readFontSize(input) {
|
|
1218
1353
|
var value = Number(input.value);
|
|
1219
|
-
|
|
1354
|
+
if (!Number.isFinite(value) || value <= 0) return 0;
|
|
1355
|
+
return Math.min(20, Math.max(10, Math.round(value)));
|
|
1220
1356
|
}
|
|
1221
1357
|
resetButton.addEventListener("click", () => {
|
|
1222
1358
|
themeSelect.value = "blue";
|
|
1223
1359
|
fontInput.value = "";
|
|
1224
1360
|
viewSelect.value = DEFAULT_SETTINGS.diagramView;
|
|
1225
|
-
foldCode.value =
|
|
1226
|
-
foldTable.value =
|
|
1227
|
-
foldDiagram.value =
|
|
1361
|
+
foldCode.value = String(DEFAULT_SETTINGS.foldCode);
|
|
1362
|
+
foldTable.value = String(DEFAULT_SETTINGS.foldTable);
|
|
1363
|
+
foldDiagram.value = String(DEFAULT_SETTINGS.foldDiagram);
|
|
1228
1364
|
});
|
|
1229
1365
|
saveButton.addEventListener("click", () => {
|
|
1230
1366
|
saveSettings({
|
|
1231
|
-
codeFontSize:
|
|
1367
|
+
codeFontSize: readFontSize(fontInput),
|
|
1232
1368
|
diagramView: viewSelect.value === "code" ? "code" : "diagram",
|
|
1233
1369
|
foldCode: readNumber(foldCode, DEFAULT_SETTINGS.foldCode),
|
|
1234
1370
|
foldTable: readNumber(foldTable, DEFAULT_SETTINGS.foldTable),
|
|
@@ -1444,7 +1580,7 @@ window.__ModuleLoader__.load({
|
|
|
1444
1580
|
closeButton.addEventListener("click", closeViewer);
|
|
1445
1581
|
document.addEventListener("keydown", onKey, true);
|
|
1446
1582
|
zooms.set(overlay, { scale: 1, x: 0, y: 0, min: ZOOM_MIN_MODAL });
|
|
1447
|
-
bindViewport(overlay, viewport, reset);
|
|
1583
|
+
bindViewport(overlay, viewport, reset, true);
|
|
1448
1584
|
document.documentElement.style.overflow = "hidden";
|
|
1449
1585
|
document.body.appendChild(overlay);
|
|
1450
1586
|
closeButton.focus();
|
|
@@ -1460,6 +1596,7 @@ window.__ModuleLoader__.load({
|
|
|
1460
1596
|
content.appendChild(note);
|
|
1461
1597
|
block.setAttribute(KEY_ATTR, key);
|
|
1462
1598
|
block.setAttribute(MMD_ATTR, "failed");
|
|
1599
|
+
decorate(block);
|
|
1463
1600
|
console.warn("[dsh-md-plus] mermaid \u6E32\u67D3\u5931\u8D25", error);
|
|
1464
1601
|
}
|
|
1465
1602
|
function apply0(ctx) {
|
|
@@ -1484,10 +1621,17 @@ window.__ModuleLoader__.load({
|
|
|
1484
1621
|
document.removeEventListener("click", onDocumentClick, true);
|
|
1485
1622
|
for (const node of injected) node.remove();
|
|
1486
1623
|
injected.clear();
|
|
1624
|
+
for (const node of document.querySelectorAll("." + BTN_CLASS)) node.remove();
|
|
1625
|
+
for (const node of document.querySelectorAll("." + HOST_CLASS)) node.remove();
|
|
1626
|
+
for (const node of document.querySelectorAll("." + FOLD_BTN_CLASS)) node.remove();
|
|
1487
1627
|
for (const node of document.querySelectorAll("[" + FOLD_ATTR + "]")) resetFold(node);
|
|
1488
1628
|
for (const node of document.querySelectorAll("." + TABLE_TOOLS_CLASS)) node.remove();
|
|
1489
|
-
for (const
|
|
1490
|
-
|
|
1629
|
+
for (const attr of [DONE_ATTR, KEY_ATTR, WRAP_ATTR, MMD_ATTR, TABLE_DONE_ATTR, "data-md-plus-lang"]) {
|
|
1630
|
+
for (const node of document.querySelectorAll("[" + attr + "]")) node.removeAttribute(attr);
|
|
1631
|
+
}
|
|
1632
|
+
for (const node of document.querySelectorAll("[data-md-plus-original-label]")) {
|
|
1633
|
+
node.textContent = node.getAttribute("data-md-plus-original-label") ?? node.textContent;
|
|
1634
|
+
node.removeAttribute("data-md-plus-original-label");
|
|
1491
1635
|
}
|
|
1492
1636
|
for (const node of document.querySelectorAll(
|
|
1493
1637
|
"." + MMD_CLASS + ", ." + MMD_CLASS + "-error, ." + MODAL_CLASS + ", ." + IMG_MODAL_CLASS + ", ." + SETTINGS_BTN_CLASS + ", ." + SETTINGS_MODAL_CLASS
|
|
@@ -1496,6 +1640,7 @@ window.__ModuleLoader__.load({
|
|
|
1496
1640
|
}
|
|
1497
1641
|
document.documentElement.style.overflow = "";
|
|
1498
1642
|
document.documentElement.style.removeProperty("--md-plus-code-font-size");
|
|
1643
|
+
document.documentElement.style.removeProperty("--md-plus-code-line-height");
|
|
1499
1644
|
document.querySelector("style[" + STYLE_ATTR + "]")?.remove();
|
|
1500
1645
|
for (const script of document.querySelectorAll("script[" + RUNTIME_ATTR + "]")) {
|
|
1501
1646
|
script.remove();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-md-plus",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Markdown display enhancements for DeepSeek Harness Web: code block restyle, syntax highlighting for languages DSH does not ship, and built-in mermaid diagrams.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|