@ai-matrx/office 0.8.28 → 0.8.30
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/CHANGELOG.md +37 -1
- package/dist/docs.cjs +123 -116
- package/dist/docs.cjs.map +1 -1
- package/dist/docs.d.cts +5 -0
- package/dist/docs.d.ts +5 -0
- package/dist/docs.js +104 -97
- package/dist/docs.js.map +1 -1
- package/dist/sheets-comment-anchors.cjs +13 -4
- package/dist/sheets-comment-anchors.cjs.map +1 -1
- package/dist/sheets-comment-anchors.js +13 -4
- package/dist/sheets-comment-anchors.js.map +1 -1
- package/dist/univer-collab.cjs +49 -5
- package/dist/univer-collab.cjs.map +1 -1
- package/dist/univer-collab.d.cts +7 -0
- package/dist/univer-collab.d.ts +7 -0
- package/dist/univer-collab.js +49 -5
- package/dist/univer-collab.js.map +1 -1
- package/package.json +5 -5
package/dist/docs.js
CHANGED
|
@@ -50,11 +50,111 @@ function takeCovered(snapshot) {
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// src/docs/comment-anchors.ts
|
|
54
|
+
import { BuildTextUtils, CustomRangeType, JSONX } from "@univerjs/core";
|
|
55
|
+
var COMMENT_ANCHOR_RANGE_TYPE = CustomRangeType.COMMENT;
|
|
56
|
+
var COMMENT_ANCHOR_PART_PREFIX = "anchor:";
|
|
57
|
+
var COMMENT_ANCHOR_LABEL_MAX = 200;
|
|
58
|
+
var ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
59
|
+
function newCommentAnchorId() {
|
|
60
|
+
const bytes = new Uint8Array(16);
|
|
61
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
62
|
+
let out = "c";
|
|
63
|
+
for (const b of bytes) out += ID_ALPHABET[b % ID_ALPHABET.length];
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function commentAnchorPartKey(anchorId) {
|
|
67
|
+
return `${COMMENT_ANCHOR_PART_PREFIX}${anchorId}`;
|
|
68
|
+
}
|
|
69
|
+
function anchorIdOfPartAnchor(anchor) {
|
|
70
|
+
if (!anchor || typeof anchor !== "object") return null;
|
|
71
|
+
const a = anchor;
|
|
72
|
+
if ((a.__kind === "part_anchor" || a.__kind === "text_anchor") && typeof a.anchor_id === "string" && a.anchor_id.length > 0) return a.anchor_id;
|
|
73
|
+
if (a.__kind !== "part_anchor" || typeof a.part_key !== "string") return null;
|
|
74
|
+
if (!a.part_key.startsWith(COMMENT_ANCHOR_PART_PREFIX)) return null;
|
|
75
|
+
const id = a.part_key.slice(COMMENT_ANCHOR_PART_PREFIX.length);
|
|
76
|
+
return id.length > 0 ? id : null;
|
|
77
|
+
}
|
|
78
|
+
function quoteOfCommentAnchor(anchor) {
|
|
79
|
+
if (!anchor || typeof anchor !== "object") return "";
|
|
80
|
+
const a = anchor;
|
|
81
|
+
return typeof a.label === "string" ? a.label : typeof a.exact === "string" ? a.exact : "";
|
|
82
|
+
}
|
|
83
|
+
function commentPartAnchor(anchorId, quote) {
|
|
84
|
+
const label = quote.replace(/\s+/g, " ").trim().slice(0, COMMENT_ANCHOR_LABEL_MAX);
|
|
85
|
+
return { __kind: "part_anchor", part_key: commentAnchorPartKey(anchorId), ...label ? { label } : {} };
|
|
86
|
+
}
|
|
87
|
+
var CONTROL = /[\u0000-\u001f\u007f]/g;
|
|
88
|
+
function commentAnchorsOf(body) {
|
|
89
|
+
const out = /* @__PURE__ */ new Map();
|
|
90
|
+
const b = body ?? {};
|
|
91
|
+
const stream = typeof b.dataStream === "string" ? b.dataStream : "";
|
|
92
|
+
for (const r of b.customRanges ?? []) {
|
|
93
|
+
if (!r || r.rangeType !== COMMENT_ANCHOR_RANGE_TYPE || typeof r.rangeId !== "string") continue;
|
|
94
|
+
const start = r.startIndex;
|
|
95
|
+
const end = r.endIndex + 1;
|
|
96
|
+
if (!(end > start)) continue;
|
|
97
|
+
const had = out.get(r.rangeId);
|
|
98
|
+
const s2 = had ? Math.min(had.start, start) : start;
|
|
99
|
+
const e2 = had ? Math.max(had.end, end) : end;
|
|
100
|
+
out.set(r.rangeId, { id: r.rangeId, start: s2, end: e2, text: "" });
|
|
101
|
+
}
|
|
102
|
+
for (const span of out.values()) span.text = stream.slice(span.start, span.end).replace(CONTROL, " ");
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
function addCommentAnchorActions(body, start, end, anchorId) {
|
|
106
|
+
if (!(end > start) || start < 0) return null;
|
|
107
|
+
const textX = BuildTextUtils.customRange.add({
|
|
108
|
+
body,
|
|
109
|
+
ranges: [{ startOffset: start, endOffset: end, collapsed: false }],
|
|
110
|
+
rangeId: anchorId,
|
|
111
|
+
rangeType: COMMENT_ANCHOR_RANGE_TYPE
|
|
112
|
+
});
|
|
113
|
+
if (!textX) return null;
|
|
114
|
+
return JSONX.getInstance().editOp(textX.serialize(), ["body"]);
|
|
115
|
+
}
|
|
116
|
+
function removeCommentAnchorActions(documentDataModel, anchorId) {
|
|
117
|
+
const textX = BuildTextUtils.customRange.delete({ documentDataModel, rangeId: anchorId });
|
|
118
|
+
if (!textX) return null;
|
|
119
|
+
return JSONX.getInstance().editOp(textX.serialize(), ["body"]);
|
|
120
|
+
}
|
|
121
|
+
var RETAIN_KEYS = /* @__PURE__ */ new Set(["t", "len", "body", "coverType"]);
|
|
122
|
+
var RANGE_KEYS = /* @__PURE__ */ new Set(["rangeId", "rangeType", "startIndex", "endIndex", "properties"]);
|
|
123
|
+
var isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
124
|
+
var keysOf = (o) => Object.keys(o).filter((k) => o[k] !== void 0);
|
|
125
|
+
function isDocsAnchorOnlyOp(op) {
|
|
126
|
+
if (!Array.isArray(op) || op.length !== 2 || op[0] !== "body") return false;
|
|
127
|
+
const x = op[1];
|
|
128
|
+
if (!isObj(x) || x.et !== "text-x" || !Array.isArray(x.e) || x.e.length === 0) return false;
|
|
129
|
+
if (keysOf(x).some((k) => k !== "et" && k !== "e")) return false;
|
|
130
|
+
for (const c of x.e) {
|
|
131
|
+
if (!isObj(c) || c.t !== "r" || typeof c.len !== "number") return false;
|
|
132
|
+
if (keysOf(c).some((k) => !RETAIN_KEYS.has(k))) return false;
|
|
133
|
+
if ("coverType" in c && typeof c.coverType !== "number") return false;
|
|
134
|
+
if ("body" in c) {
|
|
135
|
+
const b = c.body;
|
|
136
|
+
if (!isObj(b) || keysOf(b).some((k) => k !== "dataStream" && k !== "customRanges")) return false;
|
|
137
|
+
if (b.dataStream !== void 0 && b.dataStream !== "") return false;
|
|
138
|
+
if (!Array.isArray(b.customRanges) || b.customRanges.length === 0) return false;
|
|
139
|
+
for (const r of b.customRanges) {
|
|
140
|
+
if (!isObj(r) || r.rangeType !== COMMENT_ANCHOR_RANGE_TYPE) return false;
|
|
141
|
+
if (keysOf(r).some((k) => !RANGE_KEYS.has(k))) return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
53
148
|
// src/docs/document-model.ts
|
|
54
149
|
var RICH_TEXT_EDITING_ID = "doc.mutation.rich-text-editing";
|
|
55
150
|
var COMMAND_TYPE = 0;
|
|
56
151
|
var DEPTH_GUARDED = /* @__PURE__ */ Symbol.for("ai-matrx.office.docs.command-depth-guard");
|
|
57
152
|
var DOCUMENT_SAVE_DELAY_MS = 2500;
|
|
153
|
+
function isCommentAnchorMutation(info) {
|
|
154
|
+
if (info.id !== RICH_TEXT_EDITING_ID) return false;
|
|
155
|
+
const params = info.params;
|
|
156
|
+
return !!params && !params.segmentId && isDocsAnchorOnlyOp(params.actions);
|
|
157
|
+
}
|
|
58
158
|
var viewIds = 0;
|
|
59
159
|
var DocumentModel = class {
|
|
60
160
|
documentId;
|
|
@@ -193,7 +293,9 @@ var DocumentModel = class {
|
|
|
193
293
|
onViewMutation(viewId, info, options) {
|
|
194
294
|
if (this.relaying || options?.fromCollab || options?.fromChangeset) return;
|
|
195
295
|
const view = this.views.get(viewId);
|
|
196
|
-
if (!view
|
|
296
|
+
if (!view) return;
|
|
297
|
+
const editable = view.port.editable();
|
|
298
|
+
if (!editable && !(view.port.commentOnly?.() === true && isCommentAnchorMutation(info))) return;
|
|
197
299
|
this.lastEditedView = viewId;
|
|
198
300
|
this.relay(info, viewId);
|
|
199
301
|
for (const listener of this.collabListeners) listener(info, options);
|
|
@@ -208,7 +310,7 @@ var DocumentModel = class {
|
|
|
208
310
|
view.pre = null;
|
|
209
311
|
for (const listener of Array.from(this.otListeners)) listener(m);
|
|
210
312
|
}
|
|
211
|
-
if (isContentMutation(info)) this.markDirty();
|
|
313
|
+
if (editable && isContentMutation(info)) this.markDirty();
|
|
212
314
|
}
|
|
213
315
|
/**
|
|
214
316
|
* Per view: the outermost command running (a mutation's group label) and, while a room listens, the document
|
|
@@ -959,101 +1061,6 @@ var RemoteCaretBook = class {
|
|
|
959
1061
|
return out;
|
|
960
1062
|
}
|
|
961
1063
|
};
|
|
962
|
-
|
|
963
|
-
// src/docs/comment-anchors.ts
|
|
964
|
-
import { BuildTextUtils, CustomRangeType, JSONX } from "@univerjs/core";
|
|
965
|
-
var COMMENT_ANCHOR_RANGE_TYPE = CustomRangeType.COMMENT;
|
|
966
|
-
var COMMENT_ANCHOR_PART_PREFIX = "anchor:";
|
|
967
|
-
var COMMENT_ANCHOR_LABEL_MAX = 200;
|
|
968
|
-
var ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
969
|
-
function newCommentAnchorId() {
|
|
970
|
-
const bytes = new Uint8Array(16);
|
|
971
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
972
|
-
let out = "c";
|
|
973
|
-
for (const b of bytes) out += ID_ALPHABET[b % ID_ALPHABET.length];
|
|
974
|
-
return out;
|
|
975
|
-
}
|
|
976
|
-
function commentAnchorPartKey(anchorId) {
|
|
977
|
-
return `${COMMENT_ANCHOR_PART_PREFIX}${anchorId}`;
|
|
978
|
-
}
|
|
979
|
-
function anchorIdOfPartAnchor(anchor) {
|
|
980
|
-
if (!anchor || typeof anchor !== "object") return null;
|
|
981
|
-
const a = anchor;
|
|
982
|
-
if ((a.__kind === "part_anchor" || a.__kind === "text_anchor") && typeof a.anchor_id === "string" && a.anchor_id.length > 0) return a.anchor_id;
|
|
983
|
-
if (a.__kind !== "part_anchor" || typeof a.part_key !== "string") return null;
|
|
984
|
-
if (!a.part_key.startsWith(COMMENT_ANCHOR_PART_PREFIX)) return null;
|
|
985
|
-
const id = a.part_key.slice(COMMENT_ANCHOR_PART_PREFIX.length);
|
|
986
|
-
return id.length > 0 ? id : null;
|
|
987
|
-
}
|
|
988
|
-
function quoteOfCommentAnchor(anchor) {
|
|
989
|
-
if (!anchor || typeof anchor !== "object") return "";
|
|
990
|
-
const a = anchor;
|
|
991
|
-
return typeof a.label === "string" ? a.label : typeof a.exact === "string" ? a.exact : "";
|
|
992
|
-
}
|
|
993
|
-
function commentPartAnchor(anchorId, quote) {
|
|
994
|
-
const label = quote.replace(/\s+/g, " ").trim().slice(0, COMMENT_ANCHOR_LABEL_MAX);
|
|
995
|
-
return { __kind: "part_anchor", part_key: commentAnchorPartKey(anchorId), ...label ? { label } : {} };
|
|
996
|
-
}
|
|
997
|
-
var CONTROL = /[\u0000-\u001f\u007f]/g;
|
|
998
|
-
function commentAnchorsOf(body) {
|
|
999
|
-
const out = /* @__PURE__ */ new Map();
|
|
1000
|
-
const b = body ?? {};
|
|
1001
|
-
const stream = typeof b.dataStream === "string" ? b.dataStream : "";
|
|
1002
|
-
for (const r of b.customRanges ?? []) {
|
|
1003
|
-
if (!r || r.rangeType !== COMMENT_ANCHOR_RANGE_TYPE || typeof r.rangeId !== "string") continue;
|
|
1004
|
-
const start = r.startIndex;
|
|
1005
|
-
const end = r.endIndex + 1;
|
|
1006
|
-
if (!(end > start)) continue;
|
|
1007
|
-
const had = out.get(r.rangeId);
|
|
1008
|
-
const s2 = had ? Math.min(had.start, start) : start;
|
|
1009
|
-
const e2 = had ? Math.max(had.end, end) : end;
|
|
1010
|
-
out.set(r.rangeId, { id: r.rangeId, start: s2, end: e2, text: "" });
|
|
1011
|
-
}
|
|
1012
|
-
for (const span of out.values()) span.text = stream.slice(span.start, span.end).replace(CONTROL, " ");
|
|
1013
|
-
return out;
|
|
1014
|
-
}
|
|
1015
|
-
function addCommentAnchorActions(body, start, end, anchorId) {
|
|
1016
|
-
if (!(end > start) || start < 0) return null;
|
|
1017
|
-
const textX = BuildTextUtils.customRange.add({
|
|
1018
|
-
body,
|
|
1019
|
-
ranges: [{ startOffset: start, endOffset: end, collapsed: false }],
|
|
1020
|
-
rangeId: anchorId,
|
|
1021
|
-
rangeType: COMMENT_ANCHOR_RANGE_TYPE
|
|
1022
|
-
});
|
|
1023
|
-
if (!textX) return null;
|
|
1024
|
-
return JSONX.getInstance().editOp(textX.serialize(), ["body"]);
|
|
1025
|
-
}
|
|
1026
|
-
function removeCommentAnchorActions(documentDataModel, anchorId) {
|
|
1027
|
-
const textX = BuildTextUtils.customRange.delete({ documentDataModel, rangeId: anchorId });
|
|
1028
|
-
if (!textX) return null;
|
|
1029
|
-
return JSONX.getInstance().editOp(textX.serialize(), ["body"]);
|
|
1030
|
-
}
|
|
1031
|
-
var RETAIN_KEYS = /* @__PURE__ */ new Set(["t", "len", "body", "coverType"]);
|
|
1032
|
-
var RANGE_KEYS = /* @__PURE__ */ new Set(["rangeId", "rangeType", "startIndex", "endIndex", "properties"]);
|
|
1033
|
-
var isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
1034
|
-
var keysOf = (o) => Object.keys(o).filter((k) => o[k] !== void 0);
|
|
1035
|
-
function isDocsAnchorOnlyOp(op) {
|
|
1036
|
-
if (!Array.isArray(op) || op.length !== 2 || op[0] !== "body") return false;
|
|
1037
|
-
const x = op[1];
|
|
1038
|
-
if (!isObj(x) || x.et !== "text-x" || !Array.isArray(x.e) || x.e.length === 0) return false;
|
|
1039
|
-
if (keysOf(x).some((k) => k !== "et" && k !== "e")) return false;
|
|
1040
|
-
for (const c of x.e) {
|
|
1041
|
-
if (!isObj(c) || c.t !== "r" || typeof c.len !== "number") return false;
|
|
1042
|
-
if (keysOf(c).some((k) => !RETAIN_KEYS.has(k))) return false;
|
|
1043
|
-
if ("coverType" in c && typeof c.coverType !== "number") return false;
|
|
1044
|
-
if ("body" in c) {
|
|
1045
|
-
const b = c.body;
|
|
1046
|
-
if (!isObj(b) || keysOf(b).some((k) => k !== "dataStream" && k !== "customRanges")) return false;
|
|
1047
|
-
if (b.dataStream !== void 0 && b.dataStream !== "") return false;
|
|
1048
|
-
if (!Array.isArray(b.customRanges) || b.customRanges.length === 0) return false;
|
|
1049
|
-
for (const r of b.customRanges) {
|
|
1050
|
-
if (!isObj(r) || r.rangeType !== COMMENT_ANCHOR_RANGE_TYPE) return false;
|
|
1051
|
-
if (keysOf(r).some((k) => !RANGE_KEYS.has(k))) return false;
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
return true;
|
|
1056
|
-
}
|
|
1057
1064
|
export {
|
|
1058
1065
|
CARET_HEARTBEAT_MS,
|
|
1059
1066
|
CARET_MAX_RANGES,
|