@koi-br/ocr-web-sdk 1.0.65 → 1.0.67
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/dist/{index-BQn8gr7r.mjs → index-BwWdGx71.mjs} +10166 -10085
- package/dist/{index-DA6mPffC.js → index-YVNy3DHg.js} +94 -94
- package/dist/index.cjs.js +2 -2
- package/dist/index.esm.js +2 -2
- package/dist/style.css +1 -1
- package/dist/{tiff.min-umwnTD_S.js → tiff.min-BjOpN7Tg.js} +1 -1
- package/dist/{tiff.min-FWTAhBuz.mjs → tiff.min-C7mxi5R2.mjs} +1 -1
- package/package.json +1 -1
- package/preview/ImagePreview.vue +279 -15
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as getAugmentedNamespace, a as getDefaultExportFromCjs } from "./index-
|
|
1
|
+
import { g as getAugmentedNamespace, a as getDefaultExportFromCjs } from "./index-BwWdGx71.mjs";
|
|
2
2
|
function _mergeNamespaces(U, W) {
|
|
3
3
|
for (var Z = 0; Z < W.length; Z++) {
|
|
4
4
|
const s0 = W[Z];
|
package/package.json
CHANGED
package/preview/ImagePreview.vue
CHANGED
|
@@ -639,6 +639,137 @@ const annotationTextareaRef = ref<any>(); // 批注输入框引用
|
|
|
639
639
|
const activeBlockDiv = ref<HTMLElement | null>(null);
|
|
640
640
|
const isHighlighted = ref(false); // 标识是否为定位点击的高亮
|
|
641
641
|
|
|
642
|
+
// ✅ 跳转高亮目标(数据态):用于 renderTextLayer 重建 DOM 后恢复静态高亮
|
|
643
|
+
type JumpHighlightTarget = {
|
|
644
|
+
pageNum: number;
|
|
645
|
+
bbox: [number, number, number, number];
|
|
646
|
+
highlightStyle?: HighlightStyle;
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
const lastJumpHighlightTarget = ref<JumpHighlightTarget | null>(null);
|
|
650
|
+
|
|
651
|
+
const applyStaticJumpHighlightStyle = (
|
|
652
|
+
el: HTMLElement,
|
|
653
|
+
highlightStyle?: HighlightStyle
|
|
654
|
+
) => {
|
|
655
|
+
// 确保是“静态”状态,不要残留动画
|
|
656
|
+
el.classList.remove("highlight-animated");
|
|
657
|
+
el.style.animation = "";
|
|
658
|
+
el.style.animationFillMode = "";
|
|
659
|
+
el.style.transform = "";
|
|
660
|
+
el.style.transformOrigin = "";
|
|
661
|
+
el.style.transition = "";
|
|
662
|
+
|
|
663
|
+
// ⚠️ 这里的语义要和 highlightPosition() 保持一致:
|
|
664
|
+
// - 如果调用方传了 highlightStyle(哪怕只传了 backgroundColor),就只应用它提供的字段。
|
|
665
|
+
// 避免在“重建后补高亮”时额外加上默认的蓝色 boxShadow/边框,导致看起来像 hover 态。
|
|
666
|
+
// - 如果未传 highlightStyle,才使用默认高亮样式。
|
|
667
|
+
if (highlightStyle) {
|
|
668
|
+
if (highlightStyle.backgroundColor !== undefined) {
|
|
669
|
+
el.style.backgroundColor = highlightStyle.backgroundColor;
|
|
670
|
+
}
|
|
671
|
+
if (highlightStyle.boxShadow !== undefined) {
|
|
672
|
+
el.style.boxShadow = highlightStyle.boxShadow;
|
|
673
|
+
}
|
|
674
|
+
if (highlightStyle.border !== undefined) {
|
|
675
|
+
el.style.border = highlightStyle.border;
|
|
676
|
+
}
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
el.style.backgroundColor =
|
|
681
|
+
"var(--s-color-brand-primary-transparent-3, rgba(0, 102, 255, .15))";
|
|
682
|
+
el.style.boxShadow = "0 0 0 2px rgba(30, 144, 255, 0.6)";
|
|
683
|
+
el.style.border = "none";
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
const reapplyJumpHighlightIfNeeded = (targetPage: number) => {
|
|
687
|
+
const target = lastJumpHighlightTarget.value;
|
|
688
|
+
if (!target || target.pageNum !== targetPage) return;
|
|
689
|
+
|
|
690
|
+
const textLayer = textLayerRefs.get(targetPage);
|
|
691
|
+
if (!textLayer) return;
|
|
692
|
+
|
|
693
|
+
const tolerance = 2;
|
|
694
|
+
const blockDivs = textLayer.querySelectorAll(".text-block");
|
|
695
|
+
|
|
696
|
+
let matched: HTMLElement | null = null;
|
|
697
|
+
for (let i = 0; i < blockDivs.length; i++) {
|
|
698
|
+
const div = blockDivs[i] as HTMLElement;
|
|
699
|
+
const storedBbox = div.dataset.bbox;
|
|
700
|
+
if (!storedBbox) continue;
|
|
701
|
+
|
|
702
|
+
try {
|
|
703
|
+
const parsed = JSON.parse(storedBbox) as [
|
|
704
|
+
number,
|
|
705
|
+
number,
|
|
706
|
+
number,
|
|
707
|
+
number
|
|
708
|
+
];
|
|
709
|
+
const isMatch =
|
|
710
|
+
Math.abs(parsed[0] - target.bbox[0]) < tolerance &&
|
|
711
|
+
Math.abs(parsed[1] - target.bbox[1]) < tolerance &&
|
|
712
|
+
Math.abs(parsed[2] - target.bbox[2]) < tolerance &&
|
|
713
|
+
Math.abs(parsed[3] - target.bbox[3]) < tolerance;
|
|
714
|
+
|
|
715
|
+
if (isMatch) {
|
|
716
|
+
matched = div;
|
|
717
|
+
break;
|
|
718
|
+
}
|
|
719
|
+
} catch (_e) {
|
|
720
|
+
// ignore
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (!matched) return;
|
|
725
|
+
|
|
726
|
+
// ✅ 输入态也要补回跳转高亮(否则提交触发 renderTextLayer 重建后会丢失 B 的高亮)
|
|
727
|
+
// 但输入态不要抢占 activeBlockDiv/isHighlighted,避免影响批注弹窗锚点与焦点。
|
|
728
|
+
if (currentAnnotationBlock.value) {
|
|
729
|
+
// 如果刚好命中“锁定输入态块”,保持输入态样式优先,不覆盖
|
|
730
|
+
if (lockedAnnotationDiv.value && matched === lockedAnnotationDiv.value) {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
applyStaticJumpHighlightStyle(matched, target.highlightStyle);
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
applyStaticJumpHighlightStyle(matched, target.highlightStyle);
|
|
739
|
+
|
|
740
|
+
// 让状态也恢复一致(避免 renderTextLayer 清空引用后 isHighlighted/activeBlockDiv 脱节)
|
|
741
|
+
activeBlockDiv.value = matched;
|
|
742
|
+
isHighlighted.value = true;
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
// ✅ lastJumpHighlightTarget 的清理交由 clearAllHighlights() 统一负责。
|
|
746
|
+
// hover 等局部交互可能会暂时把 isHighlighted 置为 false,但这不代表用户要取消“跳转高亮”。
|
|
747
|
+
// 只有在真正“全局清高亮”时才清空缓存目标,避免提交触发重建后高亮丢失。
|
|
748
|
+
|
|
749
|
+
// ✅ 批注输入态锁定的文本块(与 activeBlockDiv 解耦,避免被 jump/highlight 覆盖)
|
|
750
|
+
const lockedAnnotationDiv = ref<HTMLElement | null>(null);
|
|
751
|
+
|
|
752
|
+
const LOCKED_ANNOTATION_OUTLINE = "2px solid rgba(24, 144, 255, 0.85)";
|
|
753
|
+
const LOCKED_ANNOTATION_OUTLINE_OFFSET = "1px";
|
|
754
|
+
|
|
755
|
+
const applyLockedAnnotationOutline = (blockDiv: HTMLElement) => {
|
|
756
|
+
blockDiv.style.setProperty(
|
|
757
|
+
"outline",
|
|
758
|
+
LOCKED_ANNOTATION_OUTLINE,
|
|
759
|
+
"important"
|
|
760
|
+
);
|
|
761
|
+
blockDiv.style.setProperty(
|
|
762
|
+
"outline-offset",
|
|
763
|
+
LOCKED_ANNOTATION_OUTLINE_OFFSET,
|
|
764
|
+
"important"
|
|
765
|
+
);
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
const clearLockedAnnotationOutline = (blockDiv: HTMLElement) => {
|
|
769
|
+
blockDiv.style.removeProperty("outline");
|
|
770
|
+
blockDiv.style.removeProperty("outline-offset");
|
|
771
|
+
};
|
|
772
|
+
|
|
642
773
|
// 根据当前页码过滤blocksData
|
|
643
774
|
const currentPageBlocksData = computed(() => {
|
|
644
775
|
if (!props.blocksData || props.blocksData.length === 0) {
|
|
@@ -1069,10 +1200,14 @@ const switchToPage = (page: number, autoClearMark: boolean = true) => {
|
|
|
1069
1200
|
return;
|
|
1070
1201
|
}
|
|
1071
1202
|
|
|
1072
|
-
//
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1203
|
+
// 重置文本选择状态和批注状态(若处于输入态先解除锁定,避免 outline 残留)
|
|
1204
|
+
if (lockedAnnotationDiv.value) {
|
|
1205
|
+
closeAnnotationInput();
|
|
1206
|
+
} else {
|
|
1207
|
+
showAnnotationPopup.value = false;
|
|
1208
|
+
currentAnnotationBlock.value = null;
|
|
1209
|
+
annotationInput.value = "";
|
|
1210
|
+
}
|
|
1076
1211
|
const hadHighlight = isHighlighted.value && activeBlockDiv.value !== null;
|
|
1077
1212
|
activeBlockDiv.value = null;
|
|
1078
1213
|
isHighlighted.value = false;
|
|
@@ -1134,10 +1269,14 @@ const reset = () => {
|
|
|
1134
1269
|
|
|
1135
1270
|
position.value = { x: 0, y: 0 };
|
|
1136
1271
|
|
|
1137
|
-
//
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1272
|
+
// 重置文本选择状态和批注状态(若处于输入态先解除锁定,避免 outline 残留)
|
|
1273
|
+
if (lockedAnnotationDiv.value) {
|
|
1274
|
+
closeAnnotationInput();
|
|
1275
|
+
} else {
|
|
1276
|
+
showAnnotationPopup.value = false;
|
|
1277
|
+
currentAnnotationBlock.value = null;
|
|
1278
|
+
annotationInput.value = "";
|
|
1279
|
+
}
|
|
1141
1280
|
const hadHighlight = isHighlighted.value && activeBlockDiv.value !== null;
|
|
1142
1281
|
activeBlockDiv.value = null;
|
|
1143
1282
|
isHighlighted.value = false;
|
|
@@ -1475,6 +1614,11 @@ const renderTextLayer = (pageNum?: number) => {
|
|
|
1475
1614
|
|
|
1476
1615
|
// Hover 和点击事件
|
|
1477
1616
|
blockDiv.addEventListener("mouseenter", (e) => {
|
|
1617
|
+
// ✅ 输入态:锚点已锁定,禁止 hover 驱动位置/激活块变化
|
|
1618
|
+
if (currentAnnotationBlock.value) {
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1478
1622
|
// 如果未启用 hover 效果,直接返回
|
|
1479
1623
|
if (!props.enableBlockHover) {
|
|
1480
1624
|
return;
|
|
@@ -1507,6 +1651,11 @@ const renderTextLayer = (pageNum?: number) => {
|
|
|
1507
1651
|
});
|
|
1508
1652
|
|
|
1509
1653
|
blockDiv.addEventListener("mouseleave", () => {
|
|
1654
|
+
// ✅ 输入态:不再启动 auto-hide 逻辑
|
|
1655
|
+
if (currentAnnotationBlock.value) {
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1510
1659
|
// 如果未启用 hover 效果,直接返回
|
|
1511
1660
|
if (!props.enableBlockHover) {
|
|
1512
1661
|
return;
|
|
@@ -1526,6 +1675,9 @@ const renderTextLayer = (pageNum?: number) => {
|
|
|
1526
1675
|
textLayer.appendChild(blockDiv);
|
|
1527
1676
|
});
|
|
1528
1677
|
|
|
1678
|
+
// ✅ 页面重建后,把“最后一次跳转高亮”补回到新 DOM 节点上(静态)
|
|
1679
|
+
reapplyJumpHighlightIfNeeded(targetPage);
|
|
1680
|
+
|
|
1529
1681
|
// 标记该页面已渲染
|
|
1530
1682
|
renderedPages.value.add(targetPage);
|
|
1531
1683
|
} catch (error) {
|
|
@@ -1568,6 +1720,9 @@ const showAnnotationButtonForBlock = (
|
|
|
1568
1720
|
event: MouseEvent,
|
|
1569
1721
|
blockDiv: HTMLElement
|
|
1570
1722
|
) => {
|
|
1723
|
+
// ✅ 输入态:不允许入口浮层继续跟随 hover 更新位置
|
|
1724
|
+
if (currentAnnotationBlock.value) return;
|
|
1725
|
+
|
|
1571
1726
|
const bboxStr = blockDiv.dataset.bbox || "";
|
|
1572
1727
|
if (!bboxStr) return;
|
|
1573
1728
|
|
|
@@ -1724,6 +1879,9 @@ const clearAllHighlights = (
|
|
|
1724
1879
|
// 清除引用和标志
|
|
1725
1880
|
activeBlockDiv.value = null;
|
|
1726
1881
|
isHighlighted.value = false;
|
|
1882
|
+
|
|
1883
|
+
// ✅ 真正“全局清高亮”时才清空跳转高亮缓存
|
|
1884
|
+
lastJumpHighlightTarget.value = null;
|
|
1727
1885
|
|
|
1728
1886
|
// 清除定时器
|
|
1729
1887
|
if (highlightTimer) {
|
|
@@ -2124,6 +2282,29 @@ const openAnnotationInput = (e?: Event) => {
|
|
|
2124
2282
|
// 确保弹窗显示
|
|
2125
2283
|
showAnnotationPopup.value = true;
|
|
2126
2284
|
|
|
2285
|
+
// ✅ 锁定锚点高亮(输入态)
|
|
2286
|
+
if (activeBlockDiv.value) {
|
|
2287
|
+
// 如果之前有锁定块且不是当前块,先解除之前的锁定,避免 outline 残留
|
|
2288
|
+
if (
|
|
2289
|
+
lockedAnnotationDiv.value &&
|
|
2290
|
+
lockedAnnotationDiv.value !== activeBlockDiv.value
|
|
2291
|
+
) {
|
|
2292
|
+
clearLockedAnnotationOutline(lockedAnnotationDiv.value);
|
|
2293
|
+
restoreBlockStyle(lockedAnnotationDiv.value);
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
lockedAnnotationDiv.value = activeBlockDiv.value;
|
|
2297
|
+
|
|
2298
|
+
// 清除其它块的高亮,避免竞态残留
|
|
2299
|
+
clearAllHighlights(lockedAnnotationDiv.value);
|
|
2300
|
+
|
|
2301
|
+
// 保持该块的 hover/批注样式
|
|
2302
|
+
applyHoverStyle(lockedAnnotationDiv.value, !!existingAnnotation);
|
|
2303
|
+
|
|
2304
|
+
// 使用 outline 作为“锁定态”标识(不依赖 scoped CSS)
|
|
2305
|
+
applyLockedAnnotationOutline(lockedAnnotationDiv.value);
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2127
2308
|
// 重新计算弹窗位置(输入框更大)
|
|
2128
2309
|
nextTick(() => {
|
|
2129
2310
|
adjustAnnotationPopupPosition();
|
|
@@ -2169,9 +2350,13 @@ const adjustAnnotationPopupPosition = () => {
|
|
|
2169
2350
|
let left: number;
|
|
2170
2351
|
let top: number;
|
|
2171
2352
|
|
|
2172
|
-
|
|
2353
|
+
const anchorBlockDiv = currentAnnotationBlock.value
|
|
2354
|
+
? lockedAnnotationDiv.value
|
|
2355
|
+
: activeBlockDiv.value;
|
|
2356
|
+
|
|
2357
|
+
if (anchorBlockDiv) {
|
|
2173
2358
|
// 使用文本块位置,和批注按钮使用相同的计算逻辑
|
|
2174
|
-
const rect =
|
|
2359
|
+
const rect = anchorBlockDiv.getBoundingClientRect();
|
|
2175
2360
|
const relativeX =
|
|
2176
2361
|
rect.left - containerRect.left + containerRef.value.scrollLeft;
|
|
2177
2362
|
const relativeY =
|
|
@@ -2250,10 +2435,30 @@ const closeAnnotationInput = () => {
|
|
|
2250
2435
|
annotationInput.value = "";
|
|
2251
2436
|
showAnnotationPopup.value = false;
|
|
2252
2437
|
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2438
|
+
const lockedDiv = lockedAnnotationDiv.value;
|
|
2439
|
+
|
|
2440
|
+
// ✅ 优先清理“输入态锁定块”(不依赖 activeBlockDiv,避免被跳转覆盖后清不到)
|
|
2441
|
+
if (lockedDiv) {
|
|
2442
|
+
clearLockedAnnotationOutline(lockedDiv);
|
|
2443
|
+
restoreBlockStyle(lockedDiv);
|
|
2444
|
+
|
|
2445
|
+
// 如果当前 activeBlock 就是这个锁定块,且不是跳转高亮,则恢复引用
|
|
2446
|
+
if (activeBlockDiv.value === lockedDiv && !isHighlighted.value) {
|
|
2447
|
+
activeBlockDiv.value = null;
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
lockedAnnotationDiv.value = null;
|
|
2451
|
+
return;
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
// 兼容路径:没有锁定块时,按原逻辑处理 activeBlock
|
|
2455
|
+
if (activeBlockDiv.value) {
|
|
2456
|
+
clearLockedAnnotationOutline(activeBlockDiv.value);
|
|
2457
|
+
|
|
2458
|
+
if (!isHighlighted.value) {
|
|
2459
|
+
restoreBlockStyle(activeBlockDiv.value);
|
|
2460
|
+
activeBlockDiv.value = null;
|
|
2461
|
+
}
|
|
2257
2462
|
}
|
|
2258
2463
|
};
|
|
2259
2464
|
|
|
@@ -2549,10 +2754,38 @@ const highlightPosition = (
|
|
|
2549
2754
|
// 🔑 关键:清除页面上所有的高亮元素,确保不会有残留
|
|
2550
2755
|
// 这样可以避免多个高亮框同时存在的问题
|
|
2551
2756
|
const hadHighlight = activeBlockDiv.value !== null && isHighlighted.value;
|
|
2552
|
-
|
|
2757
|
+
|
|
2758
|
+
// ✅ 如果当前有批注输入态锁定块,先记录它的批注状态,清理后再补回样式
|
|
2759
|
+
const lockedDiv = lockedAnnotationDiv.value;
|
|
2760
|
+
let lockedHasAnnotation = false;
|
|
2761
|
+
if (lockedDiv) {
|
|
2762
|
+
const bboxStr = lockedDiv.dataset.bbox;
|
|
2763
|
+
const pageStr = lockedDiv.dataset.page;
|
|
2764
|
+
const lockedPageNum = pageStr ? parseInt(pageStr, 10) : undefined;
|
|
2765
|
+
if (bboxStr) {
|
|
2766
|
+
try {
|
|
2767
|
+
const bbox = JSON.parse(bboxStr) as [
|
|
2768
|
+
number,
|
|
2769
|
+
number,
|
|
2770
|
+
number,
|
|
2771
|
+
number
|
|
2772
|
+
];
|
|
2773
|
+
lockedHasAnnotation = !!getAnnotationForBlock(bbox, lockedPageNum);
|
|
2774
|
+
} catch (_e) {
|
|
2775
|
+
lockedHasAnnotation = false;
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2553
2780
|
// 清除所有高亮(包括所有页面的文本块),不排除任何元素
|
|
2554
2781
|
clearAllHighlights();
|
|
2555
2782
|
|
|
2783
|
+
// ✅ 清理后补回锁定块样式(避免 jump/highlight 清掉输入态的背景高亮)
|
|
2784
|
+
if (lockedDiv) {
|
|
2785
|
+
applyHoverStyle(lockedDiv, lockedHasAnnotation);
|
|
2786
|
+
applyLockedAnnotationOutline(lockedDiv);
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2556
2789
|
// 如果之前有高亮,触发高亮清除事件
|
|
2557
2790
|
if (hadHighlight) {
|
|
2558
2791
|
emit("highlight-clear");
|
|
@@ -2660,6 +2893,9 @@ const highlightPosition = (
|
|
|
2660
2893
|
activeBlockDiv.value = elementRef;
|
|
2661
2894
|
isHighlighted.value = true;
|
|
2662
2895
|
|
|
2896
|
+
// ✅ 记录最后一次“跳转高亮”的目标,用于 renderTextLayer 重建后补回静态高亮
|
|
2897
|
+
lastJumpHighlightTarget.value = { pageNum, bbox, highlightStyle };
|
|
2898
|
+
|
|
2663
2899
|
// 使用传入的高亮样式,如果没有传入则使用默认样式
|
|
2664
2900
|
if (highlightStyle) {
|
|
2665
2901
|
if (highlightStyle.backgroundColor) {
|
|
@@ -2814,8 +3050,36 @@ const jumpToPosition = (
|
|
|
2814
3050
|
isHighlighted: isHighlighted.value,
|
|
2815
3051
|
reason: previousPositioningId ? '之前的定位被新定位覆盖' : '清除残留的高亮'
|
|
2816
3052
|
});
|
|
3053
|
+
// ✅ 如果当前有批注输入态锁定块,先记录它的批注状态,清理后再补回样式
|
|
3054
|
+
const lockedDiv = lockedAnnotationDiv.value;
|
|
3055
|
+
let lockedHasAnnotation = false;
|
|
3056
|
+
if (lockedDiv) {
|
|
3057
|
+
const bboxStr = lockedDiv.dataset.bbox;
|
|
3058
|
+
const pageStr = lockedDiv.dataset.page;
|
|
3059
|
+
const lockedPageNum = pageStr ? parseInt(pageStr, 10) : undefined;
|
|
3060
|
+
if (bboxStr) {
|
|
3061
|
+
try {
|
|
3062
|
+
const lockedBbox = JSON.parse(bboxStr) as [
|
|
3063
|
+
number,
|
|
3064
|
+
number,
|
|
3065
|
+
number,
|
|
3066
|
+
number
|
|
3067
|
+
];
|
|
3068
|
+
lockedHasAnnotation = !!getAnnotationForBlock(lockedBbox, lockedPageNum);
|
|
3069
|
+
} catch (_e) {
|
|
3070
|
+
lockedHasAnnotation = false;
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
|
|
2817
3075
|
// 清除所有页面的高亮元素,不排除任何元素
|
|
2818
3076
|
clearAllHighlights();
|
|
3077
|
+
|
|
3078
|
+
// ✅ 清理后补回锁定块样式(避免跳转清掉输入态的背景高亮)
|
|
3079
|
+
if (lockedDiv) {
|
|
3080
|
+
applyHoverStyle(lockedDiv, lockedHasAnnotation);
|
|
3081
|
+
applyLockedAnnotationOutline(lockedDiv);
|
|
3082
|
+
}
|
|
2819
3083
|
}
|
|
2820
3084
|
|
|
2821
3085
|
// 🔑 关键:在定位开始时设置标记,禁用同步滚动
|