@ctzhian/tiptap 2.1.16 → 2.1.18

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.
@@ -13,7 +13,7 @@ import { Box } from '@mui/material';
13
13
  import React, { useCallback, useEffect, useState } from 'react';
14
14
  import "../index.css";
15
15
  var Reader = function Reader() {
16
- var _useState = useState("本文用以记录 Gitlab 相关问题及解答\n\n![https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg](https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg)\n\n## 我在使用 `git@git.in.chaitin.net:ns/repo` 时可以访问仓库,但是 `https://git.in.chaitin.net/ns/repo` 无法访问\n\n问题通常出现 git clone 与其他依赖 git 进行的操作,如 `go get` 等,具体报错可能为 `Permission Denied`.\n\n在使用 curl 借助 `CI_JOB_TOKEN` 获取其他仓库 cicd job 产物或者 generic package 时,其具体报错为 `404 Not Found` 的问题.\n\n原因是在使用 `git@git.in.chaitin.net` 时,使用的是 ssh 协议,此时默认使用的是 `~/.ssh` 下的私钥进行认证你在 gitlab 中添加的 `SSH Keys`。而使用 `https://git.in.chaitin.net/ns/repo` 时,使用的是 http 协议,此时默认使用的是 `~/.netrc` 认证你在 gitlab 中申请的 `Access tokens`。部分软件如 `go get` 默认使用的便是 http 来拉取代码,因此需要额外配置。\n\n这里推荐两种解决方案:\n\n1. 配置 `~/.netrc` 文件(推荐)\n\n 在 ~/.netrc 文件中添加以下配置:\n\n ```text\n machine git.in.chaitin.net login git password <your access token>\n ```\n\n 在 gitlab cicd job 中遇到拉取其他仓库时遇到权限问题可以使用本配置,比如可以在 job 的 `before_script` 阶段添加以下命令:\n\n ```shell\n echo \"machine git.in.chaitin.net login git password $CI_JOB_TOKEN\" >> ~/.netrc\n ```\n\n 注意: 其中 `$CI_JOB_TOKEN` 是 job 运行期间生成的 token,其权限与 trigger 用户相同,详见 [CI Job Token](https://docs.gitlab.com/ci/jobs/ci_job_token/)。其 Token 权限由 `pipeline 触发者`权限以及`目标仓库权限`共同决定。因此被拉取的目标仓库也需要保证其 `Setting -> CI/CD -> Job token permissions` 配置正确,允许源仓库的 CI/CD 能够访问到该仓库,否则依然会出现如 `404 Not Found`, `403 Forbidden` 的权限问题。(如果你是 pipeline 触发者,可以手动在浏览器通过 gitlab api 访问目标仓库的 generic package 或者 job artifact 如果可以正常下载,说明是 `Job token permissions` 问题)\n\n2. 配置 `git url replace`\n\n 在 ~/.gitconfig 文件中添加以下配置:\n\n ```ini\n [url \"git@git.in.chaitin.net:\"]\n insteadOf = https://git.in.chaitin.net/\n ```\n\n 这个配置可以将所有 `https://git.in.chaitin.net/` 请求替换为 `git@git.in.chaitin.net:` 使用 ssh 来拉取代码仓库\n\n## 我在 clone gitlab 仓库时没问题,但是 lfs 遇到了 EOF 问题\n\nEOF 在大多数情况下由代理导致,如果代理不允许客户端访问某个网站,行为可能是提早结束连接,导致 `EOF` 错误。如\n\n> 在 ubunu 虚拟机里无法拉取 safeline-aliyun 项目里的 lfs 文件怎么处理?\n\n```bash\nroot@OPS-5108:~/proj/safeline-aliyun# git lfs fetch --all\nfetch: 34 object(s) found, done.\nfetch: Fetching all references...\nbatch response: Post https://git.in.chaitin.net/patronus/safeline-aliyun.git/info/lfs/objects/batch: EOF\nerror: failed to fetch some objects from 'https://git.in.chaitin.net/patronus/safeline-aliyun.git/info/lfs'\n```\n\n可以看到返回了 EOF 问题,经查代理未配置在 git config 中。从 `env` 中可以看到用户配置了 *_proxy 但其中发现 `no_proxy` 配置不正确:\n\n```shell\nroot@OPS-5108:~/proj/safeline-aliyun# env | grep pro\nno_proxy=localhost, 127.0.0.1, ::1\nPWD=/root/proj/safeline-aliyun\nftp_proxy=http://proxy.in.chaitin.net:8123\nhttps_proxy=http://proxy.in.chaitin.net:8123\nproxy=http://proxy.in.chaitin.net:8123\nhttp_proxy=http://proxy.in.chaitin.net:8123\nOLDPWD=/root/proj\n```\n\n需要按照 [代理配置](https://info.chaitin.net/colab-editor/page/%E7%A0%94%E5%8F%91%E4%BD%93%E7%B3%BB%2F%E7%A0%94%E5%8F%91%E6%94%AF%E6%8C%81%2F%E4%BB%A3%E7%90%86%E6%89%AB%E7%9B%B2) 进行正确配置后,重新执行操作,发现 EOF 问题被解决。\n\n## 我在访问公司内部服务时报错 `x509: certificate signed by unknown authority`\n\n公司部分内部服务采用自签名证书,导致客户端在访问这些服务时会遇到 `x509: certificate signed by unknown authority` 错误。为了确保客户端能够信任这些自签名证书,你需要配置信任自签名证书即 CA。\n\n以 debian 系系统举例:\n\n```shell\ncurl -o /usr/local/share/ca-certificates/chaitin_ca.crt -L https://chaitin-ops-public.cn-beijing.oss.aliyuncs.com/Chaitin_Ltd_Root_CA.pem\nupdate-ca-certificates\n```\n\n如果无法访问外网,可以尝试 `http://s3-ephemeral.in.chaitin.net/dev/Chaitin_Ltd_Root_CA.pem`\n\n其他系统 CA 证书安装请参考 [安装CA证书](https://info.chaitin.net/colab-editor/page/IT%E5%8A%9E%E5%85%AC/%E5%8A%9E%E5%85%AC%E7%BD%91%E7%BB%9C/windows%E7%94%A8%E6%88%B7/%E5%A4%87%E9%80%89%E6%96%B9%E6%A1%88%EF%BC%88Windows%EF%BC%89/%E8%AF%81%E4%B9%A6%E5%AE%89%E8%A3%85%28windows%29/%E9%95%BF%E4%BA%AD%E6%A0%B9%E8%AF%81%E4%B9%A6%E5%AE%89%E8%A3%85%28windows%29)\n"),
16
+ var _useState = useState("本文用以记录 Gitlab 相关问题及解答\n\n## 我在使用 `git@git.in.chaitin.net:ns/repo` 时可以访问仓库,但是 `https://git.in.chaitin.net/ns/repo` 无法访问\n\n问题通常出现 git clone 与其他依赖 git 进行的操作,如 `go get` 等,具体报错可能为 `Permission Denied`.\n\n在使用 curl 借助 `CI_JOB_TOKEN` 获取其他仓库 cicd job 产物或者 generic package 时,其具体报错为 `404 Not Found` 的问题.\n\n原因是在使用 `git@git.in.chaitin.net` 时,使用的是 ssh 协议,此时默认使用的是 `~/.ssh` 下的私钥进行认证你在 gitlab 中添加的 `SSH Keys`。而使用 `https://git.in.chaitin.net/ns/repo` 时,使用的是 http 协议,此时默认使用的是 `~/.netrc` 认证你在 gitlab 中申请的 `Access tokens`。部分软件如 `go get` 默认使用的便是 http 来拉取代码,因此需要额外配置。\n\n这里推荐两种解决方案:\n\n1. 配置 `~/.netrc` 文件(推荐)\n\n 在 ~/.netrc 文件中添加以下配置:\n\n ```text\n machine git.in.chaitin.net login git password <your access token>\n ```\n\n 在 gitlab cicd job 中遇到拉取其他仓库时遇到权限问题可以使用本配置,比如可以在 job 的 `before_script` 阶段添加以下命令:\n\n ```shell\n echo \"machine git.in.chaitin.net login git password $CI_JOB_TOKEN\" >> ~/.netrc\n ```\n\n 注意: 其中 `$CI_JOB_TOKEN` 是 job 运行期间生成的 token,其权限与 trigger 用户相同,详见 [CI Job Token](https://docs.gitlab.com/ci/jobs/ci_job_token/)。其 Token 权限由 `pipeline 触发者`权限以及`目标仓库权限`共同决定。因此被拉取的目标仓库也需要保证其 `Setting -> CI/CD -> Job token permissions` 配置正确,允许源仓库的 CI/CD 能够访问到该仓库,否则依然会出现如 `404 Not Found`, `403 Forbidden` 的权限问题。(如果你是 pipeline 触发者,可以手动在浏览器通过 gitlab api 访问目标仓库的 generic package 或者 job artifact 如果可以正常下载,说明是 `Job token permissions` 问题)\n\n2. 配置 `git url replace`\n\n 在 ~/.gitconfig 文件中添加以下配置:\n\n ```ini\n [url \"git@git.in.chaitin.net:\"]\n insteadOf = https://git.in.chaitin.net/\n ```\n\n 这个配置可以将所有 `https://git.in.chaitin.net/` 请求替换为 `git@git.in.chaitin.net:` 使用 ssh 来拉取代码仓库\n\n## 我在 clone gitlab 仓库时没问题,但是 lfs 遇到了 EOF 问题\n\nEOF 在大多数情况下由代理导致,如果代理不允许客户端访问某个网站,行为可能是提早结束连接,导致 `EOF` 错误。如\n\n> 在 ubunu 虚拟机里无法拉取 safeline-aliyun 项目里的 lfs 文件怎么处理?\n\n```bash\nroot@OPS-5108:~/proj/safeline-aliyun# git lfs fetch --all\nfetch: 34 object(s) found, done.\nfetch: Fetching all references...\nbatch response: Post https://git.in.chaitin.net/patronus/safeline-aliyun.git/info/lfs/objects/batch: EOF\nerror: failed to fetch some objects from 'https://git.in.chaitin.net/patronus/safeline-aliyun.git/info/lfs'\n```\n\n可以看到返回了 EOF 问题,经查代理未配置在 git config 中。从 `env` 中可以看到用户配置了 *_proxy 但其中发现 `no_proxy` 配置不正确:\n\n```shell\nroot@OPS-5108:~/proj/safeline-aliyun# env | grep pro\nno_proxy=localhost, 127.0.0.1, ::1\nPWD=/root/proj/safeline-aliyun\nftp_proxy=http://proxy.in.chaitin.net:8123\nhttps_proxy=http://proxy.in.chaitin.net:8123\nproxy=http://proxy.in.chaitin.net:8123\nhttp_proxy=http://proxy.in.chaitin.net:8123\nOLDPWD=/root/proj\n```\n\n需要按照 [代理配置](https://info.chaitin.net/colab-editor/page/%E7%A0%94%E5%8F%91%E4%BD%93%E7%B3%BB%2F%E7%A0%94%E5%8F%91%E6%94%AF%E6%8C%81%2F%E4%BB%A3%E7%90%86%E6%89%AB%E7%9B%B2) 进行正确配置后,重新执行操作,发现 EOF 问题被解决。\n\n## 我在访问公司内部服务时报错 `x509: certificate signed by unknown authority`\n\n公司部分内部服务采用自签名证书,导致客户端在访问这些服务时会遇到 `x509: certificate signed by unknown authority` 错误。为了确保客户端能够信任这些自签名证书,你需要配置信任自签名证书即 CA。\n\n以 debian 系系统举例:\n\n```shell\ncurl -o /usr/local/share/ca-certificates/chaitin_ca.crt -L https://chaitin-ops-public.cn-beijing.oss.aliyuncs.com/Chaitin_Ltd_Root_CA.pem\nupdate-ca-certificates\n```\n\n如果无法访问外网,可以尝试 `http://s3-ephemeral.in.chaitin.net/dev/Chaitin_Ltd_Root_CA.pem`\n\n其他系统 CA 证书安装请参考 [安装CA证书](https://info.chaitin.net/colab-editor/page/IT%E5%8A%9E%E5%85%AC/%E5%8A%9E%E5%85%AC%E7%BD%91%E7%BB%9C/windows%E7%94%A8%E6%88%B7/%E5%A4%87%E9%80%89%E6%96%B9%E6%A1%88%EF%BC%88Windows%EF%BC%89/%E8%AF%81%E4%B9%A6%E5%AE%89%E8%A3%85%28windows%29/%E9%95%BF%E4%BA%AD%E6%A0%B9%E8%AF%81%E4%B9%A6%E5%AE%89%E8%A3%85%28windows%29)\n"),
17
17
  _useState2 = _slicedToArray(_useState, 2),
18
18
  mdContent = _useState2[0],
19
19
  setMdContent = _useState2[1];
@@ -4,7 +4,7 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
4
4
  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; }
