You've already forked DataMate
feat(annotation): 添加保存快捷键功能
- 实现了 Ctrl+S 保存快捷键检测逻辑 - 添加了 handleSaveShortcut 事件处理函数 - 在窗口上注册键盘事件监听器 - 修改 requestExport 函数支持 autoAdvance 参数 - 更新保存按钮点击事件传递 autoAdvance 参数
This commit is contained in:
@@ -268,6 +268,17 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSaveShortcut(event) {
|
||||||
|
if (!event || event.defaultPrevented || event.isComposing) return false;
|
||||||
|
const key = event.key;
|
||||||
|
const code = event.code;
|
||||||
|
const isS = key === "s" || key === "S" || code === "KeyS";
|
||||||
|
if (!isS) return false;
|
||||||
|
if (!(event.ctrlKey || event.metaKey)) return false;
|
||||||
|
if (event.shiftKey || event.altKey) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function handleSaveAndNextShortcut(event) {
|
function handleSaveAndNextShortcut(event) {
|
||||||
if (!isSaveAndNextShortcut(event) || event.repeat) return;
|
if (!isSaveAndNextShortcut(event) || event.repeat) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -280,6 +291,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSaveShortcut(event) {
|
||||||
|
if (!isSaveShortcut(event) || event.repeat) return;
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
try {
|
||||||
|
const raw = exportSelectedAnnotation();
|
||||||
|
postToParent("LS_EXPORT_RESULT", raw);
|
||||||
|
} catch (e) {
|
||||||
|
postToParent("LS_ERROR", { message: e?.message || String(e) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function initLabelStudio(payload) {
|
function initLabelStudio(payload) {
|
||||||
if (!window.LabelStudio) {
|
if (!window.LabelStudio) {
|
||||||
throw new Error("LabelStudio 未加载(请检查静态资源/网络)");
|
throw new Error("LabelStudio 未加载(请检查静态资源/网络)");
|
||||||
@@ -351,6 +374,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("keydown", handleSaveAndNextShortcut);
|
window.addEventListener("keydown", handleSaveAndNextShortcut);
|
||||||
|
window.addEventListener("keydown", handleSaveShortcut);
|
||||||
|
|
||||||
window.addEventListener("message", (event) => {
|
window.addEventListener("message", (event) => {
|
||||||
if (event.origin !== ORIGIN) return;
|
if (event.origin !== ORIGIN) return;
|
||||||
|
|||||||
@@ -117,6 +117,17 @@ const resolveSegmentIndex = (value: unknown) => {
|
|||||||
return Number.isFinite(parsed) ? parsed : undefined;
|
return Number.isFinite(parsed) ? parsed : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isSaveShortcut = (event: KeyboardEvent) => {
|
||||||
|
if (event.defaultPrevented || event.isComposing) return false;
|
||||||
|
const key = event.key;
|
||||||
|
const code = event.code;
|
||||||
|
const isS = key === "s" || key === "S" || code === "KeyS";
|
||||||
|
if (!isS) return false;
|
||||||
|
if (!(event.ctrlKey || event.metaKey)) return false;
|
||||||
|
if (event.shiftKey || event.altKey) return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
const normalizePayload = (payload: unknown): ExportPayload | undefined => {
|
const normalizePayload = (payload: unknown): ExportPayload | undefined => {
|
||||||
if (!payload || typeof payload !== "object") return undefined;
|
if (!payload || typeof payload !== "object") return undefined;
|
||||||
return payload as ExportPayload;
|
return payload as ExportPayload;
|
||||||
@@ -851,14 +862,27 @@ export default function LabelStudioTextEditor() {
|
|||||||
});
|
});
|
||||||
}, [modal]);
|
}, [modal]);
|
||||||
|
|
||||||
const requestExport = () => {
|
const requestExport = useCallback((autoAdvance: boolean) => {
|
||||||
if (!selectedFileId) {
|
if (!selectedFileId) {
|
||||||
message.warning("请先选择文件");
|
message.warning("请先选择文件");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pendingAutoAdvanceRef.current = true;
|
pendingAutoAdvanceRef.current = autoAdvance;
|
||||||
postToIframe("LS_EXPORT", {});
|
postToIframe("LS_EXPORT", {});
|
||||||
};
|
}, [message, postToIframe, selectedFileId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleSaveShortcut = (event: KeyboardEvent) => {
|
||||||
|
if (!isSaveShortcut(event) || event.repeat) return;
|
||||||
|
if (saving || loadingTaskDetail || segmentSwitching) return;
|
||||||
|
if (!iframeReady || !lsReady) return;
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
requestExport(false);
|
||||||
|
};
|
||||||
|
window.addEventListener("keydown", handleSaveShortcut);
|
||||||
|
return () => window.removeEventListener("keydown", handleSaveShortcut);
|
||||||
|
}, [iframeReady, loadingTaskDetail, lsReady, requestExport, saving, segmentSwitching]);
|
||||||
|
|
||||||
// 段落切换处理
|
// 段落切换处理
|
||||||
const handleSegmentChange = useCallback(async (newIndex: number) => {
|
const handleSegmentChange = useCallback(async (newIndex: number) => {
|
||||||
@@ -1212,7 +1236,7 @@ export default function LabelStudioTextEditor() {
|
|||||||
icon={<SaveOutlined />}
|
icon={<SaveOutlined />}
|
||||||
loading={saving}
|
loading={saving}
|
||||||
disabled={!iframeReady || !selectedFileId}
|
disabled={!iframeReady || !selectedFileId}
|
||||||
onClick={requestExport}
|
onClick={() => requestExport(true)}
|
||||||
>
|
>
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user