@blocklet/editor 2.1.120 → 2.1.122
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.
|
@@ -16,6 +16,7 @@ export declare class EditorTranslator {
|
|
|
16
16
|
private editor;
|
|
17
17
|
private options;
|
|
18
18
|
private originalEditorState;
|
|
19
|
+
private preprocessEditorState;
|
|
19
20
|
private nodeKeyToSidMap;
|
|
20
21
|
private sidToNodeKeyMap;
|
|
21
22
|
private translations;
|
|
@@ -32,5 +33,6 @@ export declare class EditorTranslator {
|
|
|
32
33
|
}): Promise<void>;
|
|
33
34
|
applyTranslations(): void;
|
|
34
35
|
restore(sid?: string): void;
|
|
36
|
+
preprocessNodes(): Promise<void>;
|
|
35
37
|
}
|
|
36
38
|
export declare function useEditorTranslator(options: EditorTranslatorOptions): EditorTranslator;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
2
|
-
import { $getNodeByKey } from 'lexical';
|
|
2
|
+
import { $createParagraphNode, $getNodeByKey } from 'lexical';
|
|
3
3
|
import { useRef, useEffect } from 'react';
|
|
4
4
|
import { $createNodeKeyToSidMap, $createSidToNodeKeyMap, $nodeToHtml, $findTranslatableElementNodes, $htmlToNodes, } from '../translation/translation-utils';
|
|
5
5
|
import { $createEmojiNode } from '../../main/nodes/EmojiNode';
|
|
6
6
|
import { $createTranslationNode } from './TranslationNode';
|
|
7
|
+
import { $isExcalidrawNode } from '../../main/nodes/ExcalidrawNode';
|
|
8
|
+
import { $isImageNode } from '../../main/nodes/ImageNode';
|
|
9
|
+
import { $isPdfNode } from '../PdfPlugin/PdfNode';
|
|
7
10
|
export class EditorTranslator {
|
|
8
11
|
editor;
|
|
9
12
|
options;
|
|
10
13
|
originalEditorState;
|
|
14
|
+
preprocessEditorState = null;
|
|
11
15
|
nodeKeyToSidMap = new Map();
|
|
12
16
|
sidToNodeKeyMap = new Map();
|
|
13
17
|
translations = [];
|
|
@@ -32,13 +36,14 @@ export class EditorTranslator {
|
|
|
32
36
|
updateDisplayMode() {
|
|
33
37
|
// Warning: flushSync was called from inside a lifecycle method
|
|
34
38
|
setTimeout(() => {
|
|
35
|
-
this.editor.setEditorState(this.originalEditorState);
|
|
39
|
+
this.editor.setEditorState(this.preprocessEditorState || this.originalEditorState);
|
|
36
40
|
this.applyTranslations();
|
|
37
41
|
}, 10);
|
|
38
42
|
}
|
|
39
43
|
async translate({ targetLanguage, translateService, detectLanguage, useCache, }) {
|
|
40
44
|
// 翻译前备份 editor state (fix 恢复原文时图片路径错误的问题)
|
|
41
|
-
this.originalEditorState = this.editor.getEditorState();
|
|
45
|
+
this.originalEditorState = this.editor.getEditorState().clone();
|
|
46
|
+
await this.preprocessNodes();
|
|
42
47
|
this.nodeKeyToSidMap = this.editor.getEditorState().read(() => $createNodeKeyToSidMap());
|
|
43
48
|
this.sidToNodeKeyMap = this.editor.getEditorState().read(() => $createSidToNodeKeyMap());
|
|
44
49
|
let nodes = [];
|
|
@@ -115,6 +120,7 @@ export class EditorTranslator {
|
|
|
115
120
|
this.editor.update(() => {
|
|
116
121
|
if (!sid) {
|
|
117
122
|
this.editor.setEditorState(this.originalEditorState);
|
|
123
|
+
this.translations = [];
|
|
118
124
|
}
|
|
119
125
|
else if (this.options.displayMode === 'translationOnly') {
|
|
120
126
|
const nodeKey = this.sidToNodeKeyMap.get(sid);
|
|
@@ -131,6 +137,37 @@ export class EditorTranslator {
|
|
|
131
137
|
}
|
|
132
138
|
});
|
|
133
139
|
}
|
|
140
|
+
async preprocessNodes() {
|
|
141
|
+
const isSpecialNode = (node) => {
|
|
142
|
+
return $isExcalidrawNode(node) || $isImageNode(node) || $isPdfNode(node);
|
|
143
|
+
};
|
|
144
|
+
this.editor.update(() => {
|
|
145
|
+
$findTranslatableElementNodes().forEach((node) => {
|
|
146
|
+
// 如果 children 中即包含特殊结点, 也包含普通结点, 则将特殊结点与普通结点分开
|
|
147
|
+
const children = node.getChildren();
|
|
148
|
+
if (!children.some(isSpecialNode) || children.every(isSpecialNode)) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const normalNodes = [];
|
|
152
|
+
children.forEach((child) => {
|
|
153
|
+
if (isSpecialNode(child)) {
|
|
154
|
+
if (normalNodes.length > 0) {
|
|
155
|
+
node.insertBefore($createParagraphNode().append(...normalNodes));
|
|
156
|
+
normalNodes.length = 0;
|
|
157
|
+
}
|
|
158
|
+
node.insertBefore($createParagraphNode().append(child));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
normalNodes.push(child);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}, { discrete: true });
|
|
165
|
+
});
|
|
166
|
+
// 延时 10ms, 否则获取的 node-key <=> sid 映射不准确
|
|
167
|
+
// eslint-disable-next-line no-promise-executor-return
|
|
168
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
169
|
+
this.preprocessEditorState = this.editor.getEditorState().clone();
|
|
170
|
+
}
|
|
134
171
|
}
|
|
135
172
|
export function useEditorTranslator(options) {
|
|
136
173
|
const [editor] = useLexicalComposerContext();
|
|
@@ -72,10 +72,28 @@ function InternalInlineTranslationPlugin({ translateService, detectLanguage, onT
|
|
|
72
72
|
document.removeEventListener('keydown', handler);
|
|
73
73
|
};
|
|
74
74
|
}, [editor, editorTranslator]);
|
|
75
|
+
// 对于翻译后的内容,禁止 checkbox 点击交互
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
const onClick = (event) => {
|
|
78
|
+
const target = event.target;
|
|
79
|
+
if (editorTranslator.isTranslated && target.closest('li[role="checkbox"]')) {
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
event.stopPropagation();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return editor.registerRootListener((rootElement, prevRootElement) => {
|
|
85
|
+
if (prevRootElement) {
|
|
86
|
+
prevRootElement.removeEventListener('click', onClick, { capture: true });
|
|
87
|
+
}
|
|
88
|
+
if (rootElement) {
|
|
89
|
+
rootElement.addEventListener('click', onClick, { capture: true });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}, [editor, editorTranslator]);
|
|
75
93
|
if (editor.isEditable()) {
|
|
76
94
|
return null;
|
|
77
95
|
}
|
|
78
|
-
return status === 'completed' ? (_jsx(Box, { sx: { mb: 0.5 }, children: _jsxs(Box, { sx: {
|
|
96
|
+
return status === 'completed' && editorTranslator.isTranslated ? (_jsx(Box, { sx: { mb: 0.5 }, children: _jsxs(Box, { className: "inline-translation-badge", sx: {
|
|
79
97
|
display: 'inline-block',
|
|
80
98
|
px: 1,
|
|
81
99
|
fontSize: 12,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/editor",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.122",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"ufo": "^1.5.4",
|
|
67
67
|
"url-join": "^4.0.1",
|
|
68
68
|
"zustand": "^4.5.5",
|
|
69
|
-
"@blocklet/pdf": "^2.1.
|
|
69
|
+
"@blocklet/pdf": "^2.1.122"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@babel/core": "^7.25.2",
|