5
5
  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; } }
6
6
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
- import { Box, IconButton, Stack, Tooltip } from '@mui/material';
7
+ import { Box, IconButton, Stack } from '@mui/material';
8
8
  import React, { useCallback, useContext, useEffect, useState } from 'react';
9
9
  import { createPortal } from 'react-dom';
10
10
  import { AnticlockwiseLineIcon, ClockwiseLineIcon, CloseCircleFillIcon, Download2LineIcon, FullscreenExitLineIcon, FullscreenLineIcon, ResetLeftFillIcon, SkipLeftIcon, SkipRightIcon } from "../Icons";
@@ -142,9 +142,6 @@ export var CustomToolbar = function CustomToolbar() {
142
142
  padding: '8px 12px',
143
143
  backdropFilter: 'blur(10px)'
144
144
  }
145
- }, /*#__PURE__*/React.createElement(Tooltip, {
146
- title: "\u4E0A\u4E00\u5F20",
147
- placement: "top"
148
145
  }, /*#__PURE__*/React.createElement(IconButton, {
149
146
  onClick: onPrevImage,
150
147
  sx: iconButtonSx,
@@ -154,10 +151,7 @@ export var CustomToolbar = function CustomToolbar() {
154
151
  sx: {
155
152
  fontSize: '20px'
156
153
  }
157
- }))), /*#__PURE__*/React.createElement(Tooltip, {
158
- title: "\u4E0B\u4E00\u5F20",
159
- placement: "top"
160
- }, /*#__PURE__*/React.createElement(IconButton, {
154
+ })), /*#__PURE__*/React.createElement(IconButton, {
161
155
  onClick: onNextImage,
162
156
  sx: iconButtonSx,
163
157
  size: "small",
@@ -166,28 +160,19 @@ export var CustomToolbar = function CustomToolbar() {
166
160
  sx: {
167
161
  fontSize: '20px'
168
162
  }
169
- }))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(Tooltip, {
170
- title: "\u653E\u5927",
171
- placement: "top"
172
- }, /*#__PURE__*/React.createElement(IconButton, {
163
+ })), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(IconButton, {
173
164
  onClick: function onClick() {
174
165
  return handleZoom(0.5);
175
166
  },
176
167
  sx: iconButtonSx,
177
168
  size: "small"
178
- }, /*#__PURE__*/React.createElement(ZoomInIcon, null))), /*#__PURE__*/React.createElement(Tooltip, {
179
- title: "\u7F29\u5C0F",
180
- placement: "top"
181
- }, /*#__PURE__*/React.createElement(IconButton, {
169
+ }, /*#__PURE__*/React.createElement(ZoomInIcon, null)), /*#__PURE__*/React.createElement(IconButton, {
182
170
  onClick: function onClick() {
183
171
  return handleZoom(-0.5);
184
172
  },
185
173
  sx: iconButtonSx,
186
174
  size: "small"
187
- }, /*#__PURE__*/React.createElement(ZoomOutIcon, null))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(Tooltip, {
188
- title: "\u9006\u65F6\u9488\u65CB\u8F6C",
189
- placement: "top"
190
- }, /*#__PURE__*/React.createElement(IconButton, {
175
+ }, /*#__PURE__*/React.createElement(ZoomOutIcon, null)), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(IconButton, {
191
176
  onClick: function onClick() {
192
177
  return handleRotate(-90);
193
178
  },
@@ -197,10 +182,7 @@ export var CustomToolbar = function CustomToolbar() {
197
182
  sx: {
198
183
  fontSize: '20px'
199
184
  }
200
- }))), /*#__PURE__*/React.createElement(Tooltip, {
201
- title: "\u987A\u65F6\u9488\u65CB\u8F6C",
202
- placement: "top"
203
- }, /*#__PURE__*/React.createElement(IconButton, {
185
+ })), /*#__PURE__*/React.createElement(IconButton, {
204
186
  onClick: function onClick() {
205
187
  return handleRotate(90);
206
188
  },
@@ -210,10 +192,7 @@ export var CustomToolbar = function CustomToolbar() {
210
192
  sx: {
211
193
  fontSize: '20px'
212
194
  }
213
- }))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(Tooltip, {
214
- title: "\u91CD\u7F6E",
215
- placement: "top"
216
- }, /*#__PURE__*/React.createElement(IconButton, {
195
+ })), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(IconButton, {
217
196
  onClick: handleReset,
218
197
  sx: iconButtonSx,
219
198
  size: "small"
@@ -221,10 +200,7 @@ export var CustomToolbar = function CustomToolbar() {
221
200
  sx: {
222
201
  fontSize: '20px'
223
202
  }
224
- }))), currentSrc && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(Tooltip, {
225
- title: "\u4E0B\u8F7D",
226
- placement: "top"
227
- }, /*#__PURE__*/React.createElement(IconButton, {
203
+ })), currentSrc && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(IconButton, {
228
204
  onClick: handleDownload,
229
205
  sx: iconButtonSx,
230
206
  size: "small"
@@ -232,10 +208,7 @@ export var CustomToolbar = function CustomToolbar() {
232
208
  sx: {
233
209
  fontSize: '20px'
234
210
  }
235
- })))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(Tooltip, {
236
- title: isFullscreen ? '退出全屏' : '全屏',
237
- placement: "top"
238
- }, /*#__PURE__*/React.createElement(IconButton, {
211
+ }))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(IconButton, {
239
212
  onClick: handleFullscreen,
240
213
  sx: iconButtonSx,
241
214
  size: "small"
@@ -247,10 +220,7 @@ export var CustomToolbar = function CustomToolbar() {
247
220
  sx: {
248
221
  fontSize: '20px'
249
222
  }
250
- }))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(Tooltip, {
251
- title: "\u5173\u95ED",
252
- placement: "top"
253
- }, /*#__PURE__*/React.createElement(IconButton, {
223
+ })), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(IconButton, {
254
224
  onClick: handleClose,
255
225
  sx: iconButtonSx,
256
226
  size: "small"
@@ -258,7 +228,7 @@ export var CustomToolbar = function CustomToolbar() {
258
228
  sx: {
259
229
  fontSize: '20px'
260
230
  }
261
- })))));
231
+ }))));
262
232
  if (typeof document !== 'undefined') {
263
233
  return /*#__PURE__*/createPortal(toolbarContent, document.body);
264
234
  }
