dsh-md-plus 0.4.2 → 0.4.4
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 +15 -1
- package/README.md +3 -1
- package/lib/client.js +39 -9
- package/lib/highlight-runtime.js +1 -1
- package/lib/index.js +23 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
-
## 0.4.
|
|
3
|
+
## 0.4.4 —— 未发布
|
|
4
|
+
|
|
5
|
+
- 修复表格折叠按钮在低阈值和展开/收起后漂移、消失的问题:补齐表格折叠高度规则、重置滚动位置,并给按钮阴影留出空间。
|
|
6
|
+
|
|
7
|
+
## 0.4.3 —— 2026-10-30
|
|
8
|
+
|
|
9
|
+
- 修复补高亮语言映射:`hbs` / `jade` / `tscn` / `tres` 分别使用 handlebars / pug / gdresource 语法着色。
|
|
10
|
+
- 修复 Mermaid 12.1 在占位标签兜底路径下的图种识别:补充 `radar-beta`、`treemap-beta`、`venn-beta`、`ishikawa-beta`、`wardley-beta`、`cynefin-beta`、`treeView-beta`、`flowchart-elk` 等,并去掉无效裸关键字的误判。
|
|
11
|
+
- 修复插件卸载后 debounce 扫描重新插入按钮、设置入口和折叠控件的问题,同时清理 `data-md-plus-zoom` 属性。
|
|
12
|
+
- 修复 localStorage 不可用时设置保存和配色切换连当前会话都不生效的问题。
|
|
13
|
+
- 修复运行时路由 ETag 只依赖文件大小和 mtime、内容更新后仍可能返回 304 的问题。
|
|
14
|
+
- 同步能力展示页和 README 预览图到当前 DSH 样式,并把所有版本引用更新为 0.4.3。
|
|
15
|
+
- 测试补到 78 条,新增别名语言、Mermaid 新图种、卸载清理、localStorage 降级和 ETag 回归用例。
|
|
16
|
+
|
|
17
|
+
## 0.4.2 —— 2026-10-30
|
|
4
18
|
|
|
5
19
|
- 修复鼠标悬浮表格或折叠内容时吞掉页面滚轮:移除表格容器的 `overscroll-behavior` containment,折叠态改为保留横向滚动、纵向 `overflow-y: clip`,并覆盖 DSH 宿主 `.tableScroll` 自带的横向 containment。
|
|
6
20
|
- 修复宽表横向滚动条出现 / 消失时鼠标移入移出表格造成的上下跳动:取消 hover 阶段的 padding 切换,固定底部留白。
|
package/README.md
CHANGED
|
@@ -27,11 +27,13 @@ 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 # 语法检查 + 78 条测试(先 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
|
+
`npm run preview` / `scripts/showcase.mjs` 需要读取 DSH 安装目录里的主题和前端资源;如果本机 DSH 是 `app.asar` 包,请先解包到目录,并把 `DSH_APP_DIR` 指向该目录。
|
|
36
|
+
|
|
35
37
|
## 已知限制
|
|
36
38
|
|
|
37
39
|
- DSH 0.2.1-rc.4 的头部语言名由宿主决定:不认识的围栏只显示占位文案「代码块」。插件会从宿主的 React fiber 里兜底读取真实语言,读不到时才退回正文嗅探;宿主改 React 结构后这条兜底可能失效。
|
package/lib/client.js
CHANGED
|
@@ -178,6 +178,8 @@ window.__ModuleLoader__.load({
|
|
|
178
178
|
var STYLE_ATTR = "data-md-plus-style";
|
|
179
179
|
var RUNTIME_ATTR = "data-md-plus-runtime";
|
|
180
180
|
var DEBOUNCE_MS = 160;
|
|
181
|
+
var memorySettings = null;
|
|
182
|
+
var memoryTheme = null;
|
|
181
183
|
function readSettings() {
|
|
182
184
|
var settings = { ...DEFAULT_SETTINGS };
|
|
183
185
|
try {
|
|
@@ -194,11 +196,14 @@ window.__ModuleLoader__.load({
|
|
|
194
196
|
if (Number.isFinite(value) && value >= 0) settings[key] = Math.min(4e3, Math.round(value));
|
|
195
197
|
}
|
|
196
198
|
}
|
|
199
|
+
memorySettings = { ...settings };
|
|
197
200
|
} catch {
|
|
201
|
+
if (memorySettings !== null) return { ...DEFAULT_SETTINGS, ...memorySettings };
|
|
198
202
|
}
|
|
199
203
|
return settings;
|
|
200
204
|
}
|
|
201
205
|
function saveSettings(next) {
|
|
206
|
+
memorySettings = { ...next };
|
|
202
207
|
try {
|
|
203
208
|
window.localStorage.setItem(SETTINGS_KEY, JSON.stringify(next));
|
|
204
209
|
} catch {
|
|
@@ -331,10 +336,10 @@ window.__ModuleLoader__.load({
|
|
|
331
336
|
"gradle"
|
|
332
337
|
]);
|
|
333
338
|
var MMD_LANGS = /* @__PURE__ */ new Set(["mermaid", "mermaidjs", "mmd"]);
|
|
334
|
-
var MMD_FLOW = /^\s*(flowchart
|
|
335
|
-
var MMD_PIE = /^\s*pie(?:\s+title\b.*)?\s*;?\s*$/i;
|
|
339
|
+
var MMD_FLOW = /^\s*(flowchart(?:-elk)?|graph)(?:\s+(?:TD|TB|BT|RL|LR))?\s*;?\s*$/i;
|
|
340
|
+
var MMD_PIE = /^\s*pie(?:\s+(?:showData|title)\b.*)?\s*;?\s*$/i;
|
|
336
341
|
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
|
|
342
|
+
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-beta|treemap(?:-beta)?|venn-beta|ishikawa(?:-beta)?|wardley-beta|cynefin-beta|treeView-beta|info|eventmodeling|swimlane-beta|railroad-beta|railroad-abnf-beta|railroad-ebnf-beta|railroad-peg-beta)\s*;?\s*$/i;
|
|
338
343
|
function icon(paths) {
|
|
339
344
|
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>";
|
|
340
345
|
return 'url("data:image/svg+xml,' + encodeURIComponent(svg) + '")';
|
|
@@ -446,7 +451,7 @@ window.__ModuleLoader__.load({
|
|
|
446
451
|
// 用 clip 而不是 hidden:hidden 会建立隐形滚动容器,鼠标在折叠内容上滚轮会被它吞掉。
|
|
447
452
|
"." + FOLD_CLASS + "[" + FOLD_ATTR + '="on"]{max-height:var(--md-plus-fold-max-height);overflow:clip}',
|
|
448
453
|
"." + FOLD_BTN_CLASS + "{display:block;white-space:nowrap;margin:8px auto 0;padding:4px 12px;border:1px solid var(--dsw-alias-border-secondary,rgb(127 127 127 / 22%));border-radius:999px;background:var(--dsw-alias-bg-base,#fff);color:var(--dsw-alias-label-primary);font:12px/18px var(--dsw-font-family-sans,system-ui,sans-serif);cursor:pointer;box-shadow:0 2px 8px rgb(0 0 0 / 12%);z-index:2}",
|
|
449
|
-
"." + FOLD_CLASS + "[" + FOLD_ATTR + '="on"] .' + FOLD_BTN_CLASS + "{position:absolute;left:50%;bottom:
|
|
454
|
+
"." + FOLD_CLASS + "[" + FOLD_ATTR + '="on"] .' + FOLD_BTN_CLASS + "{position:absolute;left:50%;bottom:12px;transform:translateX(-50%);margin:0}",
|
|
450
455
|
// ── 图片点击放大 ────────────────────────────────────────────────
|
|
451
456
|
'[class*="_markdown_"] img{cursor:zoom-in}',
|
|
452
457
|
"." + IMG_MODAL_CLASS + "{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;justify-content:center;padding:calc(var(--dsh-windows-titlebar-height,0px) + 16px) 24px 24px;background:rgb(0 0 0 / 72%)}",
|
|
@@ -524,7 +529,9 @@ window.__ModuleLoader__.load({
|
|
|
524
529
|
TABLE + ".md-table-wide > table{width:100%;max-width:none;min-width:max-content}",
|
|
525
530
|
// 折叠态保留横向滚动,但纵向必须 clip;横向滚动容器只有在
|
|
526
531
|
// overscroll-behavior:auto 时才会把纵向滚轮交还给页面。
|
|
527
|
-
|
|
532
|
+
// 这里同时写明 min/max-height:基础表格规则的 max-height 特异性更高,不补会压过设置值;
|
|
533
|
+
// 最小高度保证极低阈值下「展开」按钮仍完整可见。
|
|
534
|
+
TABLE + "." + FOLD_CLASS + "[" + FOLD_ATTR + '="on"]{min-height:48px;max-height:var(--md-plus-fold-max-height);overflow-x:auto;overflow-y:clip}'
|
|
528
535
|
].join("\n");
|
|
529
536
|
var scripts = /* @__PURE__ */ new Map();
|
|
530
537
|
var pending = /* @__PURE__ */ new Set();
|
|
@@ -533,6 +540,7 @@ window.__ModuleLoader__.load({
|
|
|
533
540
|
var rescanQueued = false;
|
|
534
541
|
var injected = /* @__PURE__ */ new Set();
|
|
535
542
|
var diagramSeq = 0;
|
|
543
|
+
var disposed = false;
|
|
536
544
|
function injectStyle() {
|
|
537
545
|
if (document.querySelector("style[" + STYLE_ATTR + "]") !== null) return;
|
|
538
546
|
var tag = document.createElement("style");
|
|
@@ -675,6 +683,7 @@ window.__ModuleLoader__.load({
|
|
|
675
683
|
) != null;
|
|
676
684
|
}
|
|
677
685
|
function schedule(block) {
|
|
686
|
+
if (disposed) return;
|
|
678
687
|
if (block !== void 0) pending.add(block);
|
|
679
688
|
else rescanQueued = true;
|
|
680
689
|
if (timer !== null) return;
|
|
@@ -682,6 +691,7 @@ window.__ModuleLoader__.load({
|
|
|
682
691
|
}
|
|
683
692
|
function flush() {
|
|
684
693
|
timer = null;
|
|
694
|
+
if (disposed) return;
|
|
685
695
|
if (rescanQueued) {
|
|
686
696
|
rescanQueued = false;
|
|
687
697
|
for (const block of document.querySelectorAll(BLOCK)) pending.add(block);
|
|
@@ -843,7 +853,7 @@ window.__ModuleLoader__.load({
|
|
|
843
853
|
if (lang === "") return;
|
|
844
854
|
if (DSH_LANGS.has(lang)) return;
|
|
845
855
|
var api = await loadScript(HL_URL, HL_GLOBAL);
|
|
846
|
-
if (api === null || !api.supports(lang)) return;
|
|
856
|
+
if (disposed || api === null || !api.supports(lang)) return;
|
|
847
857
|
if (!pre.isConnected) return;
|
|
848
858
|
var code = pre.textContent ?? "";
|
|
849
859
|
if (code.trim() === "") return;
|
|
@@ -855,6 +865,7 @@ window.__ModuleLoader__.load({
|
|
|
855
865
|
} catch {
|
|
856
866
|
return;
|
|
857
867
|
}
|
|
868
|
+
if (disposed) return;
|
|
858
869
|
if (typeof html !== "string" || html === "") return;
|
|
859
870
|
if (!pre.isConnected || (pre.textContent ?? "") !== code) {
|
|
860
871
|
schedule(block);
|
|
@@ -879,8 +890,13 @@ window.__ModuleLoader__.load({
|
|
|
879
890
|
function getMermaidTheme() {
|
|
880
891
|
try {
|
|
881
892
|
var saved = window.localStorage.getItem(THEME_KEY);
|
|
882
|
-
if (saved !== null && THEME_ORDER.indexOf(saved) !== -1)
|
|
893
|
+
if (saved !== null && THEME_ORDER.indexOf(saved) !== -1) {
|
|
894
|
+
memoryTheme = saved;
|
|
895
|
+
return saved;
|
|
896
|
+
}
|
|
897
|
+
memoryTheme = null;
|
|
883
898
|
} catch {
|
|
899
|
+
if (memoryTheme !== null) return memoryTheme;
|
|
884
900
|
}
|
|
885
901
|
return "blue";
|
|
886
902
|
}
|
|
@@ -898,6 +914,7 @@ window.__ModuleLoader__.load({
|
|
|
898
914
|
var current = getMermaidTheme();
|
|
899
915
|
var index = THEME_ORDER.indexOf(current);
|
|
900
916
|
var next = THEME_ORDER[(index + 1) % THEME_ORDER.length];
|
|
917
|
+
memoryTheme = next;
|
|
901
918
|
try {
|
|
902
919
|
window.localStorage.setItem(THEME_KEY, next);
|
|
903
920
|
} catch {
|
|
@@ -911,16 +928,18 @@ window.__ModuleLoader__.load({
|
|
|
911
928
|
var key = "mmd\0" + code;
|
|
912
929
|
if (block.getAttribute(KEY_ATTR) === key) return;
|
|
913
930
|
var api = await loadScript(MMD_URL, MMD_GLOBAL);
|
|
914
|
-
if (api === null) return;
|
|
931
|
+
if (disposed || api === null) return;
|
|
915
932
|
if (!pre.isConnected) return;
|
|
916
933
|
var svg;
|
|
917
934
|
try {
|
|
918
935
|
var dark = document.body.hasAttribute("data-ds-dark-theme");
|
|
919
936
|
svg = await api.render("dsh-md-plus-mmd-" + ++diagramSeq, code, dark, getMermaidTheme());
|
|
920
937
|
} catch (error) {
|
|
938
|
+
if (disposed) return;
|
|
921
939
|
failDiagram(block, content, pre, key, error);
|
|
922
940
|
return;
|
|
923
941
|
}
|
|
942
|
+
if (disposed) return;
|
|
924
943
|
if (typeof svg !== "string" || svg === "") return;
|
|
925
944
|
if (svg.includes('aria-roledescription="error"')) {
|
|
926
945
|
failDiagram(block, content, pre, key, new Error("mermaid \u8FD4\u56DE\u7684\u662F\u9519\u8BEF\u5361\u7247"));
|
|
@@ -1083,6 +1102,7 @@ window.__ModuleLoader__.load({
|
|
|
1083
1102
|
target.setAttribute(FOLD_ATTR, "on");
|
|
1084
1103
|
target.classList.add(FOLD_CLASS);
|
|
1085
1104
|
target.style.setProperty("--md-plus-fold-max-height", limit + "px");
|
|
1105
|
+
if (target.hasAttribute(TABLE_DONE_ATTR)) target.scrollTop = 0;
|
|
1086
1106
|
var button = document.createElement("button");
|
|
1087
1107
|
button.type = "button";
|
|
1088
1108
|
button.className = FOLD_BTN_CLASS;
|
|
@@ -1099,6 +1119,7 @@ window.__ModuleLoader__.load({
|
|
|
1099
1119
|
button.addEventListener("click", () => {
|
|
1100
1120
|
var folded = target.getAttribute(FOLD_ATTR) === "on";
|
|
1101
1121
|
target.setAttribute(FOLD_ATTR, folded ? "off" : "on");
|
|
1122
|
+
if (target.hasAttribute(TABLE_DONE_ATTR)) target.scrollTop = 0;
|
|
1102
1123
|
button.textContent = folded ? t("foldClose") : t("foldOpen");
|
|
1103
1124
|
button.setAttribute("aria-expanded", folded ? "true" : "false");
|
|
1104
1125
|
sync?.();
|
|
@@ -1394,6 +1415,7 @@ window.__ModuleLoader__.load({
|
|
|
1394
1415
|
foldTable: readNumber(foldTable, DEFAULT_SETTINGS.foldTable),
|
|
1395
1416
|
foldDiagram: readNumber(foldDiagram, DEFAULT_SETTINGS.foldDiagram)
|
|
1396
1417
|
});
|
|
1418
|
+
memoryTheme = themeSelect.value;
|
|
1397
1419
|
try {
|
|
1398
1420
|
window.localStorage.setItem(THEME_KEY, themeSelect.value);
|
|
1399
1421
|
} catch {
|
|
@@ -1626,6 +1648,7 @@ window.__ModuleLoader__.load({
|
|
|
1626
1648
|
function apply0(ctx) {
|
|
1627
1649
|
if (typeof document === "undefined") return;
|
|
1628
1650
|
ctx.effect(() => {
|
|
1651
|
+
disposed = false;
|
|
1629
1652
|
injectStyle();
|
|
1630
1653
|
applyCodeFontSize();
|
|
1631
1654
|
ensureSettingsButton();
|
|
@@ -1641,6 +1664,13 @@ window.__ModuleLoader__.load({
|
|
|
1641
1664
|
});
|
|
1642
1665
|
schedule();
|
|
1643
1666
|
return () => {
|
|
1667
|
+
disposed = true;
|
|
1668
|
+
if (timer !== null) {
|
|
1669
|
+
window.clearTimeout(timer);
|
|
1670
|
+
timer = null;
|
|
1671
|
+
}
|
|
1672
|
+
pending.clear();
|
|
1673
|
+
rescanQueued = false;
|
|
1644
1674
|
observer.disconnect();
|
|
1645
1675
|
document.removeEventListener("click", onDocumentClick, true);
|
|
1646
1676
|
for (const node of injected) node.remove();
|
|
@@ -1650,7 +1680,7 @@ window.__ModuleLoader__.load({
|
|
|
1650
1680
|
for (const node of document.querySelectorAll("." + FOLD_BTN_CLASS)) node.remove();
|
|
1651
1681
|
for (const node of document.querySelectorAll("[" + FOLD_ATTR + "]")) resetFold(node);
|
|
1652
1682
|
for (const node of document.querySelectorAll("." + TABLE_TOOLS_CLASS)) node.remove();
|
|
1653
|
-
for (const attr of [DONE_ATTR, KEY_ATTR, WRAP_ATTR, MMD_ATTR, TABLE_DONE_ATTR, "data-md-plus-lang"]) {
|
|
1683
|
+
for (const attr of [DONE_ATTR, KEY_ATTR, WRAP_ATTR, MMD_ATTR, TABLE_DONE_ATTR, "data-md-plus-lang", ZOOM_ATTR]) {
|
|
1654
1684
|
for (const node of document.querySelectorAll("[" + attr + "]")) node.removeAttribute(attr);
|
|
1655
1685
|
}
|
|
1656
1686
|
for (const node of document.querySelectorAll("[data-md-plus-original-label]")) {
|