@ai-matrx/office 0.8.23 → 0.8.25
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 +1 -15
- package/dist/univer-collab.cjs +188 -10
- package/dist/univer-collab.cjs.map +1 -1
- package/dist/univer-collab.d.cts +31 -2
- package/dist/univer-collab.d.ts +31 -2
- package/dist/univer-collab.js +190 -10
- package/dist/univer-collab.js.map +1 -1
- package/package.json +10 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.8.
|
|
3
|
+
## 0.8.25
|
|
4
4
|
### C9: comment anchors that follow concurrent edits
|
|
5
5
|
|
|
6
6
|
- **Docs:** `addCommentAnchorActions(body, start, end, id)` anchors a passage with a `COMMENT` custom range (Univer's own builder, so the op has the link family's shape C0 proved); `commentAnchorsOf(body)` reads every anchor back (split pieces joined, Univer's inclusive end as `[start, end)`); `removeCommentAnchorActions` takes a cancelled draft's anchor out; `commentPartAnchor` / `anchorIdOfPartAnchor` are the thread's `part_anchor` (`anchor:<id>`, quote as `label`). Fuzz on the C0 corpora: anchor × every captured family and anchor × anchor, 0 divergences in 180,000 checks at 2,000 seeds; red check without a transform.
|
|
7
7
|
- **Sheets:** `installSheetCommentAnchors(univer)` registers `matrx.mutation.set-comment-anchor`, the `SHEET_MATRX_COMMENT_ANCHORS_PLUGIN` resource and a listener that moves anchors through every applied row/column insert, remove and move (and drops them with their row, column or sheet). `transformCommentAnchor` (own file) is called first by `transformMutation`; the registry declares the id (family `anchor`), and the census exempts our own ids from the Univer scan. Fuzz: 40,000 checks, 0 divergences (it caught the same anchor id on two sheets being treated as one); two headless seats: B5 becomes B6 when a peer inserts a row above, survives save and reload, and is gone on both seats when its row is deleted. The fold installs the anchors too.
|
|
8
8
|
- New export `./sheets/comment-anchors`. Consumer action: call `installSheetCommentAnchors(univer)` before creating a workbook unit that co-edits comments.
|
|
9
9
|
|
|
10
|
-
## 0.8.22
|
|
11
10
|
### C5c: Sheets co-editing — merge divergence fixed, number formats, counts and sheets travel
|
|
12
11
|
|
|
13
12
|
- **Merge divergence across chained row/column deletes, fixed at its cause.** Univer 1.0.4's structural commands only fix the merges that intersect the COMMAND's range on the other axis (any `-by-range` call with a partial range, an API call) and only while its ref-range registration is current (never refreshed after a content load or a remove-merge). A cut merge it skipped stayed put on the sender while every transform moved it, so seats ended a column apart (the session fuzz's merge at column -1 vs 0). Capture now completes the command (`mergeFixupsOwed`): the cut merges still on the sheet are removed right before the structural mutation and re-added at their model position right after it, in the traveling group and on the sender alike. Multi-seat session fuzz: 0 hash mismatches (was 2–18 per run).
|
|
@@ -21,19 +20,6 @@
|
|
|
21
20
|
- `SHEETS_COLLAB_PROTO` = 2: a room opened by this build is raised to proto 2 (when its checkpoint is at head) and older tabs open it read-only, so seats with and without merge completion never share a room.
|
|
22
21
|
- Consumer action: none.
|
|
23
22
|
|
|
24
|
-
## 0.8.21
|
|
25
|
-
### C5c: Sheets co-editing — merge divergence fixed, number formats, counts and sheets travel
|
|
26
|
-
|
|
27
|
-
- **Merge divergence across chained row/column deletes, fixed at its cause.** Univer 1.0.4's structural commands only fix the merges that intersect the COMMAND's range on the other axis (any `-by-range` call with a partial range, an API call) and only while its ref-range registration is current (never refreshed after a content load or a remove-merge). A cut merge it skipped stayed put on the sender while every transform moved it, so seats ended a column apart (the session fuzz's merge at column -1 vs 0). Capture now completes the command (`mergeFixupsOwed`): the cut merges still on the sheet are removed right before the structural mutation and re-added at their model position right after it, in the traveling group and on the sender alike. Multi-seat session fuzz: 0 hash mismatches (was 2–18 per run).
|
|
28
|
-
- **Number formats travel** (`sheet.mutation.set.numfmt` / `remove.numfmt`, family `numfmt`): typing a date or a currency no longer rolls back. Ranges follow row/column inserts, removes and moves cell by cell; against another write of the style key `n` (a numfmt, a style with `n`, a style clear, a cell delete) the later-committed op wins.
|
|
29
|
-
- **Row/column counts travel** (`set-worksheet-row-count` / `-column-count`, family `count`): a concurrent insert/remove on that axis shifts the count; two counts at once, the larger wins. "Refresh from table" growing a sheet is no longer rolled back.
|
|
30
|
-
- **Sheets: add, remove, order travel** (family `sheet`): the sheet order is transformed as one more axis. Capture records a removed sheet's index and how many sheets are left (`annotateSheetOps`, side-car `sheetIndex`, `sheetsLeft`); an insert-sheet's styles are inlined (`inlineSheetStyles`). An edit to a sheet removed at the same time is dropped and its author told; a formula naming a removed sheet, and two removes that would leave no sheet, are barriers.
|
|
31
|
-
- **Selections: a seat's own row/column/count/sheet change keeps its selection inside the sheet** (API calls set no selection; the editor crashed with "Range is out of bounds"); a remote count/sheet change clamps it too.
|
|
32
|
-
- **Transform speed:** the group transform walks the OT grid iteratively; untouched cell ops pass through by identity (no overlap, no formula, change elsewhere); barrier checks are cached per op; undo-stack rebase reuses each list's traveling shape and compares by identity.
|
|
33
|
-
- **Tests:** new chained TP1 fuzz (`sheet-transform-chain-fuzz.test.ts`, 3–5 real commands per side, plus capture fidelity); the multi-seat session fuzz is seed-repeatable (`createSheetsOtAdapter` hook `stateHash`, a synchronous hash in tests) and asserts zero incidents. `SHEET_TRANSFORMER_VERSION` = `c5c-1`.
|
|
34
|
-
- `SHEETS_COLLAB_PROTO` = 2: a room opened by this build is raised to proto 2 (when its checkpoint is at head) and older tabs open it read-only, so seats with and without merge completion never share a room.
|
|
35
|
-
- Consumer action: none.
|
|
36
|
-
|
|
37
23
|
## 0.8.20
|
|
38
24
|
|
|
39
25
|
SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
|
package/dist/univer-collab.cjs
CHANGED
|
@@ -60,6 +60,7 @@ __export(collab_exports, {
|
|
|
60
60
|
isNoopDocsOp: () => isNoopDocsOp,
|
|
61
61
|
moveSelectionsThrough: () => moveSelectionsThrough,
|
|
62
62
|
normalizeDocsOp: () => normalizeDocsOp,
|
|
63
|
+
offlineTextOfGroups: () => offlineTextOfGroups,
|
|
63
64
|
openDocsOtRoom: () => openDocsOtRoom,
|
|
64
65
|
openSheetsOtRoom: () => openSheetsOtRoom,
|
|
65
66
|
rebaseSheetUndoStack: () => rebaseSheetUndoStack,
|
|
@@ -1370,7 +1371,9 @@ function openDocsOtRoom(o) {
|
|
|
1370
1371
|
...o.presence ? { presence: o.presence } : {},
|
|
1371
1372
|
onNotice: (n) => notice(n),
|
|
1372
1373
|
...o.onIncident ? { onIncident: o.onIncident } : {},
|
|
1373
|
-
...o.onStatus ? { onStatus: o.onStatus } : {}
|
|
1374
|
+
...o.onStatus ? { onStatus: o.onStatus } : {},
|
|
1375
|
+
...o.offline ? { offline: o.offline } : {},
|
|
1376
|
+
...o.onOffline ? { onOffline: o.onOffline } : {}
|
|
1374
1377
|
});
|
|
1375
1378
|
const isSaver = () => {
|
|
1376
1379
|
if (!o.presence) return true;
|
|
@@ -1638,7 +1641,9 @@ function documentOtFactory(o) {
|
|
|
1638
1641
|
replace: ({ snapshot, stateHash, clientId }) => (0, import_collab3.collabReplace)(client, { roomId: o.documentId, snapshot, stateHash, origin: "restore", clientId }),
|
|
1639
1642
|
...o.onNotice ? { onNotice: o.onNotice } : {},
|
|
1640
1643
|
...o.onIncident ? { onIncident: o.onIncident } : {},
|
|
1641
|
-
...o.onStatus ? { onStatus: o.onStatus } : {}
|
|
1644
|
+
...o.onStatus ? { onStatus: o.onStatus } : {},
|
|
1645
|
+
offline: (0, import_collab3.browserOfflineOptions)(`${o.documentId}:${o.uid}`),
|
|
1646
|
+
...o.onOffline ? { onOffline: o.onOffline } : {}
|
|
1642
1647
|
});
|
|
1643
1648
|
await room.session.ready;
|
|
1644
1649
|
let lastKey = "";
|
|
@@ -3559,17 +3564,65 @@ function rebaseSheetUndoStack(items, remote, unitId) {
|
|
|
3559
3564
|
function createSheetsOtAdapter(port, hooks = {}) {
|
|
3560
3565
|
let queue = [];
|
|
3561
3566
|
let draining = false;
|
|
3567
|
+
const lazy = typeof port.beforeUndo === "function";
|
|
3568
|
+
let pending = [];
|
|
3569
|
+
let pendingBase = 0;
|
|
3570
|
+
let applied = 0;
|
|
3571
|
+
let currentAt = /* @__PURE__ */ new WeakMap();
|
|
3572
|
+
const PENDING_CAP = 2e3;
|
|
3573
|
+
const now = () => typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
3574
|
+
const stacksOfTargets = () => port.undoTargets().flatMap((t) => {
|
|
3575
|
+
const stacks = undoStacksOf2(t.service);
|
|
3576
|
+
return stacks ? [stacks.undo, stacks.redo].map((map) => ({ items: map.get(t.unitId), unitId: t.unitId, isUndo: map === stacks.undo })) : [];
|
|
3577
|
+
});
|
|
3578
|
+
const markNew = (items) => {
|
|
3579
|
+
for (let i = items.length - 1; i >= 0 && !currentAt.has(items[i]); i--) currentAt.set(items[i], applied);
|
|
3580
|
+
};
|
|
3581
|
+
const catchUpItem = (item, unitId) => {
|
|
3582
|
+
const from = currentAt.get(item) ?? applied;
|
|
3583
|
+
for (let k = from - pendingBase; k < pending.length; k++) if (rebaseSheetUndoStack([item], pending[k], unitId) > 0) return false;
|
|
3584
|
+
currentAt.set(item, applied);
|
|
3585
|
+
return true;
|
|
3586
|
+
};
|
|
3587
|
+
const catchUp = () => {
|
|
3588
|
+
if (!pending.length) return;
|
|
3589
|
+
const t0 = now();
|
|
3590
|
+
let dropped = 0;
|
|
3591
|
+
for (const { items, unitId } of stacksOfTargets()) {
|
|
3592
|
+
if (!items?.length) continue;
|
|
3593
|
+
for (let i = items.length - 1; i >= 0; i--)
|
|
3594
|
+
if (!catchUpItem(items[i], unitId)) {
|
|
3595
|
+
items.splice(i, 1);
|
|
3596
|
+
dropped++;
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
pending = [];
|
|
3600
|
+
pendingBase = applied;
|
|
3601
|
+
hooks.onUndoWork?.(now() - t0, "catch_up");
|
|
3602
|
+
if (dropped) hooks.onUndoRebased?.(dropped);
|
|
3603
|
+
};
|
|
3604
|
+
if (lazy) port.beforeUndo(catchUp);
|
|
3562
3605
|
const applyNow = (op) => {
|
|
3563
3606
|
for (const m of op) port.applyRemote(m);
|
|
3607
|
+
const t0 = now();
|
|
3564
3608
|
let dropped = 0;
|
|
3565
|
-
|
|
3566
|
-
const
|
|
3567
|
-
|
|
3568
|
-
for (const
|
|
3569
|
-
|
|
3570
|
-
|
|
3609
|
+
if (!lazy) {
|
|
3610
|
+
for (const { items, unitId } of stacksOfTargets()) if (items?.length) dropped += rebaseSheetUndoStack(items, op, unitId);
|
|
3611
|
+
} else if (!isNoopSheetOp(op)) {
|
|
3612
|
+
for (const { items, unitId, isUndo } of stacksOfTargets()) {
|
|
3613
|
+
if (!items?.length) continue;
|
|
3614
|
+
markNew(items);
|
|
3615
|
+
const top = items[items.length - 1];
|
|
3616
|
+
if (isUndo && (!catchUpItem(top, unitId) || rebaseSheetUndoStack([top], op, unitId) > 0)) {
|
|
3617
|
+
items.pop();
|
|
3618
|
+
dropped++;
|
|
3619
|
+
} else if (isUndo) currentAt.set(top, applied + 1);
|
|
3571
3620
|
}
|
|
3621
|
+
pending.push(op);
|
|
3622
|
+
applied++;
|
|
3623
|
+
if (pending.length > PENDING_CAP) catchUp();
|
|
3572
3624
|
}
|
|
3625
|
+
hooks.onUndoWork?.(now() - t0, "remote");
|
|
3573
3626
|
hooks.onUndoRebased?.(dropped);
|
|
3574
3627
|
port.markDirty();
|
|
3575
3628
|
};
|
|
@@ -3607,6 +3660,9 @@ function createSheetsOtAdapter(port, hooks = {}) {
|
|
|
3607
3660
|
stacks?.undo.delete(t.unitId);
|
|
3608
3661
|
stacks?.redo.delete(t.unitId);
|
|
3609
3662
|
}
|
|
3663
|
+
pending = [];
|
|
3664
|
+
pendingBase = applied;
|
|
3665
|
+
currentAt = /* @__PURE__ */ new WeakMap();
|
|
3610
3666
|
},
|
|
3611
3667
|
snapshot: () => port.snapshot(),
|
|
3612
3668
|
async hash() {
|
|
@@ -3693,7 +3749,9 @@ function openSheetsOtRoom(o) {
|
|
|
3693
3749
|
...o.presence ? { presence: o.presence } : {},
|
|
3694
3750
|
onNotice: (n) => notice(n),
|
|
3695
3751
|
...o.onIncident ? { onIncident: o.onIncident } : {},
|
|
3696
|
-
...o.onStatus ? { onStatus: o.onStatus } : {}
|
|
3752
|
+
...o.onStatus ? { onStatus: o.onStatus } : {},
|
|
3753
|
+
...o.offline ? { offline: o.offline } : {},
|
|
3754
|
+
...o.onOffline ? { onOffline: o.onOffline } : {}
|
|
3697
3755
|
});
|
|
3698
3756
|
const isSaver = () => {
|
|
3699
3757
|
if (!o.presence) return true;
|
|
@@ -3724,6 +3782,65 @@ function openSheetsOtRoom(o) {
|
|
|
3724
3782
|
};
|
|
3725
3783
|
}
|
|
3726
3784
|
|
|
3785
|
+
// src/univer/collab/sheets-ot/plugin-teardown.ts
|
|
3786
|
+
var perSheetList = (data) => Object.entries(data).flatMap(([sheet, list]) => Array.isArray(list) ? [[sheet, list.filter((x) => !!x && typeof x === "object")]] : []);
|
|
3787
|
+
var PLUGIN_TEARDOWNS = [
|
|
3788
|
+
{
|
|
3789
|
+
resource: "SHEET_CONDITIONAL_FORMATTING_PLUGIN",
|
|
3790
|
+
removals: (unitId, data) => perSheetList(data).flatMap(
|
|
3791
|
+
([subUnitId, rules]) => rules.filter((r) => typeof r.cfId === "string").map((r) => ({ id: "sheet.mutation.delete-conditional-rule", params: { unitId, subUnitId, cfId: r.cfId } }))
|
|
3792
|
+
)
|
|
3793
|
+
},
|
|
3794
|
+
{
|
|
3795
|
+
resource: "SHEET_DATA_VALIDATION_PLUGIN",
|
|
3796
|
+
removals: (unitId, data) => perSheetList(data).flatMap(([subUnitId, rules]) => {
|
|
3797
|
+
const ids = rules.map((r) => r.uid).filter((u) => typeof u === "string");
|
|
3798
|
+
return ids.length ? [{ id: "data-validation.mutation.removeRule", params: { unitId, subUnitId, ruleId: ids, source: "command" } }] : [];
|
|
3799
|
+
})
|
|
3800
|
+
},
|
|
3801
|
+
{
|
|
3802
|
+
resource: "SHEET_NOTE_PLUGIN",
|
|
3803
|
+
removals: (unitId, data) => Object.entries(data).flatMap(
|
|
3804
|
+
([sheetId, rows]) => Object.entries(rows ?? {}).flatMap(
|
|
3805
|
+
([row, cols]) => Object.entries(cols ?? {}).map(([col, note]) => ({
|
|
3806
|
+
id: "sheet.mutation.remove-note",
|
|
3807
|
+
params: { unitId, sheetId, row: Number(row), col: Number(col), ...note && typeof note.id === "string" ? { noteId: note.id } : {}, silent: true }
|
|
3808
|
+
}))
|
|
3809
|
+
)
|
|
3810
|
+
)
|
|
3811
|
+
}
|
|
3812
|
+
];
|
|
3813
|
+
function resourcesOf(saved) {
|
|
3814
|
+
const out = /* @__PURE__ */ new Map();
|
|
3815
|
+
const list = saved?.resources;
|
|
3816
|
+
for (const r of Array.isArray(list) ? list : []) {
|
|
3817
|
+
if (!r?.name) continue;
|
|
3818
|
+
try {
|
|
3819
|
+
const data = typeof r.data === "string" ? r.data ? JSON.parse(r.data) : null : r.data;
|
|
3820
|
+
if (data && typeof data === "object") out.set(r.name, data);
|
|
3821
|
+
} catch {
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3824
|
+
return out;
|
|
3825
|
+
}
|
|
3826
|
+
function releaseUnitPluginState(cs, unitId, saved) {
|
|
3827
|
+
const resources = resourcesOf(saved);
|
|
3828
|
+
let ran = 0;
|
|
3829
|
+
for (const t of PLUGIN_TEARDOWNS) {
|
|
3830
|
+
const data = resources.get(t.resource);
|
|
3831
|
+
if (!data) continue;
|
|
3832
|
+
for (const m of t.removals(unitId, data)) {
|
|
3833
|
+
try {
|
|
3834
|
+
cs.syncExecuteCommand(m.id, m.params, { onlyLocal: true });
|
|
3835
|
+
ran++;
|
|
3836
|
+
} catch (err) {
|
|
3837
|
+
console.warn(`[sheets-ot] could not release ${t.resource} state before a reload`, err);
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
return ran;
|
|
3842
|
+
}
|
|
3843
|
+
|
|
3727
3844
|
// src/univer/collab/sheets-ot/univer-port.ts
|
|
3728
3845
|
var COMMAND = 0;
|
|
3729
3846
|
var MUTATION = 2;
|
|
@@ -3733,6 +3850,8 @@ var REMOVE_MERGE = "sheet.mutation.remove-worksheet-merge";
|
|
|
3733
3850
|
var SHEET_NAME = "sheet.mutation.set-worksheet-name";
|
|
3734
3851
|
var INSERT_SHEET = "sheet.mutation.insert-sheet";
|
|
3735
3852
|
var RESHAPE = /* @__PURE__ */ new Set(["sheet.mutation.set-worksheet-row-count", "sheet.mutation.set-worksheet-column-count", "sheet.mutation.remove-sheet", INSERT_SHEET]);
|
|
3853
|
+
var UNDO = "univer.command.undo";
|
|
3854
|
+
var REDO = "univer.command.redo";
|
|
3736
3855
|
var DEPTH_GUARD = /* @__PURE__ */ Symbol.for("ai-matrx.office.sheets.command-depth-guard");
|
|
3737
3856
|
var json = (v) => v === void 0 ? v : JSON.parse(JSON.stringify(v));
|
|
3738
3857
|
var flagged = (options) => {
|
|
@@ -3742,6 +3861,7 @@ var flagged = (options) => {
|
|
|
3742
3861
|
function univerSheetsOtPort(o) {
|
|
3743
3862
|
const cs = o.commandService;
|
|
3744
3863
|
const listeners = /* @__PURE__ */ new Set();
|
|
3864
|
+
const undoWatchers = /* @__PURE__ */ new Set();
|
|
3745
3865
|
const idle = [];
|
|
3746
3866
|
const pre = /* @__PURE__ */ new WeakMap();
|
|
3747
3867
|
const tracker = { stack: [], settle: () => settle() };
|
|
@@ -3798,6 +3918,7 @@ function univerSheetsOtPort(o) {
|
|
|
3798
3918
|
if (tracker.stack.length === 0 && !group) for (const fn of idle.splice(0)) fn();
|
|
3799
3919
|
}
|
|
3800
3920
|
const before = cs.beforeCommandExecuted((info, options) => {
|
|
3921
|
+
if (info.id === UNDO || info.id === REDO) for (const fn of [...undoWatchers]) fn();
|
|
3801
3922
|
if (info.type === COMMAND) {
|
|
3802
3923
|
if (tracker.stack.length === 0 && !group) group = openGroup(info.id);
|
|
3803
3924
|
tracker.stack.push(info.id);
|
|
@@ -4043,6 +4164,8 @@ function univerSheetsOtPort(o) {
|
|
|
4043
4164
|
group = null;
|
|
4044
4165
|
applying = true;
|
|
4045
4166
|
try {
|
|
4167
|
+
const u = unitId();
|
|
4168
|
+
if (u) releaseUnitPluginState(cs, u, o.saveUnit?.(u) ?? null);
|
|
4046
4169
|
o.load(snapshot);
|
|
4047
4170
|
} finally {
|
|
4048
4171
|
applying = false;
|
|
@@ -4053,8 +4176,13 @@ function univerSheetsOtPort(o) {
|
|
|
4053
4176
|
const service = o.undoRedo?.();
|
|
4054
4177
|
return u && service ? [{ service, unitId: u }] : [];
|
|
4055
4178
|
},
|
|
4179
|
+
beforeUndo(fn) {
|
|
4180
|
+
undoWatchers.add(fn);
|
|
4181
|
+
return () => void undoWatchers.delete(fn);
|
|
4182
|
+
},
|
|
4056
4183
|
markDirty: () => o.markDirty(),
|
|
4057
4184
|
dispose() {
|
|
4185
|
+
undoWatchers.clear();
|
|
4058
4186
|
before.dispose();
|
|
4059
4187
|
after.dispose();
|
|
4060
4188
|
collab.dispose();
|
|
@@ -4132,6 +4260,53 @@ function moveSelectionsThrough(selections, m, maxRows, maxCols) {
|
|
|
4132
4260
|
return selections.map((s) => ({ ...s, range: box(s.range, s.range.rangeType), ...s.primary ? { primary: box(s.primary) } : {} }));
|
|
4133
4261
|
}
|
|
4134
4262
|
|
|
4263
|
+
// src/univer/collab/offline-text.ts
|
|
4264
|
+
var colName3 = (c) => {
|
|
4265
|
+
let n = c;
|
|
4266
|
+
let s = "";
|
|
4267
|
+
do {
|
|
4268
|
+
s = String.fromCharCode(65 + n % 26) + s;
|
|
4269
|
+
n = Math.floor(n / 26) - 1;
|
|
4270
|
+
} while (n >= 0);
|
|
4271
|
+
return s;
|
|
4272
|
+
};
|
|
4273
|
+
function collectDocText(v, out) {
|
|
4274
|
+
if (Array.isArray(v)) {
|
|
4275
|
+
for (const x of v) collectDocText(x, out);
|
|
4276
|
+
return;
|
|
4277
|
+
}
|
|
4278
|
+
if (!v || typeof v !== "object") return;
|
|
4279
|
+
const o = v;
|
|
4280
|
+
if (typeof o.dataStream === "string" && o.dataStream.length) out.push(o.dataStream);
|
|
4281
|
+
for (const k of Object.keys(o)) if (k !== "dataStream") collectDocText(o[k], out);
|
|
4282
|
+
}
|
|
4283
|
+
function collectCells(cellValue, out) {
|
|
4284
|
+
if (!cellValue || typeof cellValue !== "object") return;
|
|
4285
|
+
for (const [r, cols] of Object.entries(cellValue)) {
|
|
4286
|
+
if (!cols || typeof cols !== "object") continue;
|
|
4287
|
+
for (const [c, cell] of Object.entries(cols)) {
|
|
4288
|
+
const x = cell;
|
|
4289
|
+
const val = x?.f ?? x?.v;
|
|
4290
|
+
if (val !== void 0 && val !== null && val !== "") out.push(`${colName3(Number(c))}${Number(r) + 1}: ${String(val)}`);
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
function offlineTextOfGroups(buffers) {
|
|
4295
|
+
const docs = [];
|
|
4296
|
+
const cells = [];
|
|
4297
|
+
for (const groups of buffers) {
|
|
4298
|
+
for (const g of groups) {
|
|
4299
|
+
for (const m of g.mutations) {
|
|
4300
|
+
const p = m.params;
|
|
4301
|
+
if (p && "cellValue" in p) collectCells(p.cellValue, cells);
|
|
4302
|
+
else collectDocText(p, docs);
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
const text = docs.join("").replace(/\r/g, "\n").replace(/\u0000/g, "");
|
|
4307
|
+
return [text, cells.join("\n")].filter((s) => s.length > 0).join("\n");
|
|
4308
|
+
}
|
|
4309
|
+
|
|
4135
4310
|
// src/sheets/workbook-ot-room.ts
|
|
4136
4311
|
var Y3 = __toESM(require("yjs"), 1);
|
|
4137
4312
|
var import_awareness3 = require("y-protocols/awareness");
|
|
@@ -4234,6 +4409,7 @@ async function startWorkbookOtRoom(port, o) {
|
|
|
4234
4409
|
await provider.connect();
|
|
4235
4410
|
publishAwareness();
|
|
4236
4411
|
const client = db4();
|
|
4412
|
+
const offline = (0, import_collab6.browserOfflineOptions)(`${o.workbookId}:${o.uid}`);
|
|
4237
4413
|
const room = openSheetsOtRoom({
|
|
4238
4414
|
port,
|
|
4239
4415
|
clientId: o.clientId,
|
|
@@ -4254,7 +4430,9 @@ async function startWorkbookOtRoom(port, o) {
|
|
|
4254
4430
|
replace: ({ snapshot, stateHash, clientId }) => (0, import_collab6.collabReplace)(client, { roomId: o.workbookId, snapshot, stateHash, origin: "restore", clientId }),
|
|
4255
4431
|
...o.onNotice ? { onNotice: o.onNotice } : {},
|
|
4256
4432
|
...o.onIncident ? { onIncident: o.onIncident } : {},
|
|
4257
|
-
...o.onStatus ? { onStatus: o.onStatus } : {}
|
|
4433
|
+
...o.onStatus ? { onStatus: o.onStatus } : {},
|
|
4434
|
+
...offline ? { offline } : {},
|
|
4435
|
+
...o.onOffline ? { onOffline: o.onOffline } : {}
|
|
4258
4436
|
});
|
|
4259
4437
|
await room.session.ready;
|
|
4260
4438
|
return {
|