@@ -9,13 +9,7 @@ declare module '@tiptap/core' {
9
9
  };
10
10
  }
11
11
  }
12
- import { GetExtensionsProps } from '../../type';
13
- export interface StructuredDiffOptions {
14
- getExtensionConfig?: () => Omit<GetExtensionsProps, 'editable'> & {
15
- editable: false;
16
- };
17
- }
18
- export declare const StructuredDiffExtension: Extension<StructuredDiffOptions, any>;
12
+ export declare const StructuredDiffExtension: Extension<any, any>;
19
13
  export { diffPluginKey };
20
14
  export declare function getDiffState(editor: Editor): {
21
15
  isActive: any;
@@ -1,12 +1,4 @@
1
1
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
- function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
5
- 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."); }
6
- 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); }
7
- function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
8
- function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
9
- 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; }
10
2
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
11
3
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
12
4
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
@@ -17,7 +9,6 @@ import { Extension } from '@tiptap/core';
17
9
  import { Plugin, PluginKey } from '@tiptap/pm/state';
18
10
  import { createDecorationsFromDiffs, createEmptyDecorationSet } from "../../util/decorations";
19
11
  import { compareDocuments } from "../../util/structuredDiff";
20
- import { getExtensions } from "../index";
21
12
  var diffPluginKey = new PluginKey('structuredDiff');
