@ctzhian/tiptap 2.1.12 → 2.1.14
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/Editor/demo.js +3 -3
- package/dist/EditorMarkdown/demo.js +1 -1
- package/dist/asset/css/index.css +3 -1
- package/dist/component/Icons/bilibili-line-icon.d.ts +6 -0
- package/dist/component/Icons/bilibili-line-icon.js +13 -0
- package/dist/component/Icons/index.d.ts +1 -0
- package/dist/component/Icons/index.js +1 -0
- package/dist/component/Toolbar/EditorInsert/index.js +20 -3
- package/dist/contants/enums.d.ts +5 -0
- package/dist/contants/enums.js +24 -0
- package/dist/contants/slash-commands.js +117 -119
- package/dist/extension/component/Iframe/Insert.d.ts +4 -2
- package/dist/extension/component/Iframe/Insert.js +12 -14
- package/dist/extension/component/Iframe/Readonly.d.ts +2 -1
- package/dist/extension/component/Iframe/Readonly.js +15 -6
- package/dist/extension/component/Iframe/index.js +389 -171
- package/dist/extension/component/SlashCommandsList/index.js +1 -1
- package/dist/extension/extension/StructuredDiff.d.ts +7 -1
- package/dist/extension/extension/StructuredDiff.js +34 -4
- package/dist/extension/index.js +20 -1
- package/dist/extension/node/FileHandler.d.ts +1 -1
- package/dist/extension/node/Iframe.d.ts +3 -1
- package/dist/extension/node/Iframe.js +51 -8
- package/dist/extension/node/Table.d.ts +1 -1
- package/dist/index.css +0 -1
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.js +8 -0
- package/dist/util/structuredDiff.d.ts +0 -19
- package/dist/util/structuredDiff.js +239 -275
- package/package.json +1 -1
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
2
|
-
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
-
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
4
|
-
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
5
1
|
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
6
2
|
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
7
3
|
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
8
4
|
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
5
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
6
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
7
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
8
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
9
9
|
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
10
10
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
11
11
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
12
12
|
import { generateJSON } from '@tiptap/html';
|
|
13
13
|
import DiffMatchPatch from 'diff-match-patch';
|
|
14
|
-
|
|
15
|
-
// 创建diff-match-patch实例
|
|
16
14
|
var dmp = new DiffMatchPatch();
|
|
17
|
-
|
|
18
|
-
// 类型定义
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* 将HTML转换为ProseMirror文档结构
|
|
22
|
-
* @param {string} html - HTML字符串
|
|
23
|
-
* @param {Array} extensions - Tiptap扩展数组
|
|
24
|
-
* @returns {Object} ProseMirror文档对象
|
|
25
|
-
*/
|
|
26
15
|
export function parseHtmlToDoc(html, extensions) {
|
|
27
|
-
|
|
16
|
+
try {
|
|
17
|
+
if (!html || typeof html !== 'string') {
|
|
18
|
+
throw new Error('HTML 内容无效');
|
|
19
|
+
}
|
|
20
|
+
if (!extensions || extensions.length === 0) {
|
|
21
|
+
throw new Error('扩展数组不能为空');
|
|
22
|
+
}
|
|
23
|
+
return generateJSON(html, extensions);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error('解析 HTML 到文档结构时出错:', error);
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
28
|
}
|
|
29
29
|
function haveSameMarks(a, b) {
|
|
30
30
|
var arrA = a || [];
|
|
@@ -48,191 +48,6 @@ function haveSameMarks(a, b) {
|
|
|
48
48
|
}
|
|
49
49
|
return true;
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* 对比两个ProseMirror文档节点
|
|
54
|
-
* @param {Object} nodeA - 旧文档节点
|
|
55
|
-
* @param {Object} nodeB - 新文档节点
|
|
56
|
-
* @param {Array} path - 当前节点路径
|
|
57
|
-
* @returns {Array} 差异数组
|
|
58
|
-
*/
|
|
59
|
-
function compareNodes(nodeA, nodeB) {
|
|
60
|
-
var path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
|
|
61
|
-
var diffs = [];
|
|
62
|
-
|
|
63
|
-
// 如果节点类型不同,标记整个节点为变更
|
|
64
|
-
if ((nodeA === null || nodeA === void 0 ? void 0 : nodeA.type) !== (nodeB === null || nodeB === void 0 ? void 0 : nodeB.type)) {
|
|
65
|
-
if (nodeA) {
|
|
66
|
-
diffs.push({
|
|
67
|
-
type: 'delete',
|
|
68
|
-
path: _toConsumableArray(path),
|
|
69
|
-
node: nodeA
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
if (nodeB) {
|
|
73
|
-
diffs.push({
|
|
74
|
-
type: 'insert',
|
|
75
|
-
path: _toConsumableArray(path),
|
|
76
|
-
node: nodeB
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
return diffs;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// 如果是文本节点,进行文本级别的diff
|
|
83
|
-
if ((nodeA === null || nodeA === void 0 ? void 0 : nodeA.type) === 'text' && (nodeB === null || nodeB === void 0 ? void 0 : nodeB.type) === 'text') {
|
|
84
|
-
if (nodeA.text !== nodeB.text) {
|
|
85
|
-
// 计算文本差异
|
|
86
|
-
var textDiffs = dmp.diff_main(nodeA.text || '', nodeB.text || '');
|
|
87
|
-
dmp.diff_cleanupSemantic(textDiffs);
|
|
88
|
-
|
|
89
|
-
// 检查是否有文本差异
|
|
90
|
-
// if (textDiffs.length > 1) {
|
|
91
|
-
// console.log('发现文本差异:', { oldText: nodeA.text, newText: nodeB.text, path });
|
|
92
|
-
// }
|
|
93
|
-
|
|
94
|
-
var textOffset = 0; // offset in the NEW text node
|
|
95
|
-
|
|
96
|
-
textDiffs.forEach(function (_ref) {
|
|
97
|
-
var _ref2 = _slicedToArray(_ref, 2),
|
|
98
|
-
operation = _ref2[0],
|
|
99
|
-
text = _ref2[1];
|
|
100
|
-
if (operation === -1) {
|
|
101
|
-
// Delete
|
|
102
|
-
// The widget should be placed at the current position in the new text.
|
|
103
|
-
var diffItem = {
|
|
104
|
-
type: 'delete',
|
|
105
|
-
path: _toConsumableArray(path),
|
|
106
|
-
textDiff: {
|
|
107
|
-
offset: textOffset,
|
|
108
|
-
length: text.length,
|
|
109
|
-
text: text,
|
|
110
|
-
operation: operation
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
diffs.push(diffItem);
|
|
114
|
-
// DO NOT advance textOffset
|
|
115
|
-
} else if (operation === 1) {
|
|
116
|
-
// Insert
|
|
117
|
-
var _diffItem = {
|
|
118
|
-
type: 'insert',
|
|
119
|
-
path: _toConsumableArray(path),
|
|
120
|
-
textDiff: {
|
|
121
|
-
offset: textOffset,
|
|
122
|
-
length: text.length,
|
|
123
|
-
text: text,
|
|
124
|
-
operation: operation
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
diffs.push(_diffItem);
|
|
128
|
-
textOffset += text.length; // DO advance textOffset
|
|
129
|
-
} else {
|
|
130
|
-
// Equal
|
|
131
|
-
textOffset += text.length; // DO advance textOffset
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
// 文本相等或不相等时都可检查 marks 差异(粗粒度:节点级)
|
|
136
|
-
if (!haveSameMarks(nodeA.marks, nodeB.marks)) {
|
|
137
|
-
diffs.push({
|
|
138
|
-
type: 'modify',
|
|
139
|
-
path: _toConsumableArray(path),
|
|
140
|
-
attrChange: {
|
|
141
|
-
key: 'marks',
|
|
142
|
-
oldValue: nodeA.marks || [],
|
|
143
|
-
newValue: nodeB.marks || []
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
return diffs;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// 优先:段落/标题等内联容器执行字符级 diff 和 marks 区间对比
|
|
151
|
-
if (nodeA && nodeB && isInlineContainer(nodeA) && isInlineContainer(nodeB)) {
|
|
152
|
-
// 文本与 marks 的字符级 diff
|
|
153
|
-
diffs.push.apply(diffs, _toConsumableArray(compareInlineContainer(nodeA, nodeB, path)));
|
|
154
|
-
// 非文本内联节点(如行内数学、行内公式等)的结构化对比
|
|
155
|
-
diffs.push.apply(diffs, _toConsumableArray(compareInlineContainerChildren(nodeA, nodeB, path)));
|
|
156
|
-
return diffs;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// 对比节点属性
|
|
160
|
-
var attrsA = (nodeA === null || nodeA === void 0 ? void 0 : nodeA.attrs) || {};
|
|
161
|
-
var attrsB = (nodeB === null || nodeB === void 0 ? void 0 : nodeB.attrs) || {};
|
|
162
|
-
var allAttrKeys = new Set([].concat(_toConsumableArray(Object.keys(attrsA)), _toConsumableArray(Object.keys(attrsB))));
|
|
163
|
-
for (var _i = 0, _Array$from = Array.from(allAttrKeys); _i < _Array$from.length; _i++) {
|
|
164
|
-
var key = _Array$from[_i];
|
|
165
|
-
if (attrsA[key] !== attrsB[key]) {
|
|
166
|
-
diffs.push({
|
|
167
|
-
type: 'modify',
|
|
168
|
-
path: _toConsumableArray(path),
|
|
169
|
-
attrChange: {
|
|
170
|
-
key: key,
|
|
171
|
-
oldValue: attrsA[key],
|
|
172
|
-
newValue: attrsB[key]
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// 使用 LCS 对齐子节点,减少错配
|
|
179
|
-
var contentA = (nodeA === null || nodeA === void 0 ? void 0 : nodeA.content) || [];
|
|
180
|
-
var contentB = (nodeB === null || nodeB === void 0 ? void 0 : nodeB.content) || [];
|
|
181
|
-
var pairs = lcsAlign(contentA, contentB, nodesEqualForAlign);
|
|
182
|
-
var ai = 0;
|
|
183
|
-
var bi = 0;
|
|
184
|
-
for (var _i2 = 0, _pairs = pairs; _i2 < _pairs.length; _i2++) {
|
|
185
|
-
var _pairs$_i = _slicedToArray(_pairs[_i2], 2),
|
|
186
|
-
i = _pairs$_i[0],
|
|
187
|
-
j = _pairs$_i[1];
|
|
188
|
-
// 先处理 A 中未匹配(删除),以 B 的当前位置作为锚点
|
|
189
|
-
while (ai < i) {
|
|
190
|
-
var delNode = contentA[ai];
|
|
191
|
-
diffs.push({
|
|
192
|
-
type: 'delete',
|
|
193
|
-
path: [].concat(_toConsumableArray(path), [bi]),
|
|
194
|
-
node: delNode
|
|
195
|
-
});
|
|
196
|
-
ai++;
|
|
197
|
-
}
|
|
198
|
-
// 再处理 B 中未匹配(插入)
|
|
199
|
-
while (bi < j) {
|
|
200
|
-
var insNode = contentB[bi];
|
|
201
|
-
diffs.push({
|
|
202
|
-
type: 'insert',
|
|
203
|
-
path: [].concat(_toConsumableArray(path), [bi]),
|
|
204
|
-
node: insNode
|
|
205
|
-
});
|
|
206
|
-
bi++;
|
|
207
|
-
}
|
|
208
|
-
// 匹配上的成对递归,路径以新文档索引为准
|
|
209
|
-
var childA = contentA[i];
|
|
210
|
-
var childB = contentB[j];
|
|
211
|
-
diffs.push.apply(diffs, _toConsumableArray(compareNodes(childA, childB, [].concat(_toConsumableArray(path), [j]))));
|
|
212
|
-
ai = i + 1;
|
|
213
|
-
bi = j + 1;
|
|
214
|
-
}
|
|
215
|
-
// 处理尾部剩余未匹配项
|
|
216
|
-
while (ai < contentA.length) {
|
|
217
|
-
var _delNode = contentA[ai];
|
|
218
|
-
diffs.push({
|
|
219
|
-
type: 'delete',
|
|
220
|
-
path: [].concat(_toConsumableArray(path), [bi]),
|
|
221
|
-
node: _delNode
|
|
222
|
-
});
|
|
223
|
-
ai++;
|
|
224
|
-
}
|
|
225
|
-
while (bi < contentB.length) {
|
|
226
|
-
var _insNode = contentB[bi];
|
|
227
|
-
diffs.push({
|
|
228
|
-
type: 'insert',
|
|
229
|
-
path: [].concat(_toConsumableArray(path), [bi]),
|
|
230
|
-
node: _insNode
|
|
231
|
-
});
|
|
232
|
-
bi++;
|
|
233
|
-
}
|
|
234
|
-
return diffs;
|
|
235
|
-
}
|
|
236
51
|
function isInlineContainer(node) {
|
|
237
52
|
return node.type === 'paragraph' || node.type === 'heading';
|
|
238
53
|
}
|
|
@@ -275,13 +90,12 @@ function compareInlineContainer(nodeA, nodeB, path) {
|
|
|
275
90
|
dmp.diff_cleanupSemantic(blocks);
|
|
276
91
|
var oldOffset = 0;
|
|
277
92
|
var newOffset = 0;
|
|
278
|
-
for (var
|
|
279
|
-
var _arr$_i = _slicedToArray(_arr[
|
|
93
|
+
for (var _i = 0, _arr = blocks; _i < _arr.length; _i++) {
|
|
94
|
+
var _arr$_i = _slicedToArray(_arr[_i], 2),
|
|
280
95
|
operation = _arr$_i[0],
|
|
281
96
|
text = _arr$_i[1];
|
|
282
97
|
var len = text.length;
|
|
283
98
|
if (operation === -1) {
|
|
284
|
-
// 删除:在新文本当前位置放置删除widget
|
|
285
99
|
diffs.push({
|
|
286
100
|
type: 'delete',
|
|
287
101
|
path: _toConsumableArray(path),
|
|
@@ -294,7 +108,6 @@ function compareInlineContainer(nodeA, nodeB, path) {
|
|
|
294
108
|
});
|
|
295
109
|
oldOffset += len;
|
|
296
110
|
} else if (operation === 1) {
|
|
297
|
-
// 插入:直接在新文本当前位置标注
|
|
298
111
|
diffs.push({
|
|
299
112
|
type: 'insert',
|
|
300
113
|
path: _toConsumableArray(path),
|
|
@@ -307,7 +120,6 @@ function compareInlineContainer(nodeA, nodeB, path) {
|
|
|
307
120
|
});
|
|
308
121
|
newOffset += len;
|
|
309
122
|
} else {
|
|
310
|
-
// 相等:检测 marks 差异并生成区间级 modify
|
|
311
123
|
var runStart = null;
|
|
312
124
|
for (var i = 0; i < len; i++) {
|
|
313
125
|
var oldIdx = oldOffset + i;
|
|
@@ -331,16 +143,16 @@ function compareInlineContainer(nodeA, nodeB, path) {
|
|
|
331
143
|
}
|
|
332
144
|
}
|
|
333
145
|
if (runStart !== null) {
|
|
334
|
-
var
|
|
146
|
+
var _i2 = len;
|
|
335
147
|
diffs.push({
|
|
336
148
|
type: 'modify',
|
|
337
149
|
path: _toConsumableArray(path),
|
|
338
150
|
attrChange: {
|
|
339
151
|
key: 'marks',
|
|
340
|
-
oldValue: oldMarks.slice(oldOffset + runStart, oldOffset +
|
|
341
|
-
newValue: newMarks.slice(newOffset + runStart, newOffset +
|
|
152
|
+
oldValue: oldMarks.slice(oldOffset + runStart, oldOffset + _i2),
|
|
153
|
+
newValue: newMarks.slice(newOffset + runStart, newOffset + _i2),
|
|
342
154
|
fromOffset: newOffset + runStart,
|
|
343
|
-
toOffset: newOffset +
|
|
155
|
+
toOffset: newOffset + _i2
|
|
344
156
|
}
|
|
345
157
|
});
|
|
346
158
|
}
|
|
@@ -350,31 +162,6 @@ function compareInlineContainer(nodeA, nodeB, path) {
|
|
|
350
162
|
}
|
|
351
163
|
return diffs;
|
|
352
164
|
}
|
|
353
|
-
function nodesEqualForAlign(a, b) {
|
|
354
|
-
if (!a || !b) return false;
|
|
355
|
-
if (a.type !== b.type) return false;
|
|
356
|
-
// 对部分结构节点使用关键属性辅助匹配
|
|
357
|
-
if (a.type === 'heading') {
|
|
358
|
-
var _a$attrs$level, _a$attrs, _b$attrs$level, _b$attrs;
|
|
359
|
-
return ((_a$attrs$level = (_a$attrs = a.attrs) === null || _a$attrs === void 0 ? void 0 : _a$attrs.level) !== null && _a$attrs$level !== void 0 ? _a$attrs$level : null) === ((_b$attrs$level = (_b$attrs = b.attrs) === null || _b$attrs === void 0 ? void 0 : _b$attrs.level) !== null && _b$attrs$level !== void 0 ? _b$attrs$level : null);
|
|
360
|
-
}
|
|
361
|
-
if (a.type === 'codeBlock' || a.type === 'code_block') {
|
|
362
|
-
var _ref3, _a$attrs$language, _a$attrs2, _a$attrs3, _ref4, _b$attrs$language, _b$attrs2, _b$attrs3;
|
|
363
|
-
var langA = (_ref3 = (_a$attrs$language = (_a$attrs2 = a.attrs) === null || _a$attrs2 === void 0 ? void 0 : _a$attrs2.language) !== null && _a$attrs$language !== void 0 ? _a$attrs$language : (_a$attrs3 = a.attrs) === null || _a$attrs3 === void 0 ? void 0 : _a$attrs3.lang) !== null && _ref3 !== void 0 ? _ref3 : null;
|
|
364
|
-
var langB = (_ref4 = (_b$attrs$language = (_b$attrs2 = b.attrs) === null || _b$attrs2 === void 0 ? void 0 : _b$attrs2.language) !== null && _b$attrs$language !== void 0 ? _b$attrs$language : (_b$attrs3 = b.attrs) === null || _b$attrs3 === void 0 ? void 0 : _b$attrs3.lang) !== null && _ref4 !== void 0 ? _ref4 : null;
|
|
365
|
-
return langA === langB;
|
|
366
|
-
}
|
|
367
|
-
if (a.type === 'table_cell' || a.type === 'tableHeader' || a.type === 'table_header') {
|
|
368
|
-
var _a$attrs$colspan, _a$attrs4, _b$attrs$colspan, _b$attrs4, _a$attrs$rowspan, _a$attrs5, _b$attrs$rowspan, _b$attrs5;
|
|
369
|
-
var colspanA = (_a$attrs$colspan = (_a$attrs4 = a.attrs) === null || _a$attrs4 === void 0 ? void 0 : _a$attrs4.colspan) !== null && _a$attrs$colspan !== void 0 ? _a$attrs$colspan : 1;
|
|
370
|
-
var colspanB = (_b$attrs$colspan = (_b$attrs4 = b.attrs) === null || _b$attrs4 === void 0 ? void 0 : _b$attrs4.colspan) !== null && _b$attrs$colspan !== void 0 ? _b$attrs$colspan : 1;
|
|
371
|
-
var rowspanA = (_a$attrs$rowspan = (_a$attrs5 = a.attrs) === null || _a$attrs5 === void 0 ? void 0 : _a$attrs5.rowspan) !== null && _a$attrs$rowspan !== void 0 ? _a$attrs$rowspan : 1;
|
|
372
|
-
var rowspanB = (_b$attrs$rowspan = (_b$attrs5 = b.attrs) === null || _b$attrs5 === void 0 ? void 0 : _b$attrs5.rowspan) !== null && _b$attrs$rowspan !== void 0 ? _b$attrs$rowspan : 1;
|
|
373
|
-
return colspanA === colspanB && rowspanA === rowspanB;
|
|
374
|
-
}
|
|
375
|
-
// 默认仅按类型
|
|
376
|
-
return true;
|
|
377
|
-
}
|
|
378
165
|
function compareInlineContainerChildren(nodeA, nodeB, path) {
|
|
379
166
|
var diffs = [];
|
|
380
167
|
var aList = (nodeA.content || []).map(function (n, idx) {
|
|
@@ -395,17 +182,15 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
|
|
|
395
182
|
});
|
|
396
183
|
var equals = function equals(x, y) {
|
|
397
184
|
if (!x || !y) return false;
|
|
398
|
-
// 仅按类型对齐,属性差异作为 modify 处理
|
|
399
185
|
return x.n.type === y.n.type;
|
|
400
186
|
};
|
|
401
187
|
var pairs = lcsAlign(aList, bList, equals);
|
|
402
188
|
var ai = 0,
|
|
403
189
|
bi = 0;
|
|
404
|
-
for (var
|
|
405
|
-
var
|
|
406
|
-
i =
|
|
407
|
-
j =
|
|
408
|
-
// 删除:使用新文档当前位置作为锚点路径
|
|
190
|
+
for (var _i3 = 0, _pairs = pairs; _i3 < _pairs.length; _i3++) {
|
|
191
|
+
var _pairs$_i = _slicedToArray(_pairs[_i3], 2),
|
|
192
|
+
i = _pairs$_i[0],
|
|
193
|
+
j = _pairs$_i[1];
|
|
409
194
|
while (ai < i) {
|
|
410
195
|
var del = aList[ai];
|
|
411
196
|
var anchorIdx = bi < bList.length ? bList[bi].idx : nodeB.content ? nodeB.content.length : 0;
|
|
@@ -416,7 +201,6 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
|
|
|
416
201
|
});
|
|
417
202
|
ai++;
|
|
418
203
|
}
|
|
419
|
-
// 插入:直接使用新文档该节点的实际索引
|
|
420
204
|
while (bi < j) {
|
|
421
205
|
var ins = bList[bi];
|
|
422
206
|
diffs.push({
|
|
@@ -426,7 +210,6 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
|
|
|
426
210
|
});
|
|
427
211
|
bi++;
|
|
428
212
|
}
|
|
429
|
-
// modify:同类型节点进行属性对比,路径指向新文档该内联节点索引
|
|
430
213
|
var aItem = aList[i];
|
|
431
214
|
var bItem = bList[j];
|
|
432
215
|
if (aItem && bItem) {
|
|
@@ -447,8 +230,6 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
|
|
|
447
230
|
ai = i + 1;
|
|
448
231
|
bi = j + 1;
|
|
449
232
|
}
|
|
450
|
-
|
|
451
|
-
// 尾部删除
|
|
452
233
|
while (ai < aList.length) {
|
|
453
234
|
var _del = aList[ai++];
|
|
454
235
|
var _anchorIdx = bi < bList.length ? bList[bi].idx : nodeB.content ? nodeB.content.length : 0;
|
|
@@ -458,7 +239,6 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
|
|
|
458
239
|
node: _del.n
|
|
459
240
|
});
|
|
460
241
|
}
|
|
461
|
-
// 尾部插入
|
|
462
242
|
while (bi < bList.length) {
|
|
463
243
|
var _ins = bList[bi++];
|
|
464
244
|
diffs.push({
|
|
@@ -469,6 +249,29 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
|
|
|
469
249
|
}
|
|
470
250
|
return diffs;
|
|
471
251
|
}
|
|
252
|
+
function nodesEqualForAlign(a, b) {
|
|
253
|
+
if (!a || !b) return false;
|
|
254
|
+
if (a.type !== b.type) return false;
|
|
255
|
+
if (a.type === 'heading') {
|
|
256
|
+
var _a$attrs$level, _a$attrs, _b$attrs$level, _b$attrs;
|
|
257
|
+
return ((_a$attrs$level = (_a$attrs = a.attrs) === null || _a$attrs === void 0 ? void 0 : _a$attrs.level) !== null && _a$attrs$level !== void 0 ? _a$attrs$level : null) === ((_b$attrs$level = (_b$attrs = b.attrs) === null || _b$attrs === void 0 ? void 0 : _b$attrs.level) !== null && _b$attrs$level !== void 0 ? _b$attrs$level : null);
|
|
258
|
+
}
|
|
259
|
+
if (a.type === 'codeBlock' || a.type === 'code_block') {
|
|
260
|
+
var _ref, _a$attrs$language, _a$attrs2, _a$attrs3, _ref2, _b$attrs$language, _b$attrs2, _b$attrs3;
|
|
261
|
+
var langA = (_ref = (_a$attrs$language = (_a$attrs2 = a.attrs) === null || _a$attrs2 === void 0 ? void 0 : _a$attrs2.language) !== null && _a$attrs$language !== void 0 ? _a$attrs$language : (_a$attrs3 = a.attrs) === null || _a$attrs3 === void 0 ? void 0 : _a$attrs3.lang) !== null && _ref !== void 0 ? _ref : null;
|
|
262
|
+
var langB = (_ref2 = (_b$attrs$language = (_b$attrs2 = b.attrs) === null || _b$attrs2 === void 0 ? void 0 : _b$attrs2.language) !== null && _b$attrs$language !== void 0 ? _b$attrs$language : (_b$attrs3 = b.attrs) === null || _b$attrs3 === void 0 ? void 0 : _b$attrs3.lang) !== null && _ref2 !== void 0 ? _ref2 : null;
|
|
263
|
+
return langA === langB;
|
|
264
|
+
}
|
|
265
|
+
if (a.type === 'table_cell' || a.type === 'tableHeader' || a.type === 'table_header') {
|
|
266
|
+
var _a$attrs$colspan, _a$attrs4, _b$attrs$colspan, _b$attrs4, _a$attrs$rowspan, _a$attrs5, _b$attrs$rowspan, _b$attrs5;
|
|
267
|
+
var colspanA = (_a$attrs$colspan = (_a$attrs4 = a.attrs) === null || _a$attrs4 === void 0 ? void 0 : _a$attrs4.colspan) !== null && _a$attrs$colspan !== void 0 ? _a$attrs$colspan : 1;
|
|
268
|
+
var colspanB = (_b$attrs$colspan = (_b$attrs4 = b.attrs) === null || _b$attrs4 === void 0 ? void 0 : _b$attrs4.colspan) !== null && _b$attrs$colspan !== void 0 ? _b$attrs$colspan : 1;
|
|
269
|
+
var rowspanA = (_a$attrs$rowspan = (_a$attrs5 = a.attrs) === null || _a$attrs5 === void 0 ? void 0 : _a$attrs5.rowspan) !== null && _a$attrs$rowspan !== void 0 ? _a$attrs$rowspan : 1;
|
|
270
|
+
var rowspanB = (_b$attrs$rowspan = (_b$attrs5 = b.attrs) === null || _b$attrs5 === void 0 ? void 0 : _b$attrs5.rowspan) !== null && _b$attrs$rowspan !== void 0 ? _b$attrs$rowspan : 1;
|
|
271
|
+
return colspanA === colspanB && rowspanA === rowspanB;
|
|
272
|
+
}
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
472
275
|
function lcsAlign(a, b, equals) {
|
|
473
276
|
var n = a.length;
|
|
474
277
|
var m = b.length;
|
|
@@ -477,9 +280,9 @@ function lcsAlign(a, b, equals) {
|
|
|
477
280
|
}, function () {
|
|
478
281
|
return Array(m + 1).fill(0);
|
|
479
282
|
});
|
|
480
|
-
for (var
|
|
283
|
+
for (var _i4 = n - 1; _i4 >= 0; _i4--) {
|
|
481
284
|
for (var _j = m - 1; _j >= 0; _j--) {
|
|
482
|
-
dp[
|
|
285
|
+
dp[_i4][_j] = equals(a[_i4], b[_j]) ? 1 + dp[_i4 + 1][_j + 1] : Math.max(dp[_i4 + 1][_j], dp[_i4][_j + 1]);
|
|
483
286
|
}
|
|
484
287
|
}
|
|
485
288
|
var pairs = [];
|
|
@@ -498,51 +301,212 @@ function lcsAlign(a, b, equals) {
|
|
|
498
301
|
}
|
|
499
302
|
return pairs;
|
|
500
303
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
304
|
+
function compareNodes(nodeA, nodeB) {
|
|
305
|
+
var path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
|
|
306
|
+
var diffs = [];
|
|
307
|
+
if ((nodeA === null || nodeA === void 0 ? void 0 : nodeA.type) !== (nodeB === null || nodeB === void 0 ? void 0 : nodeB.type)) {
|
|
308
|
+
if (nodeA) {
|
|
309
|
+
diffs.push({
|
|
310
|
+
type: 'delete',
|
|
311
|
+
path: _toConsumableArray(path),
|
|
312
|
+
node: nodeA
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
if (nodeB) {
|
|
316
|
+
diffs.push({
|
|
317
|
+
type: 'insert',
|
|
318
|
+
path: _toConsumableArray(path),
|
|
319
|
+
node: nodeB
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
return diffs;
|
|
323
|
+
}
|
|
324
|
+
if ((nodeA === null || nodeA === void 0 ? void 0 : nodeA.type) === 'text' && (nodeB === null || nodeB === void 0 ? void 0 : nodeB.type) === 'text') {
|
|
325
|
+
if (nodeA.text !== nodeB.text) {
|
|
326
|
+
var textDiffs = dmp.diff_main(nodeA.text || '', nodeB.text || '');
|
|
327
|
+
dmp.diff_cleanupSemantic(textDiffs);
|
|
328
|
+
var textOffset = 0;
|
|
329
|
+
textDiffs.forEach(function (_ref3) {
|
|
330
|
+
var _ref4 = _slicedToArray(_ref3, 2),
|
|
331
|
+
operation = _ref4[0],
|
|
332
|
+
text = _ref4[1];
|
|
333
|
+
if (operation === -1) {
|
|
334
|
+
var diffItem = {
|
|
335
|
+
type: 'delete',
|
|
336
|
+
path: _toConsumableArray(path),
|
|
337
|
+
textDiff: {
|
|
338
|
+
offset: textOffset,
|
|
339
|
+
length: text.length,
|
|
340
|
+
text: text,
|
|
341
|
+
operation: operation
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
diffs.push(diffItem);
|
|
345
|
+
} else if (operation === 1) {
|
|
346
|
+
var _diffItem = {
|
|
347
|
+
type: 'insert',
|
|
348
|
+
path: _toConsumableArray(path),
|
|
349
|
+
textDiff: {
|
|
350
|
+
offset: textOffset,
|
|
351
|
+
length: text.length,
|
|
352
|
+
text: text,
|
|
353
|
+
operation: operation
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
diffs.push(_diffItem);
|
|
357
|
+
textOffset += text.length;
|
|
358
|
+
} else {
|
|
359
|
+
textOffset += text.length;
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
if (!haveSameMarks(nodeA.marks, nodeB.marks)) {
|
|
364
|
+
diffs.push({
|
|
365
|
+
type: 'modify',
|
|
366
|
+
path: _toConsumableArray(path),
|
|
367
|
+
attrChange: {
|
|
368
|
+
key: 'marks',
|
|
369
|
+
oldValue: nodeA.marks || [],
|
|
370
|
+
newValue: nodeB.marks || []
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
return diffs;
|
|
375
|
+
}
|
|
376
|
+
if (nodeA && nodeB && isInlineContainer(nodeA) && isInlineContainer(nodeB)) {
|
|
377
|
+
diffs.push.apply(diffs, _toConsumableArray(compareInlineContainer(nodeA, nodeB, path)));
|
|
378
|
+
diffs.push.apply(diffs, _toConsumableArray(compareInlineContainerChildren(nodeA, nodeB, path)));
|
|
379
|
+
return diffs;
|
|
380
|
+
}
|
|
381
|
+
var attrsA = (nodeA === null || nodeA === void 0 ? void 0 : nodeA.attrs) || {};
|
|
382
|
+
var attrsB = (nodeB === null || nodeB === void 0 ? void 0 : nodeB.attrs) || {};
|
|
383
|
+
var allAttrKeys = new Set([].concat(_toConsumableArray(Object.keys(attrsA)), _toConsumableArray(Object.keys(attrsB))));
|
|
384
|
+
for (var _i5 = 0, _Array$from = Array.from(allAttrKeys); _i5 < _Array$from.length; _i5++) {
|
|
385
|
+
var key = _Array$from[_i5];
|
|
386
|
+
if (attrsA[key] !== attrsB[key]) {
|
|
387
|
+
diffs.push({
|
|
388
|
+
type: 'modify',
|
|
389
|
+
path: _toConsumableArray(path),
|
|
390
|
+
attrChange: {
|
|
391
|
+
key: key,
|
|
392
|
+
oldValue: attrsA[key],
|
|
393
|
+
newValue: attrsB[key]
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
var contentA = (nodeA === null || nodeA === void 0 ? void 0 : nodeA.content) || [];
|
|
399
|
+
var contentB = (nodeB === null || nodeB === void 0 ? void 0 : nodeB.content) || [];
|
|
400
|
+
var pairs = lcsAlign(contentA, contentB, nodesEqualForAlign);
|
|
401
|
+
var ai = 0;
|
|
402
|
+
var bi = 0;
|
|
403
|
+
var _iterator3 = _createForOfIteratorHelper(pairs),
|
|
404
|
+
_step3;
|
|
405
|
+
try {
|
|
406
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
407
|
+
var _step3$value = _slicedToArray(_step3.value, 2),
|
|
408
|
+
i = _step3$value[0],
|
|
409
|
+
j = _step3$value[1];
|
|
410
|
+
while (ai < i) {
|
|
411
|
+
var _delNode = contentA[ai];
|
|
412
|
+
diffs.push({
|
|
413
|
+
type: 'delete',
|
|
414
|
+
path: [].concat(_toConsumableArray(path), [bi]),
|
|
415
|
+
node: _delNode
|
|
416
|
+
});
|
|
417
|
+
ai++;
|
|
418
|
+
}
|
|
419
|
+
while (bi < j) {
|
|
420
|
+
var _insNode = contentB[bi];
|
|
421
|
+
diffs.push({
|
|
422
|
+
type: 'insert',
|
|
423
|
+
path: [].concat(_toConsumableArray(path), [bi]),
|
|
424
|
+
node: _insNode
|
|
425
|
+
});
|
|
426
|
+
bi++;
|
|
427
|
+
}
|
|
428
|
+
var childA = contentA[i];
|
|
429
|
+
var childB = contentB[j];
|
|
430
|
+
diffs.push.apply(diffs, _toConsumableArray(compareNodes(childA, childB, [].concat(_toConsumableArray(path), [j]))));
|
|
431
|
+
ai = i + 1;
|
|
432
|
+
bi = j + 1;
|
|
433
|
+
}
|
|
434
|
+
} catch (err) {
|
|
435
|
+
_iterator3.e(err);
|
|
436
|
+
} finally {
|
|
437
|
+
_iterator3.f();
|
|
438
|
+
}
|
|
439
|
+
while (ai < contentA.length) {
|
|
440
|
+
var delNode = contentA[ai];
|
|
441
|
+
diffs.push({
|
|
442
|
+
type: 'delete',
|
|
443
|
+
path: [].concat(_toConsumableArray(path), [bi]),
|
|
444
|
+
node: delNode
|
|
445
|
+
});
|
|
446
|
+
ai++;
|
|
447
|
+
}
|
|
448
|
+
while (bi < contentB.length) {
|
|
449
|
+
var insNode = contentB[bi];
|
|
450
|
+
diffs.push({
|
|
451
|
+
type: 'insert',
|
|
452
|
+
path: [].concat(_toConsumableArray(path), [bi]),
|
|
453
|
+
node: insNode
|
|
454
|
+
});
|
|
455
|
+
bi++;
|
|
456
|
+
}
|
|
457
|
+
return diffs;
|
|
458
|
+
}
|
|
509
459
|
export function compareDocuments(oldHtml, newHtml, extensions) {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
460
|
+
try {
|
|
461
|
+
var docA = parseHtmlToDoc(oldHtml, extensions);
|
|
462
|
+
var docB = parseHtmlToDoc(newHtml, extensions);
|
|
463
|
+
var diffs = compareNodes(docA, docB);
|
|
464
|
+
return {
|
|
465
|
+
oldDoc: docA,
|
|
466
|
+
newDoc: docB,
|
|
467
|
+
diffs: diffs,
|
|
468
|
+
hasChanges: diffs.length > 0
|
|
469
|
+
};
|
|
470
|
+
} catch (error) {
|
|
471
|
+
console.error('对比文档时出错:', error);
|
|
472
|
+
return {
|
|
473
|
+
oldDoc: null,
|
|
474
|
+
newDoc: null,
|
|
475
|
+
diffs: [],
|
|
476
|
+
hasChanges: false
|
|
477
|
+
};
|
|
478
|
+
}
|
|
519
479
|
}
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* 将路径转换为ProseMirror位置
|
|
523
|
-
* @param {Array} path - 节点路径
|
|
524
|
-
* @param {Object} doc - ProseMirror文档
|
|
525
|
-
* @returns {number} 文档位置
|
|
526
|
-
*/
|
|
527
480
|
export function pathToPos(path, doc) {
|
|
481
|
+
if (!path || path.length === 0) {
|
|
482
|
+
return 0;
|
|
483
|
+
}
|
|
484
|
+
if (!doc) {
|
|
485
|
+
throw new Error('文档节点不能为空');
|
|
486
|
+
}
|
|
528
487
|
var pos = 0;
|
|
529
488
|
var current = doc;
|
|
530
489
|
for (var i = 0; i < path.length; i++) {
|
|
531
|
-
var _current$childCount;
|
|
490
|
+
var _current$type, _current$childCount;
|
|
532
491
|
var index = path[i];
|
|
533
|
-
var contentStartOffset = current.type.name === 'doc' ? 0 : 1;
|
|
492
|
+
var contentStartOffset = ((_current$type = current.type) === null || _current$type === void 0 ? void 0 : _current$type.name) === 'doc' ? 0 : 1;
|
|
534
493
|
var resolvedPos = pos + contentStartOffset;
|
|
535
494
|
var childCount = (_current$childCount = current.childCount) !== null && _current$childCount !== void 0 ? _current$childCount : 0;
|
|
536
495
|
var effectiveIndex = Math.min(index, childCount);
|
|
537
496
|
for (var j = 0; j < effectiveIndex; j++) {
|
|
538
497
|
var child = current.child(j);
|
|
498
|
+
if (!child) {
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
539
501
|
resolvedPos += child.nodeSize;
|
|
540
502
|
}
|
|
541
503
|
pos = resolvedPos;
|
|
542
504
|
if (index < childCount) {
|
|
543
505
|
current = current.child(index);
|
|
506
|
+
if (!current) {
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
544
509
|
} else {
|
|
545
|
-
// Path points past the end in this doc (likely a deletion). Stop descending
|
|
546
510
|
break;
|
|
547
511
|
}
|
|
548
512
|
}
|