22
13
  var DiffPluginState = /*#__PURE__*/function () {
23
14
  function DiffPluginState(decorations) {
@@ -53,40 +44,20 @@ var DiffPluginState = /*#__PURE__*/function () {
53
44
  }
54
45
  }], [{
55
46
  key: "init",
56
- value: function init(_config, state) {
47
+ value: function init(config, state) {
57
48
  return new DiffPluginState(createEmptyDecorationSet(state.doc), [], false);
58
49
  }
59
50
  }]);
60
51
  return DiffPluginState;
61
52
  }();
62
- function getExtensionsForParsing(editor, getExtensionConfig) {
63
- if (getExtensionConfig) {
64
- var config = getExtensionConfig();
65
- if (config) {
66
- var exclude = [].concat(_toConsumableArray(config.exclude || []), ['structuredDiff']);
67
- return getExtensions(_objectSpread(_objectSpread({}, config), {}, {
68
- exclude: exclude,
69
- editable: false
70
- }));
71
- }
72
- }
73
- return editor.extensionManager.extensions.filter(function (ext) {
74
- return ext.name !== 'structuredDiff';
75
- });
76
- }
77
53
  export var StructuredDiffExtension = Extension.create({
78
54
  name: 'structuredDiff',
79
- addOptions: function addOptions() {
80
- return {
81
- getExtensionConfig: undefined
82
- };
83
- },
84
55
  addProseMirrorPlugins: function addProseMirrorPlugins() {
85
56
  return [new Plugin({
86
57
  key: diffPluginKey,
87
58
  state: {
88
59
  init: DiffPluginState.init,
89
- apply: DiffPluginState.prototype.apply.bind(DiffPluginState.prototype)
60
+ apply: DiffPluginState.prototype.apply
90
61
  },
91
62
  props: {
92
63
  decorations: function decorations(state) {
@@ -97,7 +68,6 @@ export var StructuredDiffExtension = Extension.create({
97
68
  })];
98
69
  },
99
70
  addCommands: function addCommands() {
100
- var _this = this;
101
71
  return {
102
72
  showStructuredDiff: function showStructuredDiff(oldHtml, newHtml) {
103
73
  return function (_ref) {
@@ -106,8 +76,8 @@ export var StructuredDiffExtension = Extension.create({
106
76
  dispatch = _ref.dispatch,
107
77
  editor = _ref.editor;
108
78
  try {
109
- var extensionsForParsing = getExtensionsForParsing(editor, _this.options.getExtensionConfig);
110
- var comparison = compareDocuments(oldHtml, newHtml, extensionsForParsing);
79
+ var extensions = editor.extensionManager.extensions;
80
+ var comparison = compareDocuments(oldHtml, newHtml, extensions);
111
81
  if (!comparison.hasChanges) {
112
82
  return false;
113
83
  }
@@ -150,26 +150,7 @@ export var getExtensions = function getExtensions(_ref) {
150
150
  } else {
151
151
  // 只读模式
152
152
  if (!(exclude !== null && exclude !== void 0 && exclude.includes('structuredDiff'))) {
153
- defaultExtensions.push(StructuredDiffExtension.configure({
154
- getExtensionConfig: function getExtensionConfig() {
155
- return {
156
- contentType: contentType,
157
- limit: limit,
158
- exclude: [].concat(_toConsumableArray(exclude || []), ['structuredDiff']),
159
- extensions: extensionsProps,
160
- youtube: youtube,
161
- editable: false,
162
- mentionItems: mentionItems,
163
- onMentionFilter: onMentionFilter,
164
- onUpload: onUpload,
165
- onError: onError,
166
- onTocUpdate: onTocUpdate,
167
- onAiWritingGetSuggestion: onAiWritingGetSuggestion,
168
- onValidateUrl: onValidateUrl,
169
- placeholder: _placeholder
170
- };
171
- }
172
- }));
153
+ defaultExtensions.push(StructuredDiffExtension);
173
154
  }
174
155
  }
175
156
  if (!(exclude !== null && exclude !== void 0 && exclude.includes('mention')) && (mentionItems && mentionItems.length > 0 || onMentionFilter)) {
@@ -35,6 +35,25 @@ export interface ProseMirrorNode {
35
35
  attrs?: Record<string, any>;
36
36
  }>;
37
37
  }
38
+ /**
39
+ * 将HTML转换为ProseMirror文档结构
40
+ * @param {string} html - HTML字符串
41
+ * @param {Array} extensions - Tiptap扩展数组
42
+ * @returns {Object} ProseMirror文档对象
43
+ */
38
44
  export declare function parseHtmlToDoc(html: string, extensions: Extensions): any;
45
+ /**
46
+ * 对比两个HTML文档并生成结构化差异
47
+ * @param {string} oldHtml - 旧HTML
48
+ * @param {string} newHtml - 新HTML
49
+ * @param {Array} extensions - Tiptap扩展数组
50
+ * @returns {Object} 包含差异信息的对象
51
+ */
39
52
  export declare function compareDocuments(oldHtml: string, newHtml: string, extensions: Extensions): DocumentComparison;
53
+ /**
54
+ * 将路径转换为ProseMirror位置
55
+ * @param {Array} path - 节点路径
56
+ * @param {Object} doc - ProseMirror文档
57
+ * @returns {number} 文档位置
58
+ */
40
59
  export declare function pathToPos(path: number[], doc: any): number;
@@ -1,30 +1,30 @@
1
- function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
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."); }
3
- function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
4
- function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
5
1
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
6
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."); }
7
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; } }
8
4
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
5
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
6
+ 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
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
8
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(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实例
14
16
  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
+ */
15
26
  export function parseHtmlToDoc(html, extensions) {
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
- }
27
+ return generateJSON(html, extensions);
28
28
  }
29
29
  function haveSameMarks(a, b) {
30
30
  var arrA = a || [];
@@ -48,6 +48,191 @@ 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
+ }
51
236
  function isInlineContainer(node) {
52
237
  return node.type === 'paragraph' || node.type === 'heading';
53
238
  }
@@ -90,12 +275,13 @@ function compareInlineContainer(nodeA, nodeB, path) {
90
275
  dmp.diff_cleanupSemantic(blocks);
91
276
  var oldOffset = 0;
92
277
  var newOffset = 0;
93
- for (var _i = 0, _arr = blocks; _i < _arr.length; _i++) {
94
- var _arr$_i = _slicedToArray(_arr[_i], 2),
278
+ for (var _i3 = 0, _arr = blocks; _i3 < _arr.length; _i3++) {
279
+ var _arr$_i = _slicedToArray(_arr[_i3], 2),
95
280
  operation = _arr$_i[0],
96
281
  text = _arr$_i[1];
97
282
  var len = text.length;
98
283
  if (operation === -1) {
284
+ // 删除:在新文本当前位置放置删除widget
99
285
  diffs.push({
100
286
  type: 'delete',
101
287
  path: _toConsumableArray(path),
@@ -108,6 +294,7 @@ function compareInlineContainer(nodeA, nodeB, path) {
108
294
  });
109
295
  oldOffset += len;
110
296
  } else if (operation === 1) {
297
+ // 插入:直接在新文本当前位置标注
111
298
  diffs.push({
112
299
  type: 'insert',
113
300
  path: _toConsumableArray(path),
@@ -120,6 +307,7 @@ function compareInlineContainer(nodeA, nodeB, path) {
120
307
  });
121
308
  newOffset += len;
122
309
  } else {
310
+ // 相等:检测 marks 差异并生成区间级 modify
123
311
  var runStart = null;
124
312
  for (var i = 0; i < len; i++) {
125
313
  var oldIdx = oldOffset + i;
@@ -143,16 +331,16 @@ function compareInlineContainer(nodeA, nodeB, path) {
143
331
  }
144
332
  }
145
333
  if (runStart !== null) {
146
- var _i2 = len;
334
+ var _i4 = len;
147
335
  diffs.push({
148
336
  type: 'modify',
149
337
  path: _toConsumableArray(path),
150
338
  attrChange: {
151
339
  key: 'marks',
152
- oldValue: oldMarks.slice(oldOffset + runStart, oldOffset + _i2),
153
- newValue: newMarks.slice(newOffset + runStart, newOffset + _i2),
340
+ oldValue: oldMarks.slice(oldOffset + runStart, oldOffset + _i4),
341
+ newValue: newMarks.slice(newOffset + runStart, newOffset + _i4),
154
342
  fromOffset: newOffset + runStart,
155
- toOffset: newOffset + _i2
343
+ toOffset: newOffset + _i4
156
344
  }
157
345
  });
158
346
  }
@@ -162,6 +350,31 @@ function compareInlineContainer(nodeA, nodeB, path) {
162
350
  }
163
351
  return diffs;
164
352
  }
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
+ }
165
378
  function compareInlineContainerChildren(nodeA, nodeB, path) {
166
379
  var diffs = [];
167
380
  var aList = (nodeA.content || []).map(function (n, idx) {
@@ -182,15 +395,17 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
182
395
  });
183
396
  var equals = function equals(x, y) {
184
397
  if (!x || !y) return false;
398
+ // 仅按类型对齐,属性差异作为 modify 处理
185
399
  return x.n.type === y.n.type;
186
400
  };
187
401
  var pairs = lcsAlign(aList, bList, equals);
188
402
  var ai = 0,
189
403
  bi = 0;
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];
404
+ for (var _i5 = 0, _pairs2 = pairs; _i5 < _pairs2.length; _i5++) {
405
+ var _pairs2$_i = _slicedToArray(_pairs2[_i5], 2),
406
+ i = _pairs2$_i[0],
407
+ j = _pairs2$_i[1];
408
+ // 删除:使用新文档当前位置作为锚点路径
194
409
  while (ai < i) {
195
410
  var del = aList[ai];
196
411
  var anchorIdx = bi < bList.length ? bList[bi].idx : nodeB.content ? nodeB.content.length : 0;
@@ -201,6 +416,7 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
201
416
  });
202
417
  ai++;
203
418
  }
419
+ // 插入:直接使用新文档该节点的实际索引
204
420
  while (bi < j) {
205
421
  var ins = bList[bi];
206
422
  diffs.push({
@@ -210,6 +426,7 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
210
426
  });
211
427
  bi++;
212
428
  }
429
+ // modify:同类型节点进行属性对比,路径指向新文档该内联节点索引
213
430
  var aItem = aList[i];
214
431
  var bItem = bList[j];
215
432
  if (aItem && bItem) {
@@ -230,6 +447,8 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
230
447
  ai = i + 1;
231
448
  bi = j + 1;
232
449
  }
450
+
451
+ // 尾部删除
233
452
  while (ai < aList.length) {
234
453
  var _del = aList[ai++];
235
454
  var _anchorIdx = bi < bList.length ? bList[bi].idx : nodeB.content ? nodeB.content.length : 0;
@@ -239,6 +458,7 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
239
458
  node: _del.n
240
459
  });
241
460
  }
461
+ // 尾部插入
242
462
  while (bi < bList.length) {
243
463
  var _ins = bList[bi++];
244
464
  diffs.push({
@@ -249,29 +469,6 @@ function compareInlineContainerChildren(nodeA, nodeB, path) {
249
469
  }
250
470
  return diffs;
251
471
  }
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
- }
275
472
  function lcsAlign(a, b, equals) {
276
473
  var n = a.length;
277
474
  var m = b.length;
@@ -280,9 +477,9 @@ function lcsAlign(a, b, equals) {
280
477
  }, function () {
281
478
  return Array(m + 1).fill(0);
282
479
  });
283
- for (var _i4 = n - 1; _i4 >= 0; _i4--) {
480
+ for (var _i6 = n - 1; _i6 >= 0; _i6--) {
284
481
  for (var _j = m - 1; _j >= 0; _j--) {
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]);
482
+ dp[_i6][_j] = equals(a[_i6], b[_j]) ? 1 + dp[_i6 + 1][_j + 1] : Math.max(dp[_i6 + 1][_j], dp[_i6][_j + 1]);
286
483
  }
287
484
  }
288
485
  var pairs = [];
@@ -301,212 +498,51 @@ function lcsAlign(a, b, equals) {
301
498
  }
302
499
  return pairs;
303
500
  }
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
- }
501
+
502
+ /**
503
+ * 对比两个HTML文档并生成结构化差异
504
+ * @param {string} oldHtml - 旧HTML
505
+ * @param {string} newHtml - 新HTML
506
+ * @param {Array} extensions - Tiptap扩展数组
507
+ * @returns {Object} 包含差异信息的对象
508
+ */
459
509
  export function compareDocuments(oldHtml, newHtml, extensions) {
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
- }
510
+ var docA = parseHtmlToDoc(oldHtml, extensions);
511
+ var docB = parseHtmlToDoc(newHtml, extensions);
512
+ var diffs = compareNodes(docA, docB);
513
+ return {
514
+ oldDoc: docA,
515
+ newDoc: docB,
516
+ diffs: diffs,
517
+ hasChanges: diffs.length > 0
518
+ };
479
519
  }
520
+
521
+ /**
522
+ * 将路径转换为ProseMirror位置
523
+ * @param {Array} path - 节点路径
524
+ * @param {Object} doc - ProseMirror文档
525
+ * @returns {number} 文档位置
526
+ */
480
527
  export function pathToPos(path, doc) {
481
- if (!path || path.length === 0) {
482
- return 0;
483
- }
484
- if (!doc) {
485
- throw new Error('文档节点不能为空');
486
- }
487
528
  var pos = 0;
488
529
  var current = doc;
489
530
  for (var i = 0; i < path.length; i++) {
490
- var _current$type, _current$childCount;
531
+ var _current$childCount;
491
532
  var index = path[i];
492
- var contentStartOffset = ((_current$type = current.type) === null || _current$type === void 0 ? void 0 : _current$type.name) === 'doc' ? 0 : 1;
533
+ var contentStartOffset = current.type.name === 'doc' ? 0 : 1;
493
534
  var resolvedPos = pos + contentStartOffset;
494
535
  var childCount = (_current$childCount = current.childCount) !== null && _current$childCount !== void 0 ? _current$childCount : 0;
495
536
  var effectiveIndex = Math.min(index, childCount);
496
537
  for (var j = 0; j < effectiveIndex; j++) {
497
538
  var child = current.child(j);
498
- if (!child) {
499
- break;
500
- }
501
539
  resolvedPos += child.nodeSize;
502
540
  }
503
541
  pos = resolvedPos;
504
542
  if (index < childCount) {
505
543
  current = current.child(index);
506
- if (!current) {
507
- break;
508
- }
509
544
  } else {
545
+ // Path points past the end in this doc (likely a deletion). Stop descending
510
546
  break;
511
547
  }
512
548
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctzhian/tiptap",
3
- "version": "2.1.16",
3
+ "version": "2.1.18",
4
4
  "description": "基于 Tiptap 二次开发的编辑器组件",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",