@w100n/documents 0.4.0 → 0.10.0
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/SheetView-3XTEV2VT.css +319 -0
- package/dist/SheetView-3XTEV2VT.css.map +1 -0
- package/dist/SheetView-JYH2ZUZF.js +928 -0
- package/dist/SheetView-JYH2ZUZF.js.map +1 -0
- package/dist/TextEditor-X3X62R46.js +982 -0
- package/dist/TextEditor-X3X62R46.js.map +1 -0
- package/dist/caveat-cyrillic-XVO43JCM.woff2 +0 -0
- package/dist/caveat-latin-IUBKKMHQ.woff2 +0 -0
- package/dist/caveat-latin-ext-5S7R5SZN.woff2 +0 -0
- package/dist/chunk-CE3AADY6.js +3447 -0
- package/dist/chunk-CE3AADY6.js.map +1 -0
- package/dist/chunk-ISOOUYLI.js +150 -0
- package/dist/chunk-ISOOUYLI.js.map +1 -0
- package/dist/{chunk-KEV4R7W5.js → chunk-K364NAYP.js} +4 -1
- package/dist/chunk-K364NAYP.js.map +1 -0
- package/dist/chunk-QDH7EZAF.js +27 -0
- package/dist/chunk-QDH7EZAF.js.map +1 -0
- package/dist/chunk-SVRYWMES.js +196 -0
- package/dist/chunk-SVRYWMES.js.map +1 -0
- package/dist/chunk-TDP6OJET.js +31 -0
- package/dist/chunk-TDP6OJET.js.map +1 -0
- package/dist/chunk-TNSN4ZQ5.js +2909 -0
- package/dist/chunk-TNSN4ZQ5.js.map +1 -0
- package/dist/collab.cjs +6312 -0
- package/dist/collab.cjs.map +1 -0
- package/dist/collab.d.cts +39 -0
- package/dist/collab.d.ts +39 -0
- package/dist/collab.js +30 -0
- package/dist/collab.js.map +1 -0
- package/dist/grid-EI5JNZAA.js +88 -0
- package/dist/grid-EI5JNZAA.js.map +1 -0
- package/dist/index.cjs +12134 -457
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +2999 -95
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +143 -6
- package/dist/index.d.ts +143 -6
- package/dist/index.js +3377 -450
- package/dist/index.js.map +1 -1
- package/dist/memory.cjs +59 -7
- package/dist/memory.cjs.map +1 -1
- package/dist/memory.d.cts +7 -2
- package/dist/memory.d.ts +7 -2
- package/dist/memory.js +57 -8
- package/dist/memory.js.map +1 -1
- package/dist/pdfWrite-EM6GJDBF.js +76 -0
- package/dist/pdfWrite-EM6GJDBF.js.map +1 -0
- package/dist/types-B5oF25dn.d.cts +165 -0
- package/dist/types-B5oF25dn.d.ts +165 -0
- package/dist/write-DaVtTJCS.d.cts +6 -0
- package/dist/write-DaVtTJCS.d.ts +6 -0
- package/package.json +45 -3
- package/dist/chunk-KEV4R7W5.js.map +0 -1
- package/dist/types-DshXPnWA.d.cts +0 -62
- package/dist/types-DshXPnWA.d.ts +0 -62
|
@@ -0,0 +1,3447 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
attr,
|
|
4
|
+
attrs,
|
|
5
|
+
entry,
|
|
6
|
+
escape,
|
|
7
|
+
inflate,
|
|
8
|
+
parse,
|
|
9
|
+
readDocx,
|
|
10
|
+
texts,
|
|
11
|
+
unescape,
|
|
12
|
+
unzip,
|
|
13
|
+
writeDocx,
|
|
14
|
+
zip
|
|
15
|
+
} from "./chunk-TNSN4ZQ5.js";
|
|
16
|
+
import {
|
|
17
|
+
a1,
|
|
18
|
+
box,
|
|
19
|
+
boxes,
|
|
20
|
+
cell,
|
|
21
|
+
plain,
|
|
22
|
+
quoted,
|
|
23
|
+
remapped,
|
|
24
|
+
renamed,
|
|
25
|
+
shifted,
|
|
26
|
+
span,
|
|
27
|
+
squeeze,
|
|
28
|
+
stored
|
|
29
|
+
} from "./chunk-ISOOUYLI.js";
|
|
30
|
+
|
|
31
|
+
// src/collab.ts
|
|
32
|
+
import { getSchema } from "@tiptap/core";
|
|
33
|
+
import { Transform } from "@tiptap/pm/transform";
|
|
34
|
+
import { prosemirrorJSONToYXmlFragment, updateYFragment, yXmlFragmentToProseMirrorRootNode } from "@tiptap/y-tiptap";
|
|
35
|
+
import * as Y2 from "yjs";
|
|
36
|
+
|
|
37
|
+
// package.json
|
|
38
|
+
var version = "0.10.0";
|
|
39
|
+
|
|
40
|
+
// src/editor/extensions.ts
|
|
41
|
+
import { Extension as Extension2, Mark, Node } from "@tiptap/core";
|
|
42
|
+
import Collaboration from "@tiptap/extension-collaboration";
|
|
43
|
+
import CollaborationCaret from "@tiptap/extension-collaboration-caret";
|
|
44
|
+
import Highlight from "@tiptap/extension-highlight";
|
|
45
|
+
import Image from "@tiptap/extension-image";
|
|
46
|
+
import { TaskItem, TaskList } from "@tiptap/extension-list";
|
|
47
|
+
import { TableKit } from "@tiptap/extension-table";
|
|
48
|
+
import { Color, FontFamily, FontSize, TextStyle } from "@tiptap/extension-text-style";
|
|
49
|
+
import { Plugin as Plugin2, PluginKey as PluginKey2, TextSelection } from "@tiptap/pm/state";
|
|
50
|
+
import { StepMap } from "@tiptap/pm/transform";
|
|
51
|
+
import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
|
|
52
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
53
|
+
import { ySyncPluginKey } from "@tiptap/y-tiptap";
|
|
54
|
+
|
|
55
|
+
// src/editor/pager.ts
|
|
56
|
+
import { Extension } from "@tiptap/core";
|
|
57
|
+
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
58
|
+
import { Decoration, DecorationSet } from "@tiptap/pm/view";
|
|
59
|
+
var a4 = { width: 793.73, height: 1122.53, margins: [96, 96, 96, 96] };
|
|
60
|
+
var letter = { width: 816, height: 1056 };
|
|
61
|
+
var paging = new PluginKey("w100n-pager");
|
|
62
|
+
var skip = (el) => el.classList.contains("w100n-text-gap") || el.classList.contains("ProseMirror-gapcursor");
|
|
63
|
+
function measure(view) {
|
|
64
|
+
const { page } = paging.getState(view.state);
|
|
65
|
+
const [top, , bottom] = page.margins;
|
|
66
|
+
const room = page.height - top - bottom;
|
|
67
|
+
const els = [...view.dom.children];
|
|
68
|
+
const gaps = [];
|
|
69
|
+
let i = 0;
|
|
70
|
+
let shift = 0;
|
|
71
|
+
let start = 0;
|
|
72
|
+
let last = 0;
|
|
73
|
+
view.state.doc.forEach((node, offset) => {
|
|
74
|
+
let el = els[i++];
|
|
75
|
+
while (el && skip(el)) {
|
|
76
|
+
if (el.classList.contains("w100n-text-gap")) shift += el.offsetHeight;
|
|
77
|
+
el = els[i++];
|
|
78
|
+
}
|
|
79
|
+
if (!el) return;
|
|
80
|
+
const y = el.offsetTop - shift;
|
|
81
|
+
const end = y + el.offsetHeight;
|
|
82
|
+
if (node.type.name === "pageBreak") {
|
|
83
|
+
gaps.push({ pos: offset + node.nodeSize, height: start + room - end + bottom + 24 + top, page: gaps.length + 1 });
|
|
84
|
+
start = end;
|
|
85
|
+
} else if (end > start + room && y > start) {
|
|
86
|
+
gaps.push({ pos: offset, height: start + room - y + bottom + 24 + top, page: gaps.length + 1 });
|
|
87
|
+
start = y;
|
|
88
|
+
}
|
|
89
|
+
while (end > start + room) start += room;
|
|
90
|
+
last = end;
|
|
91
|
+
});
|
|
92
|
+
gaps.push({ pos: view.state.doc.content.size, height: Math.max(0, start + room - last), page: gaps.length + 1, end: true });
|
|
93
|
+
return gaps.map((g) => ({ ...g, height: Math.max(0, Math.round(g.height)) }));
|
|
94
|
+
}
|
|
95
|
+
var Pager = Extension.create({
|
|
96
|
+
name: "pager",
|
|
97
|
+
addProseMirrorPlugins: () => [new Plugin({
|
|
98
|
+
key: paging,
|
|
99
|
+
state: {
|
|
100
|
+
init: () => ({ set: DecorationSet.empty, page: a4 }),
|
|
101
|
+
apply(tr, value2) {
|
|
102
|
+
const next = tr.getMeta(paging);
|
|
103
|
+
return { set: next?.set ?? value2.set.map(tr.mapping, tr.doc), page: next?.page ?? value2.page };
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
props: { decorations: (state) => paging.getState(state).set },
|
|
107
|
+
view(view) {
|
|
108
|
+
let timer = 0;
|
|
109
|
+
let sig = "";
|
|
110
|
+
const run = () => {
|
|
111
|
+
if (!view.dom.isConnected) return;
|
|
112
|
+
const gaps = measure(view);
|
|
113
|
+
const next = gaps.map((g) => `${g.pos}:${g.height}`).join();
|
|
114
|
+
if (next === sig) return;
|
|
115
|
+
sig = next;
|
|
116
|
+
const set = DecorationSet.create(view.state.doc, gaps.map((g) => Decoration.widget(g.pos, () => {
|
|
117
|
+
const el = document.createElement("div");
|
|
118
|
+
el.className = g.end ? "w100n-text-gap is-end" : "w100n-text-gap";
|
|
119
|
+
el.style.height = `${g.height}px`;
|
|
120
|
+
el.dataset.page = String(g.page);
|
|
121
|
+
el.contentEditable = "false";
|
|
122
|
+
return el;
|
|
123
|
+
}, { key: `${g.pos}:${g.height}:${g.page}`, side: -1, ignoreSelection: true })));
|
|
124
|
+
view.dispatch(view.state.tr.setMeta(paging, { set }).setMeta("addToHistory", false));
|
|
125
|
+
};
|
|
126
|
+
const later = (ms) => {
|
|
127
|
+
clearTimeout(timer);
|
|
128
|
+
timer = window.setTimeout(run, ms);
|
|
129
|
+
};
|
|
130
|
+
const watch = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => later(200));
|
|
131
|
+
watch?.observe(view.dom);
|
|
132
|
+
later(0);
|
|
133
|
+
return {
|
|
134
|
+
update: (next, prev) => {
|
|
135
|
+
if (paging.getState(next.state).page !== paging.getState(prev).page) later(0);
|
|
136
|
+
else if (next.state.doc !== prev.doc) later(400);
|
|
137
|
+
},
|
|
138
|
+
destroy: () => {
|
|
139
|
+
clearTimeout(timer);
|
|
140
|
+
watch?.disconnect();
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
})]
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// src/editor/extensions.ts
|
|
148
|
+
var notes = new PluginKey2("w100n-notes");
|
|
149
|
+
var blocks = [
|
|
150
|
+
"paragraph",
|
|
151
|
+
"heading",
|
|
152
|
+
"bulletList",
|
|
153
|
+
"orderedList",
|
|
154
|
+
"listItem",
|
|
155
|
+
"taskList",
|
|
156
|
+
"taskItem",
|
|
157
|
+
"blockquote",
|
|
158
|
+
"codeBlock",
|
|
159
|
+
"horizontalRule",
|
|
160
|
+
"table",
|
|
161
|
+
"tableRow",
|
|
162
|
+
"tableHeader",
|
|
163
|
+
"tableCell",
|
|
164
|
+
"pageBreak",
|
|
165
|
+
"toc"
|
|
166
|
+
];
|
|
167
|
+
var changed = (trs) => {
|
|
168
|
+
const ranges = [];
|
|
169
|
+
trs.forEach((tr, n) => tr.steps.forEach((step, i) => {
|
|
170
|
+
const slice = step.slice;
|
|
171
|
+
if (!slice || !slice.openStart && !slice.openEnd && !slice.content.firstChild?.isBlock) return;
|
|
172
|
+
const after = tr.mapping.slice(i + 1);
|
|
173
|
+
for (const later of trs.slice(n + 1)) after.appendMapping(later.mapping);
|
|
174
|
+
step.getMap().forEach((_a, _b, from, to) => ranges.push([after.map(from, -1), after.map(to, 1)]));
|
|
175
|
+
}));
|
|
176
|
+
return ranges;
|
|
177
|
+
};
|
|
178
|
+
var Blocks = Extension2.create({
|
|
179
|
+
name: "blocks",
|
|
180
|
+
addGlobalAttributes: () => [{
|
|
181
|
+
types: blocks,
|
|
182
|
+
attributes: {
|
|
183
|
+
align: { default: null, parseHTML: (el) => el.style.textAlign || null, renderHTML: (attrs2) => attrs2.align ? { style: `text-align: ${attrs2.align}` } : {} },
|
|
184
|
+
indent: { default: 0, parseHTML: (el) => Number(el.dataset.indent) || 0, renderHTML: (attrs2) => attrs2.indent ? { "data-indent": attrs2.indent, style: `margin-left: ${attrs2.indent * 0.5}in` } : {} },
|
|
185
|
+
ref: { default: null, rendered: false, keepOnSplit: false }
|
|
186
|
+
}
|
|
187
|
+
}],
|
|
188
|
+
addProseMirrorPlugins: () => [new Plugin2({
|
|
189
|
+
appendTransaction(trs, _old, state) {
|
|
190
|
+
const ranges = changed(trs);
|
|
191
|
+
if (!ranges.length) return null;
|
|
192
|
+
const seen2 = /* @__PURE__ */ new Map();
|
|
193
|
+
const drop = [];
|
|
194
|
+
const visit = (node, pos2) => {
|
|
195
|
+
const ref = node.attrs.ref;
|
|
196
|
+
if (!ref) return;
|
|
197
|
+
const first = seen2.get(ref);
|
|
198
|
+
if (!first) seen2.set(ref, { pos: pos2, node });
|
|
199
|
+
else if (!first.node.textContent && node.textContent) {
|
|
200
|
+
drop.push(first.pos);
|
|
201
|
+
seen2.set(ref, { pos: pos2, node });
|
|
202
|
+
} else drop.push(pos2);
|
|
203
|
+
};
|
|
204
|
+
const from = Math.max(0, Math.min(...ranges.map((r) => r[0])));
|
|
205
|
+
const to = Math.min(state.doc.content.size, Math.max(...ranges.map((r) => r[1])));
|
|
206
|
+
const $from = state.doc.resolve(from);
|
|
207
|
+
const $to = state.doc.resolve(to);
|
|
208
|
+
const start = Math.max(0, $from.index(0) - 1);
|
|
209
|
+
const end = Math.min(state.doc.childCount, $to.index(0) + 2);
|
|
210
|
+
let pos = 0;
|
|
211
|
+
for (let i = 0; i < start; i++) pos += state.doc.child(i).nodeSize;
|
|
212
|
+
for (let i = start; i < end; i++) {
|
|
213
|
+
const top = state.doc.child(i);
|
|
214
|
+
visit(top, pos);
|
|
215
|
+
top.descendants((node, at) => visit(node, pos + 1 + at));
|
|
216
|
+
pos += top.nodeSize;
|
|
217
|
+
}
|
|
218
|
+
if (!drop.length) return null;
|
|
219
|
+
const tr = state.tr;
|
|
220
|
+
for (const at of drop) tr.setNodeAttribute(at, "ref", null);
|
|
221
|
+
return tr;
|
|
222
|
+
}
|
|
223
|
+
})]
|
|
224
|
+
});
|
|
225
|
+
var PageBreak = Node.create({
|
|
226
|
+
name: "pageBreak",
|
|
227
|
+
group: "block",
|
|
228
|
+
atom: true,
|
|
229
|
+
selectable: true,
|
|
230
|
+
addOptions: () => ({ label: "" }),
|
|
231
|
+
parseHTML: () => [{ tag: "div[data-page-break]" }],
|
|
232
|
+
renderHTML() {
|
|
233
|
+
return ["div", { "data-page-break": "", "data-label": this.options.label, class: "w100n-text-break", contenteditable: "false" }];
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
var headings = (doc, after) => {
|
|
237
|
+
const found = [];
|
|
238
|
+
doc.descendants((node, pos) => {
|
|
239
|
+
if (pos > after && node.type.name === "heading" && node.attrs.level <= 3 && node.textContent.trim()) found.push({ pos, level: node.attrs.level, text: node.textContent.trim() });
|
|
240
|
+
return !node.isTextblock;
|
|
241
|
+
});
|
|
242
|
+
return found;
|
|
243
|
+
};
|
|
244
|
+
function entries(doc, relative2, after) {
|
|
245
|
+
const list = headings(doc, after).map((h) => [h.level, h.text]);
|
|
246
|
+
const top = relative2 && list.length ? Math.min(...list.map(([level]) => level)) - 1 : 0;
|
|
247
|
+
return list.map(([level, text]) => [level - top, text]);
|
|
248
|
+
}
|
|
249
|
+
var Toc = Node.create({
|
|
250
|
+
name: "toc",
|
|
251
|
+
group: "block",
|
|
252
|
+
atom: true,
|
|
253
|
+
selectable: true,
|
|
254
|
+
addOptions: () => ({ relative: false, label: "", empty: "" }),
|
|
255
|
+
addAttributes: () => ({ entries: { default: "[]" }, title: { default: null } }),
|
|
256
|
+
parseHTML: () => [{ tag: "nav[data-toc]" }],
|
|
257
|
+
renderHTML() {
|
|
258
|
+
return ["nav", { "data-toc": "", class: "w100n-text-toc" }];
|
|
259
|
+
},
|
|
260
|
+
addNodeView() {
|
|
261
|
+
return ({ editor, getPos }) => {
|
|
262
|
+
const dom = document.createElement("nav");
|
|
263
|
+
dom.className = "w100n-text-toc";
|
|
264
|
+
dom.contentEditable = "false";
|
|
265
|
+
const paint2 = () => {
|
|
266
|
+
const at = getPos() ?? 0;
|
|
267
|
+
const list = entries(editor.state.doc, this.options.relative, at);
|
|
268
|
+
const head = document.createElement("b");
|
|
269
|
+
head.textContent = this.options.label;
|
|
270
|
+
const items = list.map(([level, text], i) => {
|
|
271
|
+
const go = document.createElement("button");
|
|
272
|
+
go.type = "button";
|
|
273
|
+
go.textContent = text;
|
|
274
|
+
go.dataset.level = String(level);
|
|
275
|
+
go.onclick = () => {
|
|
276
|
+
const hit = headings(editor.state.doc, getPos() ?? 0)[i];
|
|
277
|
+
if (hit) editor.view.nodeDOM(hit.pos)?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
278
|
+
};
|
|
279
|
+
return go;
|
|
280
|
+
});
|
|
281
|
+
const empty = document.createElement("small");
|
|
282
|
+
empty.textContent = this.options.empty;
|
|
283
|
+
dom.replaceChildren(head, ...items.length ? items : [empty]);
|
|
284
|
+
};
|
|
285
|
+
paint2();
|
|
286
|
+
return {
|
|
287
|
+
dom,
|
|
288
|
+
update: (node) => {
|
|
289
|
+
if (node.type.name !== "toc") return false;
|
|
290
|
+
paint2();
|
|
291
|
+
return true;
|
|
292
|
+
},
|
|
293
|
+
ignoreMutation: () => true
|
|
294
|
+
};
|
|
295
|
+
};
|
|
296
|
+
},
|
|
297
|
+
addProseMirrorPlugins() {
|
|
298
|
+
const relative2 = this.options.relative;
|
|
299
|
+
return [new Plugin2({
|
|
300
|
+
appendTransaction(trs, _old, state) {
|
|
301
|
+
if (!trs.some((tr2) => tr2.docChanged && !tr2.getMeta(ySyncPluginKey))) return null;
|
|
302
|
+
const at = [];
|
|
303
|
+
state.doc.forEach((node, pos) => {
|
|
304
|
+
if (node.type.name === "toc") at.push(pos);
|
|
305
|
+
});
|
|
306
|
+
if (!at.length) return null;
|
|
307
|
+
const tr = state.tr;
|
|
308
|
+
for (const pos of at) {
|
|
309
|
+
const fresh2 = JSON.stringify(entries(state.doc, relative2, pos));
|
|
310
|
+
if (state.doc.nodeAt(pos).attrs.entries !== fresh2) tr.setNodeAttribute(pos, "entries", fresh2);
|
|
311
|
+
}
|
|
312
|
+
return tr.docChanged ? tr : null;
|
|
313
|
+
}
|
|
314
|
+
})];
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
var revision = (name, tag) => Mark.create({
|
|
318
|
+
name,
|
|
319
|
+
inclusive: false,
|
|
320
|
+
excludes: "insertion deletion",
|
|
321
|
+
addAttributes: () => ({ id: { default: null }, author: { default: "" }, date: { default: "" } }),
|
|
322
|
+
parseHTML: () => [{ tag: `${tag}[data-rev]` }],
|
|
323
|
+
renderHTML: ({ HTMLAttributes }) => [tag, { "data-rev": HTMLAttributes.id, class: "w100n-text-rev", title: HTMLAttributes.author }, 0]
|
|
324
|
+
});
|
|
325
|
+
var seen = /* @__PURE__ */ new WeakMap();
|
|
326
|
+
function changes(doc) {
|
|
327
|
+
const hit = seen.get(doc);
|
|
328
|
+
if (hit) return hit;
|
|
329
|
+
const out = [];
|
|
330
|
+
doc.descendants((node, pos) => {
|
|
331
|
+
if (!node.isText) return;
|
|
332
|
+
const mark = node.marks.find((m) => m.type.name === "insertion" || m.type.name === "deletion");
|
|
333
|
+
if (!mark) return;
|
|
334
|
+
const last = out[out.length - 1];
|
|
335
|
+
if (last && last.id === mark.attrs.id && last.kind === mark.type.name && last.to === pos) Object.assign(last, { text: last.text + node.text, to: pos + node.nodeSize });
|
|
336
|
+
else out.push({ id: mark.attrs.id, kind: mark.type.name, author: mark.attrs.author, date: mark.attrs.date, text: node.text, from: pos, to: pos + node.nodeSize });
|
|
337
|
+
});
|
|
338
|
+
seen.set(doc, out);
|
|
339
|
+
return out;
|
|
340
|
+
}
|
|
341
|
+
function decide(editor, accept, id) {
|
|
342
|
+
const { state } = editor;
|
|
343
|
+
const tr = state.tr;
|
|
344
|
+
for (const c of changes(state.doc).filter((c2) => !id || c2.id === id).reverse()) {
|
|
345
|
+
if (c.kind === "insertion" === accept) tr.removeMark(c.from, c.to, state.schema.marks[c.kind].create({ id: c.id, author: c.author, date: c.date }));
|
|
346
|
+
else tr.delete(c.from, c.to);
|
|
347
|
+
}
|
|
348
|
+
if (tr.docChanged) editor.view.dispatch(tr);
|
|
349
|
+
}
|
|
350
|
+
var suggesting = new PluginKey2("w100n-suggest");
|
|
351
|
+
var Suggest = Extension2.create({
|
|
352
|
+
name: "suggest",
|
|
353
|
+
addProseMirrorPlugins() {
|
|
354
|
+
const stamp = (state, kind, from, to) => {
|
|
355
|
+
const me = suggesting.getState(state).me;
|
|
356
|
+
const own = [state.doc.resolve(from).nodeBefore, state.doc.resolve(to).nodeAfter].flatMap((n) => n?.marks ?? []).find((m) => m.type.name === kind && m.attrs.author === me);
|
|
357
|
+
return state.schema.marks[kind].create(own ? own.attrs : { id: Math.random().toString(36).slice(2, 10), author: me, date: (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z") });
|
|
358
|
+
};
|
|
359
|
+
const strike = (tr, state, from, to) => {
|
|
360
|
+
const parts2 = [];
|
|
361
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
362
|
+
if (!node.isText) return;
|
|
363
|
+
const a = Math.max(from, pos), b = Math.min(to, pos + node.nodeSize);
|
|
364
|
+
if (b > a && !node.marks.some((m) => m.type.name === "deletion")) parts2.push({ from: a, to: b, added: node.marks.some((m) => m.type.name === "insertion") });
|
|
365
|
+
});
|
|
366
|
+
const mark = stamp(state, "deletion", from, to);
|
|
367
|
+
for (const p of parts2.reverse()) {
|
|
368
|
+
if (p.added) tr.delete(p.from, p.to);
|
|
369
|
+
else tr.addMark(p.from, p.to, mark);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
const type = (view, from, to, text) => {
|
|
373
|
+
const { state } = view;
|
|
374
|
+
const tr = state.tr;
|
|
375
|
+
if (to > from) strike(tr, state, from, to);
|
|
376
|
+
const at = tr.mapping.map(to);
|
|
377
|
+
const kept = (state.storedMarks ?? state.doc.resolve(from).marks()).filter((m) => m.type.name !== "insertion" && m.type.name !== "deletion");
|
|
378
|
+
tr.insert(at, state.schema.text(text, [...kept, stamp(state, "insertion", from, to)]));
|
|
379
|
+
tr.setSelection(TextSelection.create(tr.doc, at + text.length));
|
|
380
|
+
view.dispatch(tr.scrollIntoView());
|
|
381
|
+
return true;
|
|
382
|
+
};
|
|
383
|
+
return [new Plugin2({
|
|
384
|
+
key: suggesting,
|
|
385
|
+
state: {
|
|
386
|
+
init: () => ({ on: false, me: "" }),
|
|
387
|
+
apply: (tr, value2) => tr.getMeta(suggesting) ?? value2
|
|
388
|
+
},
|
|
389
|
+
props: {
|
|
390
|
+
handleTextInput(view, from, to, text) {
|
|
391
|
+
return suggesting.getState(view.state).on && type(view, from, to, text);
|
|
392
|
+
},
|
|
393
|
+
handlePaste(view, _event, slice) {
|
|
394
|
+
if (!suggesting.getState(view.state).on) return false;
|
|
395
|
+
const { from, to } = view.state.selection;
|
|
396
|
+
return type(view, from, to, slice.content.textBetween(0, slice.content.size, "\n"));
|
|
397
|
+
},
|
|
398
|
+
handleKeyDown(view, event) {
|
|
399
|
+
const { state } = view;
|
|
400
|
+
if (!suggesting.getState(state).on || event.key !== "Backspace" && event.key !== "Delete" || event.metaKey || event.ctrlKey || event.altKey) return false;
|
|
401
|
+
const { from, to, empty, $from } = state.selection;
|
|
402
|
+
const back = event.key === "Backspace";
|
|
403
|
+
let at = from;
|
|
404
|
+
if (empty) {
|
|
405
|
+
const skip2 = (pos) => state.doc.resolve(pos)[back ? "nodeBefore" : "nodeAfter"]?.marks.some((m) => m.type.name === "deletion");
|
|
406
|
+
while (skip2(at)) at += back ? -1 : 1;
|
|
407
|
+
if (back ? at <= $from.start() : at >= $from.end()) return false;
|
|
408
|
+
}
|
|
409
|
+
const tr = state.tr;
|
|
410
|
+
if (empty) strike(tr, state, back ? at - 1 : at, back ? at : at + 1);
|
|
411
|
+
else strike(tr, state, from, to);
|
|
412
|
+
const caret = empty ? tr.mapping.map(back ? at - 1 : at + 1, back ? -1 : 1) : tr.mapping.map(back ? from : to);
|
|
413
|
+
tr.setSelection(TextSelection.create(tr.doc, caret));
|
|
414
|
+
view.dispatch(tr.scrollIntoView());
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
})];
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
var Note = Mark.create({
|
|
422
|
+
name: "comment",
|
|
423
|
+
inclusive: false,
|
|
424
|
+
excludes: "",
|
|
425
|
+
addAttributes: () => ({ id: { default: null, renderHTML: (attrs2) => ({ "data-comment": attrs2.id }) } }),
|
|
426
|
+
renderHTML: ({ HTMLAttributes }) => ["span", HTMLAttributes, 0]
|
|
427
|
+
});
|
|
428
|
+
var locks = new PluginKey2("w100n-locks");
|
|
429
|
+
var locked = (node) => node.type.name === "paragraph" && String(node.attrs.ref ?? "").startsWith("lock:");
|
|
430
|
+
var scan = (doc) => {
|
|
431
|
+
const spans = [];
|
|
432
|
+
doc.descendants((node, pos) => {
|
|
433
|
+
if (!locked(node)) return true;
|
|
434
|
+
spans.push({ from: pos, to: pos + node.nodeSize });
|
|
435
|
+
return false;
|
|
436
|
+
});
|
|
437
|
+
return spans;
|
|
438
|
+
};
|
|
439
|
+
var Locks = Extension2.create({
|
|
440
|
+
name: "locks",
|
|
441
|
+
addOptions: () => ({ label: "" }),
|
|
442
|
+
addProseMirrorPlugins() {
|
|
443
|
+
const shade = (doc, spans) => DecorationSet2.create(doc, spans.map((s) => Decoration2.node(s.from, s.to, { class: "w100n-text-lock", contenteditable: "false", "data-label": this.options.label })));
|
|
444
|
+
return [new Plugin2({
|
|
445
|
+
key: locks,
|
|
446
|
+
state: {
|
|
447
|
+
init: (_config, state) => {
|
|
448
|
+
const spans = scan(state.doc);
|
|
449
|
+
return { spans, set: shade(state.doc, spans) };
|
|
450
|
+
},
|
|
451
|
+
apply(tr, value2) {
|
|
452
|
+
if (!tr.docChanged) return value2;
|
|
453
|
+
const fresh2 = tr.steps.some((step) => {
|
|
454
|
+
let found = false;
|
|
455
|
+
step.slice?.content.descendants((node) => {
|
|
456
|
+
found || (found = locked(node));
|
|
457
|
+
return !found;
|
|
458
|
+
});
|
|
459
|
+
return found;
|
|
460
|
+
});
|
|
461
|
+
const spans = fresh2 ? scan(tr.doc) : value2.spans.map((s) => ({ from: tr.mapping.map(s.from, 1), to: tr.mapping.map(s.to, -1) })).filter((s) => s.to > s.from);
|
|
462
|
+
return { spans, set: spans.length ? shade(tr.doc, spans) : DecorationSet2.empty };
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
filterTransaction(tr, state) {
|
|
466
|
+
let spans = locks.getState(state).spans;
|
|
467
|
+
if (!spans.length || !tr.docChanged) return true;
|
|
468
|
+
return tr.mapping.maps.every((map) => {
|
|
469
|
+
let ok = true;
|
|
470
|
+
map.forEach((from, to) => {
|
|
471
|
+
for (const s of spans) if ((from < s.to && to > s.from || from > s.from && from < s.to) && !(from <= s.from && to >= s.to)) ok = false;
|
|
472
|
+
});
|
|
473
|
+
spans = spans.map((s) => ({ from: map.map(s.from, 1), to: map.map(s.to, -1) }));
|
|
474
|
+
return ok;
|
|
475
|
+
});
|
|
476
|
+
},
|
|
477
|
+
props: {
|
|
478
|
+
decorations: (state) => locks.getState(state).set,
|
|
479
|
+
handleKeyDown(view, event) {
|
|
480
|
+
const back = event.key === "Backspace";
|
|
481
|
+
const { $from, empty } = view.state.selection;
|
|
482
|
+
if (!back && event.key !== "Delete" || !empty || $from.depth < 1) return false;
|
|
483
|
+
if (back ? $from.parentOffset !== 0 : $from.parentOffset !== $from.parent.content.size) return false;
|
|
484
|
+
const at = back ? $from.before() : $from.after();
|
|
485
|
+
const node = back ? view.state.doc.resolve(at).nodeBefore : view.state.doc.resolve(at).nodeAfter;
|
|
486
|
+
if (!node || !locked(node)) return false;
|
|
487
|
+
view.dispatch(view.state.tr.delete(back ? at - node.nodeSize : at, back ? at : at + node.nodeSize));
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
})];
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
var paint = (doc, spots, active, pending2) => DecorationSet2.create(doc, [
|
|
495
|
+
...spots.filter((s) => s.to > s.from).map((s) => Decoration2.inline(s.from, s.to, { class: s.id === active ? "w100n-text-note is-active" : "w100n-text-note", "data-note": s.id })),
|
|
496
|
+
...pending2 && pending2.to > pending2.from ? [Decoration2.inline(pending2.from, pending2.to, { class: "w100n-text-note is-active" })] : []
|
|
497
|
+
]);
|
|
498
|
+
var remap = (tr) => {
|
|
499
|
+
const start = tr.before.content.findDiffStart(tr.doc.content);
|
|
500
|
+
if (!tr.getMeta(ySyncPluginKey) || start === null) return tr.mapping;
|
|
501
|
+
let { a, b } = tr.before.content.findDiffEnd(tr.doc.content);
|
|
502
|
+
if (a < start) [a, b] = [start, b + start - a];
|
|
503
|
+
if (b < start) [a, b] = [a + start - b, start];
|
|
504
|
+
return new StepMap([start, a - start, b - start]);
|
|
505
|
+
};
|
|
506
|
+
var Notes = Extension2.create({
|
|
507
|
+
name: "notes",
|
|
508
|
+
addProseMirrorPlugins: () => [new Plugin2({
|
|
509
|
+
key: notes,
|
|
510
|
+
state: {
|
|
511
|
+
init: (_config, state) => ({ spots: [], active: null, pending: null, set: DecorationSet2.create(state.doc, []) }),
|
|
512
|
+
apply(tr, value2) {
|
|
513
|
+
const next = tr.getMeta(notes);
|
|
514
|
+
if (!next && (!tr.docChanged || !value2.spots.length && !value2.pending)) return value2;
|
|
515
|
+
const by = remap(tr);
|
|
516
|
+
const map = (r) => ({ ...r, from: by.map(r.from, 1), to: by.map(r.to, -1) });
|
|
517
|
+
const merged = { ...value2, spots: value2.spots.map(map), pending: value2.pending && map(value2.pending), ...next };
|
|
518
|
+
return { ...merged, set: paint(tr.doc, merged.spots, merged.active, merged.pending) };
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
props: { decorations: (state) => notes.getState(state).set }
|
|
522
|
+
})]
|
|
523
|
+
});
|
|
524
|
+
function kit(kind, t, live) {
|
|
525
|
+
return [
|
|
526
|
+
StarterKit.configure({ trailingNode: false, link: { openOnClick: false, autolink: true, defaultProtocol: "https" }, dropcursor: { color: "#8b5cf6", width: 2 }, ...live ? { undoRedo: false } : {} }),
|
|
527
|
+
TaskList,
|
|
528
|
+
TaskItem.configure({ nested: true, a11y: { checkboxLabel: (node) => node.textContent || t.tasks } }),
|
|
529
|
+
TableKit.configure({ table: { resizable: false } }),
|
|
530
|
+
Image.configure({ inline: true, allowBase64: true }),
|
|
531
|
+
Highlight.configure({ multicolor: true }),
|
|
532
|
+
TextStyle,
|
|
533
|
+
Color,
|
|
534
|
+
FontSize,
|
|
535
|
+
FontFamily,
|
|
536
|
+
Blocks,
|
|
537
|
+
PageBreak.configure({ label: t.pageBreak }),
|
|
538
|
+
Toc.configure({ relative: kind === "markdown", label: t.toc, empty: t.tocEmpty }),
|
|
539
|
+
Note,
|
|
540
|
+
Notes,
|
|
541
|
+
...kind === "docx" ? [Pager, Locks.configure({ label: t.locked }), revision("insertion", "ins"), revision("deletion", "del"), Suggest] : [],
|
|
542
|
+
...live ? [Collaboration.configure({ document: live.doc }), CollaborationCaret.configure({ provider: live.link, user: live.user })] : []
|
|
543
|
+
];
|
|
544
|
+
}
|
|
545
|
+
var textblocks = (editor, change) => editor.chain().focus().command(({ tr, state }) => {
|
|
546
|
+
state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos) => {
|
|
547
|
+
if (!node.isTextblock) return true;
|
|
548
|
+
for (const [key2, value2] of Object.entries(change(node.attrs))) if (node.attrs[key2] !== value2) tr.setNodeAttribute(pos, key2, value2);
|
|
549
|
+
return false;
|
|
550
|
+
});
|
|
551
|
+
return true;
|
|
552
|
+
}).run();
|
|
553
|
+
var align = (editor, value2) => textblocks(editor, () => ({ align: value2 === "left" ? null : value2 }));
|
|
554
|
+
var indent = (editor, step) => {
|
|
555
|
+
const type = editor.isActive("taskItem") ? "taskItem" : editor.isActive("listItem") ? "listItem" : null;
|
|
556
|
+
if (type) return step > 0 ? editor.chain().focus().sinkListItem(type).run() : editor.chain().focus().liftListItem(type).run();
|
|
557
|
+
return textblocks(editor, (attrs2) => ({ indent: Math.min(8, Math.max(0, Number(attrs2.indent) + step)) }));
|
|
558
|
+
};
|
|
559
|
+
var clear = (editor) => {
|
|
560
|
+
const chain = editor.chain().focus();
|
|
561
|
+
for (const mark of ["bold", "italic", "underline", "strike", "code", "highlight", "textStyle"]) chain.unsetMark(mark);
|
|
562
|
+
chain.run();
|
|
563
|
+
return textblocks(editor, () => ({ align: null, indent: 0 }));
|
|
564
|
+
};
|
|
565
|
+
function locate(doc, list) {
|
|
566
|
+
if (!list.length) return [];
|
|
567
|
+
const marked2 = /* @__PURE__ */ new Map();
|
|
568
|
+
doc.descendants((node, pos) => {
|
|
569
|
+
if (!node.isText) return;
|
|
570
|
+
for (const mark of node.marks) {
|
|
571
|
+
if (mark.type.name !== "comment") continue;
|
|
572
|
+
const found = marked2.get(mark.attrs.id);
|
|
573
|
+
if (found) Object.assign(found, { to: pos + node.nodeSize, text: found.text + node.text });
|
|
574
|
+
else marked2.set(mark.attrs.id, { from: pos, to: pos + node.nodeSize, text: node.text });
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
578
|
+
const search = (quote) => {
|
|
579
|
+
const line = quote.split("\n").find((part) => part.trim())?.trim();
|
|
580
|
+
let hit = null;
|
|
581
|
+
if (line) doc.descendants((node, pos) => {
|
|
582
|
+
if (hit) return false;
|
|
583
|
+
if (!node.isTextblock) return true;
|
|
584
|
+
const at = node.textBetween(0, node.content.size, void 0, "\uFFFC").indexOf(line);
|
|
585
|
+
if (at >= 0) hit = { from: pos + 1 + at, to: pos + 1 + at + line.length };
|
|
586
|
+
return false;
|
|
587
|
+
});
|
|
588
|
+
return hit;
|
|
589
|
+
};
|
|
590
|
+
return list.flatMap((c) => {
|
|
591
|
+
const own = [c.anchor, c.id].find((id) => id && marked2.has(id));
|
|
592
|
+
let range = own ? marked2.get(own) : void 0;
|
|
593
|
+
if (!range) {
|
|
594
|
+
const twin = [...marked2].find(([id, m]) => !claimed.has(id) && m.text === c.quote);
|
|
595
|
+
if (twin) {
|
|
596
|
+
claimed.add(twin[0]);
|
|
597
|
+
range = twin[1];
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
range ?? (range = search(c.quote));
|
|
601
|
+
return range ? [{ id: c.id, from: range.from, to: range.to }] : [];
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// src/editor/markdown.ts
|
|
606
|
+
import { marked } from "marked";
|
|
607
|
+
import { MarkdownSerializer } from "prosemirror-markdown";
|
|
608
|
+
var tags = { u: "underline", ins: "underline", mark: "highlight", s: "strike", del: "strike", b: "bold", strong: "bold", i: "italic", em: "italic" };
|
|
609
|
+
var decode = (text) => text.includes("&") ? new DOMParser().parseFromString(`<p>${text.replace(/</g, "<")}</p>`, "text/html").body.textContent ?? text : text;
|
|
610
|
+
var unique = (marks) => [...new Map(marks.map((m) => [m.type, m])).values()];
|
|
611
|
+
function inline(tokens = [], outer = []) {
|
|
612
|
+
const out = [];
|
|
613
|
+
let open = [];
|
|
614
|
+
const marks = () => unique([...outer, ...open]);
|
|
615
|
+
const text = (value2, extra = []) => {
|
|
616
|
+
const set = unique([...marks(), ...extra]);
|
|
617
|
+
const clean = out[out.length - 1]?.type === "hardBreak" ? value2.replace(/^\n/, "") : value2;
|
|
618
|
+
if (clean) out.push({ type: "text", text: clean, ...set.length ? { marks: set } : {} });
|
|
619
|
+
};
|
|
620
|
+
const wrap = (children, mark) => out.push(...inline(children, [...marks(), mark]));
|
|
621
|
+
for (const token of tokens) {
|
|
622
|
+
if (token.type === "text") {
|
|
623
|
+
if (token.tokens) out.push(...inline(token.tokens, marks()));
|
|
624
|
+
else text(decode(token.text));
|
|
625
|
+
} else if (token.type === "escape") text(decode(token.text));
|
|
626
|
+
else if (token.type === "strong") wrap(token.tokens, { type: "bold" });
|
|
627
|
+
else if (token.type === "em") wrap(token.tokens, { type: "italic" });
|
|
628
|
+
else if (token.type === "del") wrap(token.tokens, { type: "strike" });
|
|
629
|
+
else if (token.type === "codespan") text(token.text, [{ type: "code" }]);
|
|
630
|
+
else if (token.type === "br") out.push({ type: "hardBreak" });
|
|
631
|
+
else if (token.type === "link") wrap(token.tokens, { type: "link", attrs: { href: token.href } });
|
|
632
|
+
else if (token.type === "image") out.push({ type: "image", attrs: { src: token.href, alt: token.text || null, title: token.title || null }, ...marks().length ? { marks: marks() } : {} });
|
|
633
|
+
else if (token.type === "html") {
|
|
634
|
+
const tag = /^<(\/?)([a-z]+)\s*\/?>$/i.exec(token.raw.trim());
|
|
635
|
+
const name = tag?.[2].toLowerCase() ?? "";
|
|
636
|
+
if (name === "br") out.push({ type: "hardBreak" });
|
|
637
|
+
else if (!tags[name]) text(token.raw);
|
|
638
|
+
else open = tag[1] ? open.filter((m) => m.type !== tags[name]) : [...open, { type: tags[name] }];
|
|
639
|
+
} else if (token.type !== "checkbox") text(token.raw);
|
|
640
|
+
}
|
|
641
|
+
return out;
|
|
642
|
+
}
|
|
643
|
+
var fill = (content) => content.length ? content : [{ type: "paragraph" }];
|
|
644
|
+
function block(token, hints) {
|
|
645
|
+
const ref = (hint) => {
|
|
646
|
+
const id = `md${Object.keys(hints).length + 1}`;
|
|
647
|
+
hints[id] = hint;
|
|
648
|
+
return id;
|
|
649
|
+
};
|
|
650
|
+
switch (token.type) {
|
|
651
|
+
case "space":
|
|
652
|
+
case "def":
|
|
653
|
+
case "checkbox":
|
|
654
|
+
return [];
|
|
655
|
+
case "heading":
|
|
656
|
+
return [{ type: "heading", attrs: { level: token.depth }, content: inline(token.tokens) }];
|
|
657
|
+
case "paragraph":
|
|
658
|
+
case "text":
|
|
659
|
+
return [{ type: "paragraph", content: token.tokens ? inline(token.tokens) : inline([{ type: "text", raw: token.text, text: token.text }]) }];
|
|
660
|
+
case "blockquote":
|
|
661
|
+
return [{ type: "blockquote", content: fill(token.tokens.flatMap((t) => block(t, hints))) }];
|
|
662
|
+
case "code": {
|
|
663
|
+
const fence = /^ {0,3}(`{3,}|~{3,})/.exec(token.raw)?.[1][0];
|
|
664
|
+
return [{ type: "codeBlock", attrs: { language: token.lang || null, ref: fence ? ref({ fence: fence.repeat(3) }) : null }, content: token.text ? [{ type: "text", text: token.text }] : [] }];
|
|
665
|
+
}
|
|
666
|
+
case "html":
|
|
667
|
+
return [{ type: "codeBlock", attrs: { language: "html" }, content: [{ type: "text", text: token.raw.replace(/\n+$/, "") }] }];
|
|
668
|
+
case "hr":
|
|
669
|
+
return [{ type: "horizontalRule" }];
|
|
670
|
+
case "list": {
|
|
671
|
+
const list = token;
|
|
672
|
+
const tasks = list.items.every((entry2) => entry2.task);
|
|
673
|
+
const marker = /^\s*(?:([-*+])|\d+([.)]))/.exec(list.raw);
|
|
674
|
+
const id = ref({ bullet: marker?.[1], delim: marker?.[2], loose: list.loose });
|
|
675
|
+
return [{
|
|
676
|
+
type: tasks ? "taskList" : list.ordered ? "orderedList" : "bulletList",
|
|
677
|
+
attrs: list.ordered && !tasks ? { start: list.start === "" ? 1 : Number(list.start), ref: id } : { ref: id },
|
|
678
|
+
content: list.items.map((entry2) => {
|
|
679
|
+
const content = fill(entry2.tokens.flatMap((t) => block(t, hints)));
|
|
680
|
+
if (!tasks && entry2.task) content[0].content = [{ type: "text", text: entry2.checked ? "[x] " : "[ ] " }, ...content[0].content ?? []];
|
|
681
|
+
return tasks ? { type: "taskItem", attrs: { checked: !!entry2.checked }, content } : { type: "listItem", content };
|
|
682
|
+
})
|
|
683
|
+
}];
|
|
684
|
+
}
|
|
685
|
+
case "table": {
|
|
686
|
+
const table = token;
|
|
687
|
+
const cell2 = (type) => (c, i) => ({ type, attrs: { align: table.align[i] }, content: [{ type: "paragraph", content: inline(c.tokens) }] });
|
|
688
|
+
return [{ type: "table", content: [
|
|
689
|
+
{ type: "tableRow", content: table.header.map(cell2("tableHeader")) },
|
|
690
|
+
...table.rows.map((row2) => ({ type: "tableRow", content: row2.map(cell2("tableCell")) }))
|
|
691
|
+
] }];
|
|
692
|
+
}
|
|
693
|
+
default:
|
|
694
|
+
return [{ type: "paragraph", content: inline([{ type: "text", raw: token.raw, text: token.raw }]) }];
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
var opens = /^\s*<!--\s*toc\s*-->\s*$/i;
|
|
698
|
+
var shuts = /^\s*<!--\s*\/toc\s*-->\s*$/i;
|
|
699
|
+
var row = /^(\s*)[-*+]\s+\[((?:\\.|[^\]\\])*)\]\(#[^)\s]*\)\s*$/;
|
|
700
|
+
function contents(tokens, i) {
|
|
701
|
+
if (tokens[i].type !== "html" || !opens.test(tokens[i].raw)) return null;
|
|
702
|
+
let j = i + 1;
|
|
703
|
+
const skip2 = () => {
|
|
704
|
+
while (tokens[j]?.type === "space") j++;
|
|
705
|
+
};
|
|
706
|
+
skip2();
|
|
707
|
+
const list = tokens[j]?.type === "list" ? tokens[j++] : null;
|
|
708
|
+
skip2();
|
|
709
|
+
if (tokens[j]?.type !== "html" || !shuts.test(tokens[j].raw)) return null;
|
|
710
|
+
const rows = list ? list.raw.split("\n").filter((line) => line.trim()).map((line) => row.exec(line)) : [];
|
|
711
|
+
if (rows.some((r) => !r)) return null;
|
|
712
|
+
const steps = [...new Set(rows.map((r) => r[1].length))].sort((a, b) => a - b);
|
|
713
|
+
return { end: j, entries: rows.map((r) => [steps.indexOf(r[1].length) + 1, r[2].replace(/\\(.)/g, "$1")]) };
|
|
714
|
+
}
|
|
715
|
+
var slug = (text, seen2) => {
|
|
716
|
+
const base = text.toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, "").trim().replace(/\s/g, "-");
|
|
717
|
+
const n = seen2.get(base) ?? 0;
|
|
718
|
+
seen2.set(base, n + 1);
|
|
719
|
+
return n ? `${base}-${n}` : base;
|
|
720
|
+
};
|
|
721
|
+
function sniff(tokens) {
|
|
722
|
+
const style = { bullet: "-", delim: ".", em: "*", strong: "**", fence: "```", br: "\\\n", loose: false };
|
|
723
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
724
|
+
const note = (key2, value2) => {
|
|
725
|
+
if (seen2.has(key2)) return;
|
|
726
|
+
seen2.add(key2);
|
|
727
|
+
style[key2] = value2;
|
|
728
|
+
};
|
|
729
|
+
let loose = 0;
|
|
730
|
+
marked.walkTokens(tokens, (token) => {
|
|
731
|
+
if (token.type === "list") {
|
|
732
|
+
const marker = /^\s*(?:([-*+])|\d+([.)]))/.exec(token.raw);
|
|
733
|
+
if (token.ordered) note("delim", marker?.[2] ?? ".");
|
|
734
|
+
else note("bullet", marker?.[1] ?? "-");
|
|
735
|
+
loose += token.loose ? 1 : -1;
|
|
736
|
+
} else if (token.type === "em") note("em", token.raw[0]);
|
|
737
|
+
else if (token.type === "strong") note("strong", token.raw.slice(0, 2));
|
|
738
|
+
else if (token.type === "code" && /^ {0,3}(```|~~~)/.test(token.raw)) note("fence", token.raw.trimStart().slice(0, 3));
|
|
739
|
+
else if (token.type === "br" && token.raw !== "<br>") note("br", token.raw.startsWith("\\") ? "\\\n" : " \n");
|
|
740
|
+
});
|
|
741
|
+
style.loose = loose > 0;
|
|
742
|
+
return style;
|
|
743
|
+
}
|
|
744
|
+
function fromMarkdown(source) {
|
|
745
|
+
const bom = source.startsWith("\uFEFF");
|
|
746
|
+
const crlf = source.includes("\r\n");
|
|
747
|
+
const tokens = marked.lexer(source.slice(bom ? 1 : 0).replace(/\r\n?/g, "\n"));
|
|
748
|
+
const hints = {};
|
|
749
|
+
const content = [];
|
|
750
|
+
const raws = [];
|
|
751
|
+
let head = "";
|
|
752
|
+
let gap = "";
|
|
753
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
754
|
+
const token = tokens[i];
|
|
755
|
+
const toc = contents(tokens, i);
|
|
756
|
+
const made2 = toc ? [{ type: "toc", attrs: { entries: JSON.stringify(toc.entries) } }] : block(token, hints);
|
|
757
|
+
if (!made2.length) {
|
|
758
|
+
gap += token.raw;
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
if (raws.length) raws[raws.length - 1] += gap;
|
|
762
|
+
else head = gap;
|
|
763
|
+
gap = "";
|
|
764
|
+
content.push(...made2);
|
|
765
|
+
raws.push(toc ? tokens.slice(i, toc.end + 1).map((t) => t.raw).join("") : token.raw);
|
|
766
|
+
if (toc) i = toc.end;
|
|
767
|
+
}
|
|
768
|
+
if (!content.length) {
|
|
769
|
+
content.push({ type: "paragraph" });
|
|
770
|
+
raws.push("");
|
|
771
|
+
head = "";
|
|
772
|
+
}
|
|
773
|
+
return { doc: { type: "doc", content }, raws, head, tail: gap, style: sniff(tokens), hints, crlf, bom };
|
|
774
|
+
}
|
|
775
|
+
var track = ({ doc: _json, ...parsed }, doc) => {
|
|
776
|
+
const nodes = [];
|
|
777
|
+
doc.forEach((node) => nodes.push(node));
|
|
778
|
+
return nodes.length === parsed.raws.length ? { ...parsed, nodes } : { ...parsed, nodes: [], raws: [], head: "", tail: "\n" };
|
|
779
|
+
};
|
|
780
|
+
var ticks = (node, side) => {
|
|
781
|
+
const len = Math.max(0, ...(node.isText ? node.text.match(/`+/g) ?? [] : []).map((run) => run.length));
|
|
782
|
+
return len ? side > 0 ? ` ${"`".repeat(len + 1)}` : `${"`".repeat(len + 1)} ` : "`";
|
|
783
|
+
};
|
|
784
|
+
var plain2 = (mark, parent, index) => {
|
|
785
|
+
const node = parent.child(index);
|
|
786
|
+
const href = mark.attrs.href;
|
|
787
|
+
if (!node.isText || node.marks.length !== 1 || index + 1 < parent.childCount && mark.isInSet(parent.child(index + 1).marks)) return null;
|
|
788
|
+
const text = node.text;
|
|
789
|
+
if (text !== href && `mailto:${text}` !== href && !(text.startsWith("www.") && `http://${text}` === href)) return null;
|
|
790
|
+
const before = index ? parent.child(index - 1) : null;
|
|
791
|
+
const after = index + 1 < parent.childCount ? parent.child(index + 1) : null;
|
|
792
|
+
const left = before ? before.isText ? before.text.slice(-1) : "x" : "";
|
|
793
|
+
const right = after ? after.isText ? after.text : "x" : "";
|
|
794
|
+
return /^[\s(*_~]?$/.test(left) && /^([\s)]|[.,:;!?]+(\s|$)|$)/.test(right) ? "bare" : text === href || href.startsWith("mailto:") ? "angle" : null;
|
|
795
|
+
};
|
|
796
|
+
function serializer(style, hints, before, cell2 = false) {
|
|
797
|
+
let form = null;
|
|
798
|
+
const hint = (node) => hints[node.attrs.ref] ?? {};
|
|
799
|
+
const run = (parent, index, types) => {
|
|
800
|
+
let n = 0;
|
|
801
|
+
for (let i = index - 1; i >= 0 && types.includes(parent.child(i).type.name); i--) n++;
|
|
802
|
+
if (!index && before && types.includes(before.type.name)) n++;
|
|
803
|
+
return n % 2;
|
|
804
|
+
};
|
|
805
|
+
const tight = (state, node, render) => {
|
|
806
|
+
const deep = node.content.content.some((entry2) => entry2.content.content.filter((child) => !child.type.name.endsWith("List")).length > 1);
|
|
807
|
+
const was = state.options.tightLists;
|
|
808
|
+
state.options.tightLists = !deep && !(hint(node).loose ?? style.loose);
|
|
809
|
+
render();
|
|
810
|
+
state.options.tightLists = was;
|
|
811
|
+
};
|
|
812
|
+
const list = (state, node, parent, index) => {
|
|
813
|
+
const bullet = hint(node).bullet ?? (run(parent, index, ["bulletList", "taskList"]) ? style.bullet === "-" ? "*" : "-" : style.bullet);
|
|
814
|
+
tight(state, node, () => state.renderList(node, " ", () => `${bullet} `));
|
|
815
|
+
};
|
|
816
|
+
const blank2 = { open: "", close: "", mixable: true };
|
|
817
|
+
const wrap = (open, close = open) => ({ open, close, mixable: true, expelEnclosingWhitespace: true });
|
|
818
|
+
return new MarkdownSerializer({
|
|
819
|
+
paragraph(state, node) {
|
|
820
|
+
state.renderInline(node);
|
|
821
|
+
state.closeBlock(node);
|
|
822
|
+
},
|
|
823
|
+
heading(state, node) {
|
|
824
|
+
state.write(`${"#".repeat(node.attrs.level)} `);
|
|
825
|
+
state.renderInline(node, false);
|
|
826
|
+
state.closeBlock(node);
|
|
827
|
+
},
|
|
828
|
+
blockquote(state, node) {
|
|
829
|
+
state.wrapBlock("> ", null, node, () => state.renderContent(node));
|
|
830
|
+
},
|
|
831
|
+
codeBlock(state, node) {
|
|
832
|
+
const mark = (hint(node).fence ?? style.fence)[0];
|
|
833
|
+
const longest = Math.max(2, ...(node.textContent.match(new RegExp(`${mark}{3,}`, "g")) ?? []).map((r) => r.length));
|
|
834
|
+
const fence = mark.repeat(longest + 1);
|
|
835
|
+
state.write(`${fence}${node.attrs.language ?? ""}
|
|
836
|
+
`);
|
|
837
|
+
state.text(node.textContent, false);
|
|
838
|
+
state.ensureNewLine();
|
|
839
|
+
state.write(fence);
|
|
840
|
+
state.closeBlock(node);
|
|
841
|
+
},
|
|
842
|
+
horizontalRule(state, node) {
|
|
843
|
+
state.write("---");
|
|
844
|
+
state.closeBlock(node);
|
|
845
|
+
},
|
|
846
|
+
pageBreak(state, node) {
|
|
847
|
+
state.closeBlock(node);
|
|
848
|
+
},
|
|
849
|
+
toc(state, node) {
|
|
850
|
+
const seen2 = /* @__PURE__ */ new Map();
|
|
851
|
+
const lines2 = JSON.parse(node.attrs.entries).map(([level, text]) => `${" ".repeat(level - 1)}${style.bullet} [${text.replace(/[[\]\\]/g, "\\$&")}](#${slug(text, seen2)})
|
|
852
|
+
`);
|
|
853
|
+
state.write(`<!-- toc -->
|
|
854
|
+
${lines2.join("")}<!-- /toc -->`);
|
|
855
|
+
state.closeBlock(node);
|
|
856
|
+
},
|
|
857
|
+
bulletList: list,
|
|
858
|
+
taskList: list,
|
|
859
|
+
orderedList(state, node, parent, index) {
|
|
860
|
+
const start = node.attrs.start ?? 1;
|
|
861
|
+
const delim = hint(node).delim ?? (run(parent, index, ["orderedList"]) ? style.delim === "." ? ")" : "." : style.delim);
|
|
862
|
+
const width = String(start + node.childCount - 1).length;
|
|
863
|
+
tight(state, node, () => state.renderList(node, " ".repeat(width + 2), (i) => `${start + i}${delim} `));
|
|
864
|
+
},
|
|
865
|
+
listItem(state, node) {
|
|
866
|
+
state.renderContent(node);
|
|
867
|
+
},
|
|
868
|
+
taskItem(state, node) {
|
|
869
|
+
state.write(node.attrs.checked ? "[x] " : "[ ] ");
|
|
870
|
+
state.renderContent(node);
|
|
871
|
+
},
|
|
872
|
+
table(state, node) {
|
|
873
|
+
const rows = [];
|
|
874
|
+
const aligns = [];
|
|
875
|
+
node.forEach((row2, _, r) => {
|
|
876
|
+
const cells = [];
|
|
877
|
+
row2.forEach((c) => {
|
|
878
|
+
const span2 = c.attrs.colspan || 1;
|
|
879
|
+
const text = [];
|
|
880
|
+
c.forEach((child) => text.push(serializer(style, hints, null, true).serialize(c.type.schema.topNodeType.create(null, child)).replace(/\n+/g, " ")));
|
|
881
|
+
if (!r) aligns.push(c.attrs.align, ...Array(span2 - 1).fill(null));
|
|
882
|
+
cells.push(text.join("<br>").replace(/\|/g, "\\|"), ...Array(span2 - 1).fill(""));
|
|
883
|
+
});
|
|
884
|
+
rows.push(cells);
|
|
885
|
+
});
|
|
886
|
+
const width = Math.max(...rows.map((r) => r.length));
|
|
887
|
+
const line = (cells) => `| ${[...cells, ...Array(width - cells.length).fill("")].join(" | ")} |`;
|
|
888
|
+
const rule = Array.from({ length: width }, (_, i) => ({ left: ":---", center: ":---:", right: "---:" })[aligns[i] ?? ""] ?? "---");
|
|
889
|
+
[line(rows[0]), `| ${rule.join(" | ")} |`, ...rows.slice(1).map(line)].forEach((text, i) => {
|
|
890
|
+
if (i) state.ensureNewLine();
|
|
891
|
+
state.write(text);
|
|
892
|
+
});
|
|
893
|
+
state.closeBlock(node);
|
|
894
|
+
},
|
|
895
|
+
image(state, node) {
|
|
896
|
+
const src = String(node.attrs.src ?? "");
|
|
897
|
+
const title = node.attrs.title ? ` "${String(node.attrs.title).replace(/"/g, '\\"')}"` : "";
|
|
898
|
+
state.write(` ? `<${src}>` : src.replace(/[()]/g, "\\$&")}${title})`);
|
|
899
|
+
},
|
|
900
|
+
hardBreak(state, node, parent, index) {
|
|
901
|
+
for (let i = index + 1; i < parent.childCount; i++) {
|
|
902
|
+
if (parent.child(i).type === node.type) continue;
|
|
903
|
+
state.write(cell2 ? "<br>" : style.br);
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
},
|
|
907
|
+
text(state, node) {
|
|
908
|
+
state.text(node.text, !state.inAutolink);
|
|
909
|
+
}
|
|
910
|
+
}, {
|
|
911
|
+
italic: wrap(style.em),
|
|
912
|
+
bold: wrap(style.strong),
|
|
913
|
+
strike: wrap("~~"),
|
|
914
|
+
underline: wrap("<u>", "</u>"),
|
|
915
|
+
highlight: wrap("<mark>", "</mark>"),
|
|
916
|
+
textStyle: blank2,
|
|
917
|
+
comment: blank2,
|
|
918
|
+
link: {
|
|
919
|
+
open(state, mark, parent, index) {
|
|
920
|
+
form = plain2(mark, parent, index);
|
|
921
|
+
state.inAutolink = !!form;
|
|
922
|
+
return form === "bare" ? "" : form === "angle" ? "<" : "[";
|
|
923
|
+
},
|
|
924
|
+
close(state, mark) {
|
|
925
|
+
state.inAutolink = void 0;
|
|
926
|
+
const was = form;
|
|
927
|
+
form = null;
|
|
928
|
+
return was === "bare" ? "" : was === "angle" ? ">" : `](${String(mark.attrs.href).replace(/[()"]/g, "\\$&")})`;
|
|
929
|
+
},
|
|
930
|
+
mixable: true
|
|
931
|
+
},
|
|
932
|
+
code: { open: (_s, _m, parent, index) => ticks(parent.child(index), -1), close: (_s, _m, parent, index) => ticks(parent.child(index - 1), 1), escape: false }
|
|
933
|
+
}, { hardBreakNodeName: "hardBreak", strict: false, escapeExtraCharacters: /<(?=[A-Za-z/!?])/g });
|
|
934
|
+
}
|
|
935
|
+
var one = (node, before, base) => serializer(base.style, base.hints, before).serialize(node.type.schema.topNodeType.create(null, node)).replace(/\n+$/, "");
|
|
936
|
+
function toMarkdown(doc, base) {
|
|
937
|
+
const nodes = [];
|
|
938
|
+
const found = [];
|
|
939
|
+
let j = 0;
|
|
940
|
+
doc.forEach((node) => {
|
|
941
|
+
let k = -1;
|
|
942
|
+
for (let m = j; m < Math.min(base.nodes.length, j + 64) && k < 0; m++) if (base.nodes[m] === node || base.nodes[m].eq(node)) k = m;
|
|
943
|
+
if (k >= 0) j = k + 1;
|
|
944
|
+
nodes.push(node);
|
|
945
|
+
found.push(k);
|
|
946
|
+
});
|
|
947
|
+
let out = base.head;
|
|
948
|
+
const starts = [];
|
|
949
|
+
nodes.forEach((node, i) => {
|
|
950
|
+
const k = found[i];
|
|
951
|
+
if (i && !(k >= 0 && found[i - 1] === k - 1)) out = out.replace(/\n*$/, "\n\n");
|
|
952
|
+
starts.push(out.length);
|
|
953
|
+
out += k >= 0 ? base.raws[k] : one(node, i ? nodes[i - 1] : null, base);
|
|
954
|
+
});
|
|
955
|
+
const last = found[found.length - 1];
|
|
956
|
+
const end = last >= 0 && last === base.nodes.length - 1;
|
|
957
|
+
if (!end) out = out.replace(/\n*$/, "\n");
|
|
958
|
+
const cut = out.length;
|
|
959
|
+
out += end ? base.tail : base.tail.trim() ? `
|
|
960
|
+
${base.tail.replace(/^\n+/, "")}` : "";
|
|
961
|
+
const at = starts.map((s) => Math.min(s, cut));
|
|
962
|
+
const raws = at.map((s, i) => out.slice(s, i + 1 < at.length ? at[i + 1] : cut));
|
|
963
|
+
const text = base.crlf ? out.replace(/\n/g, "\r\n") : out;
|
|
964
|
+
return { text: base.bom ? `\uFEFF${text}` : text, base: { ...base, nodes, raws, tail: out.slice(cut) } };
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// src/sheets/model.ts
|
|
968
|
+
var SheetRefusal = class extends Error {
|
|
969
|
+
constructor(code, sheet = "") {
|
|
970
|
+
super(code);
|
|
971
|
+
this.code = code;
|
|
972
|
+
this.sheet = sheet;
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
var counter = 0;
|
|
976
|
+
var fresh = (prefix) => `${prefix}${Date.now().toString(36)}${(counter++).toString(36)}${Math.random().toString(36).slice(2, 6)}`;
|
|
977
|
+
var numbered = (prefix, count) => Array.from({ length: count }, (_, i) => `${prefix}${i}`);
|
|
978
|
+
function insert(list, at, count, prefix) {
|
|
979
|
+
list.splice(at, 0, ...Array.from({ length: count }, () => fresh(prefix)));
|
|
980
|
+
}
|
|
981
|
+
function move(list, from, count, to) {
|
|
982
|
+
const taken = list.splice(from, count);
|
|
983
|
+
list.splice(to > from ? to - count : to, 0, ...taken);
|
|
984
|
+
}
|
|
985
|
+
function resize(list, count, prefix) {
|
|
986
|
+
if (list.length > count) list.length = count;
|
|
987
|
+
else insert(list, list.length, count - list.length, prefix);
|
|
988
|
+
}
|
|
989
|
+
function rebase(model, lines2, sheets) {
|
|
990
|
+
model.origin = { sheets, lines: Object.fromEntries(Object.entries(lines2).map(([id, l]) => [id, { rows: [...l.rows], cols: [...l.cols] }])) };
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
// src/sheets/csv.ts
|
|
994
|
+
function decode2(bytes) {
|
|
995
|
+
if (bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) return { text: new TextDecoder("utf-8").decode(bytes.subarray(3)), encoding: "utf-8", bom: true };
|
|
996
|
+
if (bytes[0] === 255 && bytes[1] === 254) return { text: new TextDecoder("utf-16le").decode(bytes.subarray(2)), encoding: "utf-16le", bom: true };
|
|
997
|
+
if (bytes[0] === 254 && bytes[1] === 255) return { text: new TextDecoder("utf-16be").decode(bytes.subarray(2)), encoding: "utf-16be", bom: true };
|
|
998
|
+
try {
|
|
999
|
+
return { text: new TextDecoder("utf-8", { fatal: true }).decode(bytes), encoding: "utf-8", bom: false };
|
|
1000
|
+
} catch {
|
|
1001
|
+
const scored = ["windows-1252", "windows-1250", "windows-1251"].map((encoding) => {
|
|
1002
|
+
const text = new TextDecoder(encoding).decode(bytes);
|
|
1003
|
+
let score = 0;
|
|
1004
|
+
for (const [word] of text.matchAll(/\p{L}+/gu)) {
|
|
1005
|
+
const cyrillic = (word.match(/\p{Script=Cyrillic}/gu) ?? []).length;
|
|
1006
|
+
const accented = (word.match(/[^\x00-\x7f\p{Script=Cyrillic}]/gu) ?? []).length;
|
|
1007
|
+
if (cyrillic === word.length || !cyrillic && accented * 2 <= word.length) score += 1;
|
|
1008
|
+
else score -= 1;
|
|
1009
|
+
}
|
|
1010
|
+
score -= 3 * (text.match(/\p{L}[^\p{L}\x00-\x7f]|[^\p{L}\x00-\x7f]\p{L}/gu) ?? []).length;
|
|
1011
|
+
return { text, encoding, score };
|
|
1012
|
+
});
|
|
1013
|
+
const best = scored.reduce((a, b) => b.score > a.score ? b : a);
|
|
1014
|
+
return { text: best.text, encoding: best.encoding, bom: false };
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
function encode(text, encoding, bom) {
|
|
1018
|
+
if (encoding === "utf-8") {
|
|
1019
|
+
const body = new TextEncoder().encode(text);
|
|
1020
|
+
if (!bom) return body;
|
|
1021
|
+
const out2 = new Uint8Array(body.length + 3);
|
|
1022
|
+
out2.set([239, 187, 191]);
|
|
1023
|
+
out2.set(body, 3);
|
|
1024
|
+
return out2;
|
|
1025
|
+
}
|
|
1026
|
+
if (encoding === "utf-16le" || encoding === "utf-16be") {
|
|
1027
|
+
const out2 = new Uint8Array(text.length * 2 + (bom ? 2 : 0));
|
|
1028
|
+
const view = new DataView(out2.buffer);
|
|
1029
|
+
let at = 0;
|
|
1030
|
+
if (bom) {
|
|
1031
|
+
view.setUint16(0, 65279, encoding === "utf-16le");
|
|
1032
|
+
at = 2;
|
|
1033
|
+
}
|
|
1034
|
+
for (let i = 0; i < text.length; i++) view.setUint16(at + i * 2, text.charCodeAt(i), encoding === "utf-16le");
|
|
1035
|
+
return out2;
|
|
1036
|
+
}
|
|
1037
|
+
const table = /* @__PURE__ */ new Map();
|
|
1038
|
+
const decoder2 = new TextDecoder(encoding);
|
|
1039
|
+
for (let b = 255; b >= 0; b--) table.set(decoder2.decode(new Uint8Array([b])), b);
|
|
1040
|
+
const out = new Uint8Array(text.length);
|
|
1041
|
+
for (let i = 0; i < text.length; i++) out[i] = table.get(text[i]) ?? 63;
|
|
1042
|
+
return out;
|
|
1043
|
+
}
|
|
1044
|
+
function split(text, delimiter, limit = Infinity) {
|
|
1045
|
+
const rows = [];
|
|
1046
|
+
let row2 = [];
|
|
1047
|
+
let i = 0;
|
|
1048
|
+
const n = text.length;
|
|
1049
|
+
while (i <= n && rows.length < limit) {
|
|
1050
|
+
const start = i;
|
|
1051
|
+
let value2 = "";
|
|
1052
|
+
if (text[i] === '"') {
|
|
1053
|
+
i++;
|
|
1054
|
+
while (i < n) {
|
|
1055
|
+
if (text[i] === '"') {
|
|
1056
|
+
if (text[i + 1] === '"') {
|
|
1057
|
+
value2 += '"';
|
|
1058
|
+
i += 2;
|
|
1059
|
+
continue;
|
|
1060
|
+
}
|
|
1061
|
+
i++;
|
|
1062
|
+
break;
|
|
1063
|
+
}
|
|
1064
|
+
value2 += text[i++];
|
|
1065
|
+
}
|
|
1066
|
+
while (i < n && text[i] !== delimiter && text[i] !== "\n" && text[i] !== "\r") value2 += text[i++];
|
|
1067
|
+
} else {
|
|
1068
|
+
while (i < n && text[i] !== delimiter && text[i] !== "\n" && text[i] !== "\r") i++;
|
|
1069
|
+
value2 = text.slice(start, i);
|
|
1070
|
+
}
|
|
1071
|
+
row2.push({ text: value2, raw: text.slice(start, i) });
|
|
1072
|
+
if (i >= n) {
|
|
1073
|
+
rows.push(row2);
|
|
1074
|
+
break;
|
|
1075
|
+
}
|
|
1076
|
+
if (text[i] === delimiter) {
|
|
1077
|
+
i++;
|
|
1078
|
+
continue;
|
|
1079
|
+
}
|
|
1080
|
+
i += text[i] === "\r" && text[i + 1] === "\n" ? 2 : 1;
|
|
1081
|
+
rows.push(row2);
|
|
1082
|
+
row2 = [];
|
|
1083
|
+
if (i >= n) break;
|
|
1084
|
+
}
|
|
1085
|
+
return rows;
|
|
1086
|
+
}
|
|
1087
|
+
function sniff2(text) {
|
|
1088
|
+
let best = ",", score = -1;
|
|
1089
|
+
for (const d of [",", ";", " ", "|"]) {
|
|
1090
|
+
const rows = split(text, d, 30).filter((r) => r.length > 1 || r[0]?.text);
|
|
1091
|
+
if (!rows.length) continue;
|
|
1092
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1093
|
+
for (const r of rows) counts.set(r.length, (counts.get(r.length) ?? 0) + 1);
|
|
1094
|
+
const [width, often] = [...counts].sort((a, b) => b[1] - a[1] || b[0] - a[0])[0];
|
|
1095
|
+
const s = width > 1 ? often * 100 + width : 0;
|
|
1096
|
+
if (s > score) {
|
|
1097
|
+
score = s;
|
|
1098
|
+
best = d;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
return best;
|
|
1102
|
+
}
|
|
1103
|
+
var numeric = (s, decimal) => decimal === "," ? /^-?(0|[1-9]\d*)(,\d+)?$/.test(s) : /^-?(0|[1-9]\d*)(\.\d+)?([eE][-+]?\d+)?$/.test(s);
|
|
1104
|
+
function readCsv(bytes) {
|
|
1105
|
+
const { text, encoding, bom } = decode2(new Uint8Array(bytes));
|
|
1106
|
+
const delimiter = sniff2(text);
|
|
1107
|
+
const eol = /\r\n/.test(text) ? "\r\n" : /\r(?!\n)/.test(text) && !text.includes("\n") ? "\r" : "\n";
|
|
1108
|
+
const rows = split(text, delimiter);
|
|
1109
|
+
const end = /[\r\n]$/.test(text);
|
|
1110
|
+
if (end && rows.length && rows[rows.length - 1].length === 1 && rows[rows.length - 1][0].raw === "") rows.pop();
|
|
1111
|
+
let commas = 0, dots = 0;
|
|
1112
|
+
if (delimiter !== ",") for (const r of rows) for (const f of r) {
|
|
1113
|
+
if (/^-?\d+,\d+$/.test(f.text)) commas++;
|
|
1114
|
+
else if (/^-?\d+\.\d+$/.test(f.text)) dots++;
|
|
1115
|
+
}
|
|
1116
|
+
const decimal = commas > dots ? "," : ".";
|
|
1117
|
+
const cellData = {};
|
|
1118
|
+
let width = 0;
|
|
1119
|
+
rows.forEach((r, i) => {
|
|
1120
|
+
width = Math.max(width, r.length);
|
|
1121
|
+
r.forEach((f, c) => {
|
|
1122
|
+
if (f.text === "") return;
|
|
1123
|
+
(cellData[i] ?? (cellData[i] = {}))[c] = numeric(f.text, decimal) ? { v: Number(decimal === "," ? f.text.replace(",", ".") : f.text), t: 2 } : { v: f.text, t: 1 };
|
|
1124
|
+
});
|
|
1125
|
+
});
|
|
1126
|
+
const height = Math.max(rows.length + 100, 1e3);
|
|
1127
|
+
const cols = Math.max(width + 4, 26);
|
|
1128
|
+
const format = { delimiter, encoding, bom, eol, decimal, end };
|
|
1129
|
+
const book = {
|
|
1130
|
+
id: "book",
|
|
1131
|
+
name: "",
|
|
1132
|
+
appVersion: "",
|
|
1133
|
+
locale: "enUS",
|
|
1134
|
+
styles: {},
|
|
1135
|
+
sheetOrder: ["s1"],
|
|
1136
|
+
sheets: { s1: { id: "s1", name: "Sheet1", rowCount: height, columnCount: cols, cellData, defaultColumnWidth: 88, defaultRowHeight: 24 } }
|
|
1137
|
+
};
|
|
1138
|
+
return { book, csv: format, lines: { s1: { rows: numbered("r", height), cols: numbered("c", cols) } }, origin: { sheets: { s1: 1 }, lines: { s1: { rows: numbered("r", height), cols: numbered("c", cols) } } } };
|
|
1139
|
+
}
|
|
1140
|
+
function value(x) {
|
|
1141
|
+
if (!x) return null;
|
|
1142
|
+
const stream = x.p?.body?.dataStream;
|
|
1143
|
+
if (stream !== void 0 && (x.v === void 0 || x.v === null || x.v === "")) return stream.replace(/\r?\n$/, "").replace(/\r\n?/g, "\n");
|
|
1144
|
+
if (x.t === 3 && typeof x.v === "number") return x.v === 1;
|
|
1145
|
+
return x.v ?? null;
|
|
1146
|
+
}
|
|
1147
|
+
function writeCsv(original, model) {
|
|
1148
|
+
const { text } = decode2(new Uint8Array(original));
|
|
1149
|
+
const format = model.csv ?? readCsv(original).csv;
|
|
1150
|
+
const old = split(text, format.delimiter);
|
|
1151
|
+
if (format.end && old.length && old[old.length - 1].length === 1 && old[old.length - 1][0].raw === "") old.pop();
|
|
1152
|
+
const sid = model.book.sheetOrder[0];
|
|
1153
|
+
const sheet = model.book.sheets[sid];
|
|
1154
|
+
const cells = sheet.cellData ?? {};
|
|
1155
|
+
const lines2 = model.lines[sid], origin = model.origin.lines[sid] ?? lines2;
|
|
1156
|
+
const rowFrom = new Map(origin.rows.map((id, i) => [id, i])), colFrom = new Map(origin.cols.map((id, i) => [id, i]));
|
|
1157
|
+
const quote = (s) => s.includes(format.delimiter) || s.includes('"') || s.includes("\n") || s.includes("\r") ? `"${s.replace(/"/g, '""')}"` : s;
|
|
1158
|
+
const show = (v) => {
|
|
1159
|
+
if (v === null || v === void 0) return "";
|
|
1160
|
+
if (typeof v === "boolean") return v ? "TRUE" : "FALSE";
|
|
1161
|
+
if (typeof v === "number") return format.decimal === "," ? String(v).replace(".", ",") : String(v);
|
|
1162
|
+
return String(v);
|
|
1163
|
+
};
|
|
1164
|
+
const last = Math.max(-1, ...Object.keys(cells).map(Number).filter((r) => Object.values(cells[r] ?? {}).some((x) => show(value(x)) !== "")));
|
|
1165
|
+
const out = [];
|
|
1166
|
+
for (let r = 0; r <= last; r++) {
|
|
1167
|
+
const r0 = rowFrom.get(lines2.rows[r]) ?? -1;
|
|
1168
|
+
const was = r0 >= 0 ? old[r0] : void 0;
|
|
1169
|
+
const line = cells[r] ?? {};
|
|
1170
|
+
const filled2 = Object.keys(line).map(Number).filter((c) => show(value(line[c])) !== "");
|
|
1171
|
+
let count = filled2.length ? Math.max(...filled2) + 1 : 0;
|
|
1172
|
+
if (was) for (let c0 = 0; c0 < was.length; c0++) count = Math.max(count, lines2.cols.indexOf(origin.cols[c0]) + 1);
|
|
1173
|
+
const fields = [];
|
|
1174
|
+
for (let c = 0; c < count; c++) {
|
|
1175
|
+
const c0 = colFrom.get(lines2.cols[c]) ?? -1;
|
|
1176
|
+
const before = was && c0 >= 0 ? was[c0] : void 0;
|
|
1177
|
+
const now = show(value(line[c]));
|
|
1178
|
+
if (before && now === before.text) fields.push(before.raw);
|
|
1179
|
+
else if (before && before.text !== "" && now !== "" && numeric(before.text, format.decimal) && Number(before.text.replace(",", ".")) === Number(now.replace(",", "."))) fields.push(before.raw);
|
|
1180
|
+
else fields.push(quote(now));
|
|
1181
|
+
}
|
|
1182
|
+
out.push(fields.join(format.delimiter));
|
|
1183
|
+
}
|
|
1184
|
+
const body = out.join(format.eol) + (format.end && out.length ? format.eol : "");
|
|
1185
|
+
const bytes = encode(body, format.encoding, format.bom);
|
|
1186
|
+
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// src/sheets/pack.ts
|
|
1190
|
+
var decoder = new TextDecoder();
|
|
1191
|
+
var Pack = class {
|
|
1192
|
+
constructor(bytes) {
|
|
1193
|
+
this.names = /* @__PURE__ */ new Map();
|
|
1194
|
+
this.changed = /* @__PURE__ */ new Map();
|
|
1195
|
+
this.entries = unzip(new Uint8Array(bytes));
|
|
1196
|
+
this.entries.forEach((e, i) => this.names.set(e.name.replace(/^\//, ""), i));
|
|
1197
|
+
}
|
|
1198
|
+
bytes(name) {
|
|
1199
|
+
const next = this.changed.get(name);
|
|
1200
|
+
if (next !== void 0) return typeof next === "string" ? new TextEncoder().encode(next) : next;
|
|
1201
|
+
const i = this.names.get(name);
|
|
1202
|
+
return i === void 0 ? null : inflate(this.entries[i]);
|
|
1203
|
+
}
|
|
1204
|
+
text(name) {
|
|
1205
|
+
const next = this.changed.get(name);
|
|
1206
|
+
if (typeof next === "string") return next;
|
|
1207
|
+
const bytes = this.bytes(name);
|
|
1208
|
+
return bytes && decoder.decode(bytes);
|
|
1209
|
+
}
|
|
1210
|
+
put(name, value2) {
|
|
1211
|
+
this.changed.set(name, value2);
|
|
1212
|
+
}
|
|
1213
|
+
rels(part) {
|
|
1214
|
+
const xml = this.text(relsOf(part));
|
|
1215
|
+
if (!xml) return [];
|
|
1216
|
+
const base = part.includes("/") ? part.slice(0, part.lastIndexOf("/") + 1) : "";
|
|
1217
|
+
return [...xml.matchAll(/<(?:\w+:)?Relationship\b[^>]*>/g)].map((m) => {
|
|
1218
|
+
const a = Object.fromEntries(attrs(m[0]));
|
|
1219
|
+
const external = a.TargetMode === "External";
|
|
1220
|
+
return { id: a.Id, type: a.Type.slice(a.Type.lastIndexOf("/") + 1), target: external ? a.Target : resolve(base, a.Target), external };
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
build() {
|
|
1224
|
+
const out = [];
|
|
1225
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
1226
|
+
for (const e of this.entries) {
|
|
1227
|
+
const name = e.name.replace(/^\//, "");
|
|
1228
|
+
seen2.add(name);
|
|
1229
|
+
const next = this.changed.get(name);
|
|
1230
|
+
if (next === null) continue;
|
|
1231
|
+
out.push(next === void 0 ? e : entry(e.name, typeof next === "string" ? new TextEncoder().encode(next) : next, e));
|
|
1232
|
+
}
|
|
1233
|
+
const like = this.entries[0];
|
|
1234
|
+
for (const [name, next] of this.changed) if (!seen2.has(name) && next !== null) out.push(entry(name, typeof next === "string" ? new TextEncoder().encode(next) : next, like));
|
|
1235
|
+
return zip(out);
|
|
1236
|
+
}
|
|
1237
|
+
};
|
|
1238
|
+
var relsOf = (part) => {
|
|
1239
|
+
const i = part.lastIndexOf("/");
|
|
1240
|
+
return `${part.slice(0, i + 1)}_rels/${part.slice(i + 1)}.rels`;
|
|
1241
|
+
};
|
|
1242
|
+
function resolve(base, target) {
|
|
1243
|
+
if (target.startsWith("/")) return target.slice(1);
|
|
1244
|
+
const parts2 = (base + target).split("/");
|
|
1245
|
+
const out = [];
|
|
1246
|
+
for (const p of parts2) {
|
|
1247
|
+
if (p === "..") out.pop();
|
|
1248
|
+
else if (p !== "." && p !== "") out.push(p);
|
|
1249
|
+
}
|
|
1250
|
+
return out.join("/");
|
|
1251
|
+
}
|
|
1252
|
+
function relative(from, to) {
|
|
1253
|
+
const a = from.split("/").slice(0, -1), b = to.split("/");
|
|
1254
|
+
let i = 0;
|
|
1255
|
+
while (i < a.length && a[i] === b[i]) i++;
|
|
1256
|
+
return [...a.slice(i).map(() => ".."), ...b.slice(i)].join("/");
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// src/sheets/styles.ts
|
|
1260
|
+
var builtin = {
|
|
1261
|
+
1: "0",
|
|
1262
|
+
2: "0.00",
|
|
1263
|
+
3: "#,##0",
|
|
1264
|
+
4: "#,##0.00",
|
|
1265
|
+
5: '"$"#,##0_);("$"#,##0)',
|
|
1266
|
+
6: '"$"#,##0_);[Red]("$"#,##0)',
|
|
1267
|
+
7: '"$"#,##0.00_);("$"#,##0.00)',
|
|
1268
|
+
8: '"$"#,##0.00_);[Red]("$"#,##0.00)',
|
|
1269
|
+
9: "0%",
|
|
1270
|
+
10: "0.00%",
|
|
1271
|
+
11: "0.00E+00",
|
|
1272
|
+
12: "# ?/?",
|
|
1273
|
+
13: "# ??/??",
|
|
1274
|
+
14: "yyyy-mm-dd",
|
|
1275
|
+
15: "d-mmm-yy",
|
|
1276
|
+
16: "d-mmm",
|
|
1277
|
+
17: "mmm-yy",
|
|
1278
|
+
18: "h:mm AM/PM",
|
|
1279
|
+
19: "h:mm:ss AM/PM",
|
|
1280
|
+
20: "h:mm",
|
|
1281
|
+
21: "h:mm:ss",
|
|
1282
|
+
22: "yyyy-mm-dd h:mm",
|
|
1283
|
+
37: "#,##0 ;(#,##0)",
|
|
1284
|
+
38: "#,##0 ;[Red](#,##0)",
|
|
1285
|
+
39: "#,##0.00;(#,##0.00)",
|
|
1286
|
+
40: "#,##0.00;[Red](#,##0.00)",
|
|
1287
|
+
45: "mm:ss",
|
|
1288
|
+
46: "[h]:mm:ss",
|
|
1289
|
+
47: "mmss.0",
|
|
1290
|
+
48: "##0.0E+0",
|
|
1291
|
+
49: "@"
|
|
1292
|
+
};
|
|
1293
|
+
var indexed = [
|
|
1294
|
+
"000000",
|
|
1295
|
+
"FFFFFF",
|
|
1296
|
+
"FF0000",
|
|
1297
|
+
"00FF00",
|
|
1298
|
+
"0000FF",
|
|
1299
|
+
"FFFF00",
|
|
1300
|
+
"FF00FF",
|
|
1301
|
+
"00FFFF",
|
|
1302
|
+
"000000",
|
|
1303
|
+
"FFFFFF",
|
|
1304
|
+
"FF0000",
|
|
1305
|
+
"00FF00",
|
|
1306
|
+
"0000FF",
|
|
1307
|
+
"FFFF00",
|
|
1308
|
+
"FF00FF",
|
|
1309
|
+
"00FFFF",
|
|
1310
|
+
"800000",
|
|
1311
|
+
"008000",
|
|
1312
|
+
"000080",
|
|
1313
|
+
"808000",
|
|
1314
|
+
"800080",
|
|
1315
|
+
"008080",
|
|
1316
|
+
"C0C0C0",
|
|
1317
|
+
"808080",
|
|
1318
|
+
"9999FF",
|
|
1319
|
+
"993366",
|
|
1320
|
+
"FFFFCC",
|
|
1321
|
+
"CCFFFF",
|
|
1322
|
+
"660066",
|
|
1323
|
+
"FF8080",
|
|
1324
|
+
"0066CC",
|
|
1325
|
+
"CCCCFF",
|
|
1326
|
+
"000080",
|
|
1327
|
+
"FF00FF",
|
|
1328
|
+
"FFFF00",
|
|
1329
|
+
"00FFFF",
|
|
1330
|
+
"800080",
|
|
1331
|
+
"800000",
|
|
1332
|
+
"008080",
|
|
1333
|
+
"0000FF",
|
|
1334
|
+
"00CCFF",
|
|
1335
|
+
"CCFFFF",
|
|
1336
|
+
"CCFFCC",
|
|
1337
|
+
"FFFF99",
|
|
1338
|
+
"99CCFF",
|
|
1339
|
+
"FF99CC",
|
|
1340
|
+
"CC99FF",
|
|
1341
|
+
"FFCC99",
|
|
1342
|
+
"3366FF",
|
|
1343
|
+
"33CCCC",
|
|
1344
|
+
"99CC00",
|
|
1345
|
+
"FFCC00",
|
|
1346
|
+
"FF9900",
|
|
1347
|
+
"FF6600",
|
|
1348
|
+
"666699",
|
|
1349
|
+
"969696",
|
|
1350
|
+
"003366",
|
|
1351
|
+
"339966",
|
|
1352
|
+
"003300",
|
|
1353
|
+
"333300",
|
|
1354
|
+
"993300",
|
|
1355
|
+
"993366",
|
|
1356
|
+
"333399",
|
|
1357
|
+
"333333",
|
|
1358
|
+
"000000",
|
|
1359
|
+
"FFFFFF"
|
|
1360
|
+
];
|
|
1361
|
+
var lines = ["", "thin", "hair", "dotted", "dashed", "dashDot", "dashDotDot", "double", "medium", "mediumDashed", "mediumDashDot", "mediumDashDotDot", "slantDashDot", "thick"];
|
|
1362
|
+
var across = ["", "left", "center", "right", "justify", "justify", "distributed"];
|
|
1363
|
+
var down = ["", "top", "center", "bottom"];
|
|
1364
|
+
var sides = [["l", "left"], ["r", "right"], ["t", "top"], ["b", "bottom"]];
|
|
1365
|
+
var fontOrder = ["b", "i", "strike", "condense", "extend", "outline", "shadow", "u", "vertAlign", "sz", "color", "name", "family", "charset", "scheme"];
|
|
1366
|
+
function tinted(hex2, tint) {
|
|
1367
|
+
if (!tint) return hex2;
|
|
1368
|
+
const [r, g, b] = [0, 2, 4].map((i) => parseInt(hex2.slice(i, i + 2), 16) / 255);
|
|
1369
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
|
1370
|
+
let h = 0, s = 0, l = (max + min) / 2;
|
|
1371
|
+
if (max !== min) {
|
|
1372
|
+
const d = max - min;
|
|
1373
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
1374
|
+
h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
|
|
1375
|
+
h /= 6;
|
|
1376
|
+
}
|
|
1377
|
+
l = tint < 0 ? l * (1 + tint) : l * (1 - tint) + tint;
|
|
1378
|
+
const hue = (p2, q2, t) => {
|
|
1379
|
+
if (t < 0) t += 1;
|
|
1380
|
+
if (t > 1) t -= 1;
|
|
1381
|
+
return t < 1 / 6 ? p2 + (q2 - p2) * 6 * t : t < 1 / 2 ? q2 : t < 2 / 3 ? p2 + (q2 - p2) * (2 / 3 - t) * 6 : p2;
|
|
1382
|
+
};
|
|
1383
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s, p = 2 * l - q;
|
|
1384
|
+
const out = s === 0 ? [l, l, l] : [hue(p, q, h + 1 / 3), hue(p, q, h), hue(p, q, h - 1 / 3)];
|
|
1385
|
+
return out.map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join("").toUpperCase();
|
|
1386
|
+
}
|
|
1387
|
+
function palette(theme) {
|
|
1388
|
+
if (!theme) return ["FFFFFF", "000000", "E7E6E6", "44546A", "4472C4", "ED7D31", "A5A5A5", "FFC000", "5B9BD5", "70AD47", "0563C1", "954F72"];
|
|
1389
|
+
const scheme = /<(?:\w+:)?clrScheme\b[^>]*>([\s\S]*?)<\/(?:\w+:)?clrScheme>/.exec(theme)?.[1] ?? "";
|
|
1390
|
+
const pick = (name) => {
|
|
1391
|
+
const m = new RegExp(`<(?:\\w+:)?${name}>([\\s\\S]*?)</(?:\\w+:)?${name}>`).exec(scheme)?.[1] ?? "";
|
|
1392
|
+
return /(?:val|lastClr)="([0-9A-Fa-f]{6})"/.exec(m.includes("lastClr") ? m.replace(/val="\w+"/, "") : m)?.[1]?.toUpperCase() ?? "000000";
|
|
1393
|
+
};
|
|
1394
|
+
const [dk1, lt1, dk2, lt2] = ["dk1", "lt1", "dk2", "lt2"].map(pick);
|
|
1395
|
+
return [lt1, dk1, lt2, dk2, ...["accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "hlink", "folHlink"].map(pick)];
|
|
1396
|
+
}
|
|
1397
|
+
var hex = (c) => {
|
|
1398
|
+
const s = String(c ?? "").trim();
|
|
1399
|
+
let m = /^#?([0-9a-f]{6})$/i.exec(s);
|
|
1400
|
+
if (m) return "#" + m[1].toUpperCase();
|
|
1401
|
+
m = /^#?([0-9a-f]{3})$/i.exec(s);
|
|
1402
|
+
if (m) return "#" + m[1].split("").map((x) => x + x).join("").toUpperCase();
|
|
1403
|
+
m = /^rgba?\((\d+),\s*(\d+),\s*(\d+)/i.exec(s);
|
|
1404
|
+
return m ? "#" + [m[1], m[2], m[3]].map((v) => Number(v).toString(16).padStart(2, "0")).join("").toUpperCase() : null;
|
|
1405
|
+
};
|
|
1406
|
+
function norm(l) {
|
|
1407
|
+
const out = {};
|
|
1408
|
+
if (l.bl) out.bl = 1;
|
|
1409
|
+
if (l.it) out.it = 1;
|
|
1410
|
+
if (l.ul?.s) out.ul = { s: 1 };
|
|
1411
|
+
if (l.st?.s) out.st = { s: 1 };
|
|
1412
|
+
if (l.va === 2 || l.va === 3) out.va = l.va;
|
|
1413
|
+
if (l.fs) out.fs = Number(l.fs);
|
|
1414
|
+
if (l.ff) out.ff = l.ff;
|
|
1415
|
+
const cl = hex(l.cl?.rgb);
|
|
1416
|
+
if (cl) out.cl = { rgb: cl };
|
|
1417
|
+
const bg = hex(l.bg?.rgb);
|
|
1418
|
+
if (bg) out.bg = { rgb: bg };
|
|
1419
|
+
if (l.bd) {
|
|
1420
|
+
const bd = {};
|
|
1421
|
+
for (const k of ["t", "b", "l", "r", "tl_br", "bl_tr"]) {
|
|
1422
|
+
const b = l.bd[k];
|
|
1423
|
+
if (b && b.s) bd[k] = { s: b.s, cl: { rgb: hex(b.cl?.rgb) ?? "#000000" } };
|
|
1424
|
+
}
|
|
1425
|
+
if (Object.keys(bd).length) out.bd = bd;
|
|
1426
|
+
}
|
|
1427
|
+
if (l.ht) out.ht = l.ht;
|
|
1428
|
+
if (l.vt) out.vt = l.vt;
|
|
1429
|
+
if (l.tb === 3) out.tb = 3;
|
|
1430
|
+
if (l.tr && (l.tr.a || l.tr.v)) out.tr = { a: l.tr.a ?? 0, v: l.tr.v ? 1 : 0 };
|
|
1431
|
+
if (l.n?.pattern && l.n.pattern !== "General") out.n = { pattern: l.n.pattern };
|
|
1432
|
+
return out;
|
|
1433
|
+
}
|
|
1434
|
+
var Styles = class {
|
|
1435
|
+
constructor(xml, theme) {
|
|
1436
|
+
this.formats = /* @__PURE__ */ new Map();
|
|
1437
|
+
this.fonts = [];
|
|
1438
|
+
this.fills = [];
|
|
1439
|
+
this.borders = [];
|
|
1440
|
+
this.xfs = [];
|
|
1441
|
+
this.looks = [];
|
|
1442
|
+
this.index = /* @__PURE__ */ new Map();
|
|
1443
|
+
this.added = false;
|
|
1444
|
+
this.custom = null;
|
|
1445
|
+
this.prefix = () => this.root?.name.includes(":") ? this.root.name.slice(0, this.root.name.indexOf(":") + 1) : "";
|
|
1446
|
+
this.bare = (name) => name.slice(name.indexOf(":") + 1);
|
|
1447
|
+
this.child = (el, name) => el.kids.find((k) => this.bare(k.name) === name);
|
|
1448
|
+
this.xml = xml;
|
|
1449
|
+
this.theme = palette(theme);
|
|
1450
|
+
this.root = xml ? parse(xml).kids.find((k) => !k.name.startsWith("?")) ?? null : null;
|
|
1451
|
+
const s = xml ?? "";
|
|
1452
|
+
const list = (name, tag) => {
|
|
1453
|
+
const el = this.root && this.child(this.root, name);
|
|
1454
|
+
return el ? el.kids.filter((k) => this.bare(k.name) === tag).map((k) => s.slice(k.start, k.end)) : [];
|
|
1455
|
+
};
|
|
1456
|
+
for (const f of list("numFmts", "numFmt")) {
|
|
1457
|
+
const a = Object.fromEntries(attrs(f));
|
|
1458
|
+
this.formats.set(Number(a.numFmtId), a.formatCode);
|
|
1459
|
+
}
|
|
1460
|
+
const colours = this.root && this.child(this.root, "colors");
|
|
1461
|
+
const custom = colours && this.child(colours, "indexedColors");
|
|
1462
|
+
if (custom) this.custom = custom.kids.map((k) => (attr(s, k, "rgb") ?? "FF000000").slice(-6).toUpperCase());
|
|
1463
|
+
this.fonts = list("fonts", "font");
|
|
1464
|
+
this.fills = list("fills", "fill");
|
|
1465
|
+
this.borders = list("borders", "border");
|
|
1466
|
+
this.xfs = list("cellXfs", "xf");
|
|
1467
|
+
if (!this.fonts.length) this.fonts = ['<font><sz val="11"/><name val="Calibri"/></font>'];
|
|
1468
|
+
if (!this.fills.length) this.fills = ['<fill><patternFill patternType="none"/></fill>', '<fill><patternFill patternType="gray125"/></fill>'];
|
|
1469
|
+
if (!this.borders.length) this.borders = ["<border><left/><right/><top/><bottom/><diagonal/></border>"];
|
|
1470
|
+
if (!this.xfs.length) this.xfs = ['<xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/>'];
|
|
1471
|
+
const raw = this.xfs.map((x) => this.look(x));
|
|
1472
|
+
this.looks = raw.map((l) => norm({ ...raw[0], ...l }));
|
|
1473
|
+
this.looks.forEach((l, i) => {
|
|
1474
|
+
const k = JSON.stringify(l);
|
|
1475
|
+
if (!this.index.has(k)) this.index.set(k, i);
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1478
|
+
color(tag) {
|
|
1479
|
+
if (!tag) return void 0;
|
|
1480
|
+
const a = Object.fromEntries(attrs(tag));
|
|
1481
|
+
if (a.auto === "1" || a.auto === "true") return void 0;
|
|
1482
|
+
let hex2;
|
|
1483
|
+
if (a.rgb) hex2 = a.rgb.slice(-6).toUpperCase();
|
|
1484
|
+
else if (a.theme !== void 0) hex2 = this.theme[Number(a.theme)];
|
|
1485
|
+
else if (a.indexed !== void 0) hex2 = (this.custom ?? indexed)[Number(a.indexed)] ?? (Number(a.indexed) === 64 ? "000000" : void 0);
|
|
1486
|
+
return hex2 && "#" + tinted(hex2, Number(a.tint ?? 0));
|
|
1487
|
+
}
|
|
1488
|
+
parts(xml) {
|
|
1489
|
+
const root = parse(xml).kids[0];
|
|
1490
|
+
const out = /* @__PURE__ */ new Map();
|
|
1491
|
+
if (root) for (const k of root.kids) out.set(this.bare(k.name), xml.slice(k.start, k.end));
|
|
1492
|
+
return { root, out, open: root ? xml.slice(root.start, root.open) : "" };
|
|
1493
|
+
}
|
|
1494
|
+
pattern(id) {
|
|
1495
|
+
return this.formats.get(id) ?? builtin[id] ?? (id === 0 ? "General" : "General");
|
|
1496
|
+
}
|
|
1497
|
+
look(xf) {
|
|
1498
|
+
const a = Object.fromEntries(attrs(xf.slice(0, xf.indexOf(">") + 1)));
|
|
1499
|
+
const s = {};
|
|
1500
|
+
const font = this.parts(this.fonts[Number(a.fontId ?? 0)] ?? this.fonts[0]).out;
|
|
1501
|
+
const val = (tag) => tag && Object.fromEntries(attrs(tag)).val;
|
|
1502
|
+
const on = (tag) => tag !== void 0 && !/^(0|false)$/.test(val(tag) ?? "1");
|
|
1503
|
+
if (on(font.get("b"))) s.bl = 1;
|
|
1504
|
+
if (on(font.get("i"))) s.it = 1;
|
|
1505
|
+
if (on(font.get("strike"))) s.st = { s: 1 };
|
|
1506
|
+
if (font.has("u") && val(font.get("u")) !== "none") s.ul = { s: 1 };
|
|
1507
|
+
const va = val(font.get("vertAlign"));
|
|
1508
|
+
if (va === "superscript") s.va = 3;
|
|
1509
|
+
if (va === "subscript") s.va = 2;
|
|
1510
|
+
if (font.has("sz")) s.fs = Number(val(font.get("sz")));
|
|
1511
|
+
if (font.has("name")) s.ff = val(font.get("name"));
|
|
1512
|
+
const cl = this.color(font.get("color"));
|
|
1513
|
+
if (cl) s.cl = { rgb: cl };
|
|
1514
|
+
const fill3 = this.fills[Number(a.fillId ?? 0)];
|
|
1515
|
+
const pattern = fill3 && /patternType="(\w+)"/.exec(fill3)?.[1];
|
|
1516
|
+
if (fill3 && pattern && pattern !== "none" && pattern !== "gray125") {
|
|
1517
|
+
const fg = this.color(/<(?:\w+:)?fgColor\b[^>]*>/.exec(fill3)?.[0]);
|
|
1518
|
+
if (fg) s.bg = { rgb: fg };
|
|
1519
|
+
}
|
|
1520
|
+
const border = this.parts(this.borders[Number(a.borderId ?? 0)] ?? "<border/>");
|
|
1521
|
+
const bd = {};
|
|
1522
|
+
for (const [key2, name] of sides) {
|
|
1523
|
+
const el = border.out.get(name) ?? border.out.get(name === "left" ? "start" : name === "right" ? "end" : name);
|
|
1524
|
+
const style = el && /style="(\w+)"/.exec(el)?.[1];
|
|
1525
|
+
if (!style || style === "none") continue;
|
|
1526
|
+
bd[key2] = { s: Math.max(1, lines.indexOf(style)), cl: { rgb: this.color(/<(?:\w+:)?color\b[^>]*>/.exec(el)?.[0]) ?? "#000000" } };
|
|
1527
|
+
}
|
|
1528
|
+
const diagonal = border.out.get("diagonal");
|
|
1529
|
+
const dstyle = diagonal && /style="(\w+)"/.exec(diagonal)?.[1];
|
|
1530
|
+
if (dstyle && dstyle !== "none") {
|
|
1531
|
+
const line = { s: Math.max(1, lines.indexOf(dstyle)), cl: { rgb: this.color(/<(?:\w+:)?color\b[^>]*>/.exec(diagonal)?.[0]) ?? "#000000" } };
|
|
1532
|
+
const flags = Object.fromEntries(attrs(border.open));
|
|
1533
|
+
if (flags.diagonalDown === "1" || flags.diagonalDown === "true") bd.tl_br = line;
|
|
1534
|
+
if (flags.diagonalUp === "1" || flags.diagonalUp === "true") bd.bl_tr = line;
|
|
1535
|
+
}
|
|
1536
|
+
if (Object.keys(bd).length) s.bd = bd;
|
|
1537
|
+
const align2 = /<(?:\w+:)?alignment\b[^>]*>/.exec(xf)?.[0];
|
|
1538
|
+
if (align2) {
|
|
1539
|
+
const al = Object.fromEntries(attrs(align2));
|
|
1540
|
+
const ht = across.indexOf(al.horizontal === "centerContinuous" ? "center" : al.horizontal);
|
|
1541
|
+
if (ht > 0) s.ht = ht;
|
|
1542
|
+
const vt = down.indexOf(al.vertical);
|
|
1543
|
+
if (vt > 0) s.vt = vt;
|
|
1544
|
+
if (al.wrapText === "1" || al.wrapText === "true") s.tb = 3;
|
|
1545
|
+
const turn = Number(al.textRotation ?? 0);
|
|
1546
|
+
if (turn === 255) s.tr = { a: 0, v: 1 };
|
|
1547
|
+
else if (turn) s.tr = { a: turn <= 90 ? turn : 90 - turn, v: 0 };
|
|
1548
|
+
}
|
|
1549
|
+
const id = Number(a.numFmtId ?? 0);
|
|
1550
|
+
if (id) s.n = { pattern: this.pattern(id) };
|
|
1551
|
+
return s;
|
|
1552
|
+
}
|
|
1553
|
+
find(look) {
|
|
1554
|
+
return this.index.get(JSON.stringify(norm(look)));
|
|
1555
|
+
}
|
|
1556
|
+
derive(base, look) {
|
|
1557
|
+
look = norm(look);
|
|
1558
|
+
const key2 = JSON.stringify(look);
|
|
1559
|
+
const known = this.index.get(key2);
|
|
1560
|
+
if (known !== void 0) return known;
|
|
1561
|
+
const was = this.looks[base] ?? {};
|
|
1562
|
+
const xf = this.xfs[base] ?? this.xfs[0];
|
|
1563
|
+
const head = xf.slice(0, xf.indexOf(">") + 1);
|
|
1564
|
+
const a = new Map(attrs(head));
|
|
1565
|
+
const same3 = (keys) => keys.every((k) => JSON.stringify(was[k]) === JSON.stringify(look[k]));
|
|
1566
|
+
const p = this.prefix();
|
|
1567
|
+
if (!same3(["bl", "it", "st", "ul", "va", "fs", "ff", "cl"])) {
|
|
1568
|
+
a.set("fontId", String(this.add("fonts", this.font(Number(a.get("fontId") ?? 0), was, look))));
|
|
1569
|
+
a.set("applyFont", "1");
|
|
1570
|
+
}
|
|
1571
|
+
if (!same3(["bg"])) {
|
|
1572
|
+
a.set("fillId", String(look.bg?.rgb ? this.add("fills", `<${p}fill><${p}patternFill patternType="solid"><${p}fgColor rgb="${argb(look.bg.rgb)}"/><${p}bgColor indexed="64"/></${p}patternFill></${p}fill>`) : 0));
|
|
1573
|
+
a.set("applyFill", "1");
|
|
1574
|
+
}
|
|
1575
|
+
if (!same3(["bd"])) {
|
|
1576
|
+
a.set("borderId", String(this.add("borders", this.border(Number(a.get("borderId") ?? 0), was, look))));
|
|
1577
|
+
a.set("applyBorder", "1");
|
|
1578
|
+
}
|
|
1579
|
+
if (!same3(["n"])) {
|
|
1580
|
+
a.set("numFmtId", String(this.format(look.n?.pattern ?? "General")));
|
|
1581
|
+
a.set("applyNumberFormat", "1");
|
|
1582
|
+
}
|
|
1583
|
+
let inner = xf.endsWith("/>") && xf.indexOf(">") === xf.length - 1 ? "" : xf.slice(head.length, xf.lastIndexOf("<"));
|
|
1584
|
+
if (!same3(["ht", "vt", "tb", "tr"])) {
|
|
1585
|
+
const old = /<(?:\w+:)?alignment\b[^>]*>/.exec(inner)?.[0];
|
|
1586
|
+
const al = new Map(old ? attrs(old) : []);
|
|
1587
|
+
const put = (name2, value2) => value2 === null ? al.delete(name2) : al.set(name2, value2);
|
|
1588
|
+
put("horizontal", look.ht ? across[look.ht] : null);
|
|
1589
|
+
put("vertical", look.vt ? down[look.vt] : null);
|
|
1590
|
+
put("wrapText", look.tb === 3 ? "1" : null);
|
|
1591
|
+
put("textRotation", look.tr?.v ? "255" : look.tr?.a ? String(look.tr.a > 0 ? look.tr.a : 90 - look.tr.a) : null);
|
|
1592
|
+
const tag = al.size ? `<${p}alignment ${[...al].map(([k, v]) => `${k}="${escape(v)}"`).join(" ")}/>` : "";
|
|
1593
|
+
inner = old ? inner.replace(old, tag) : tag + inner;
|
|
1594
|
+
a.set("applyAlignment", "1");
|
|
1595
|
+
}
|
|
1596
|
+
const name = head.slice(1, head.search(/[\s/>]/));
|
|
1597
|
+
const open = `<${name} ${[...a].map(([k, v]) => `${k}="${escape(v)}"`).join(" ")}`;
|
|
1598
|
+
const next = inner ? `${open}>${inner}</${name}>` : `${open}/>`;
|
|
1599
|
+
this.xfs.push(next);
|
|
1600
|
+
this.added = true;
|
|
1601
|
+
const index = this.xfs.length - 1;
|
|
1602
|
+
this.looks.push(norm({ ...this.looks[0], ...this.look(next) }));
|
|
1603
|
+
this.index.set(key2, index);
|
|
1604
|
+
return index;
|
|
1605
|
+
}
|
|
1606
|
+
add(list, xml) {
|
|
1607
|
+
const at = this[list].indexOf(xml);
|
|
1608
|
+
if (at >= 0) return at;
|
|
1609
|
+
this[list].push(xml);
|
|
1610
|
+
this.added = true;
|
|
1611
|
+
return this[list].length - 1;
|
|
1612
|
+
}
|
|
1613
|
+
font(id, was, look) {
|
|
1614
|
+
const p = this.prefix();
|
|
1615
|
+
const { out } = this.parts(this.fonts[id] ?? this.fonts[0]);
|
|
1616
|
+
const set = (name, xml) => xml === null ? out.delete(name) : out.set(name, xml);
|
|
1617
|
+
const diff = (k) => JSON.stringify(was[k]) !== JSON.stringify(look[k]);
|
|
1618
|
+
if (diff("bl")) set("b", look.bl ? `<${p}b/>` : null);
|
|
1619
|
+
if (diff("it")) set("i", look.it ? `<${p}i/>` : null);
|
|
1620
|
+
if (diff("st")) set("strike", look.st?.s ? `<${p}strike/>` : null);
|
|
1621
|
+
if (diff("ul")) set("u", look.ul?.s ? `<${p}u/>` : null);
|
|
1622
|
+
if (diff("va")) set("vertAlign", look.va === 3 ? `<${p}vertAlign val="superscript"/>` : look.va === 2 ? `<${p}vertAlign val="subscript"/>` : null);
|
|
1623
|
+
if (diff("fs")) set("sz", `<${p}sz val="${look.fs ?? 11}"/>`);
|
|
1624
|
+
if (diff("cl")) set("color", look.cl?.rgb ? `<${p}color rgb="${argb(look.cl.rgb)}"/>` : null);
|
|
1625
|
+
if (diff("ff")) {
|
|
1626
|
+
set("name", `<${p}name val="${escape(look.ff ?? "Calibri")}"/>`);
|
|
1627
|
+
set("scheme", null);
|
|
1628
|
+
}
|
|
1629
|
+
return `<${p}font>${fontOrder.filter((k) => out.has(k)).map((k) => out.get(k)).join("")}</${p}font>`;
|
|
1630
|
+
}
|
|
1631
|
+
border(id, was, look) {
|
|
1632
|
+
const p = this.prefix();
|
|
1633
|
+
const { out, open } = this.parts(this.borders[id] ?? this.borders[0]);
|
|
1634
|
+
const flags = new Map(open ? attrs(open) : []);
|
|
1635
|
+
const line = (name, b) => b ? `<${p}${name} style="${lines[b.s] || "thin"}"><${p}color rgb="${argb(b.cl?.rgb ?? "#000000")}"/></${p}${name}>` : `<${p}${name}/>`;
|
|
1636
|
+
const before = was.bd ?? {}, after = look.bd ?? {};
|
|
1637
|
+
const parts2 = [];
|
|
1638
|
+
for (const [key2, name] of sides) {
|
|
1639
|
+
const old = out.get(name) ?? out.get(name === "left" ? "start" : name === "right" ? "end" : name);
|
|
1640
|
+
parts2.push(JSON.stringify(before[key2]) === JSON.stringify(after[key2]) && old ? old : line(name, after[key2]));
|
|
1641
|
+
}
|
|
1642
|
+
const diagonal = after.tl_br ?? after.bl_tr;
|
|
1643
|
+
if (JSON.stringify(before.tl_br) === JSON.stringify(after.tl_br) && JSON.stringify(before.bl_tr) === JSON.stringify(after.bl_tr)) parts2.push(out.get("diagonal") ?? `<${p}diagonal/>`);
|
|
1644
|
+
else {
|
|
1645
|
+
parts2.push(line("diagonal", diagonal));
|
|
1646
|
+
if (after.tl_br) flags.set("diagonalDown", "1");
|
|
1647
|
+
else flags.delete("diagonalDown");
|
|
1648
|
+
if (after.bl_tr) flags.set("diagonalUp", "1");
|
|
1649
|
+
else flags.delete("diagonalUp");
|
|
1650
|
+
}
|
|
1651
|
+
for (const extra of ["vertical", "horizontal"]) if (out.has(extra)) parts2.push(out.get(extra));
|
|
1652
|
+
const attributes = [...flags].map(([k, v]) => ` ${k}="${escape(v)}"`).join("");
|
|
1653
|
+
return `<${p}border${attributes}>${parts2.join("")}</${p}border>`;
|
|
1654
|
+
}
|
|
1655
|
+
format(pattern) {
|
|
1656
|
+
if (pattern === "General") return 0;
|
|
1657
|
+
for (const [id2, code] of this.formats) if (code === pattern) return id2;
|
|
1658
|
+
for (const [id2, code] of Object.entries(builtin)) if (code === pattern) return Number(id2);
|
|
1659
|
+
const id = Math.max(163, ...this.formats.keys()) + 1;
|
|
1660
|
+
this.formats.set(id, pattern);
|
|
1661
|
+
this.added = true;
|
|
1662
|
+
return id;
|
|
1663
|
+
}
|
|
1664
|
+
build() {
|
|
1665
|
+
if (!this.added) return null;
|
|
1666
|
+
const p = this.prefix();
|
|
1667
|
+
const s = this.xml ?? `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1668
|
+
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"></styleSheet>`;
|
|
1669
|
+
const root = parse(s).kids.find((k) => !k.name.startsWith("?"));
|
|
1670
|
+
const order2 = ["numFmts", "fonts", "fills", "borders", "cellStyleXfs", "cellXfs", "cellStyles", "dxfs", "tableStyles", "colors", "extLst"];
|
|
1671
|
+
const lists = {
|
|
1672
|
+
numFmts: [...this.formats].map(([id, code]) => `<${p}numFmt numFmtId="${id}" formatCode="${escape(code)}"/>`),
|
|
1673
|
+
fonts: this.fonts,
|
|
1674
|
+
fills: this.fills,
|
|
1675
|
+
borders: this.borders,
|
|
1676
|
+
cellXfs: this.xfs
|
|
1677
|
+
};
|
|
1678
|
+
const edits2 = [];
|
|
1679
|
+
for (const name of Object.keys(lists)) {
|
|
1680
|
+
if (!lists[name].length) continue;
|
|
1681
|
+
const el = root.kids.find((k) => this.bare(k.name) === name);
|
|
1682
|
+
if (el) {
|
|
1683
|
+
const open = s.slice(el.start, el.open).replace(/\s*\/?>$/, "").replace(/\scount="\d*"/, "");
|
|
1684
|
+
edits2.push([el.start, el.end, `${open} count="${lists[name].length}">${lists[name].join("")}</${el.name}>`]);
|
|
1685
|
+
} else {
|
|
1686
|
+
const after = root.kids.find((k) => order2.indexOf(this.bare(k.name)) > order2.indexOf(name));
|
|
1687
|
+
const at = after ? after.start : root.close;
|
|
1688
|
+
edits2.push([at, at, `<${p}${name} count="${lists[name].length}">${lists[name].join("")}</${p}${name}>`]);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
edits2.sort((x, y) => y[0] - x[0]);
|
|
1692
|
+
let out = s;
|
|
1693
|
+
for (const [from, to, xml] of edits2) out = out.slice(0, from) + xml + out.slice(to);
|
|
1694
|
+
return out;
|
|
1695
|
+
}
|
|
1696
|
+
};
|
|
1697
|
+
var argb = (hex2) => "FF" + hex2.replace("#", "").toUpperCase().padStart(6, "0").slice(-6);
|
|
1698
|
+
|
|
1699
|
+
// src/sheets/xlsx.ts
|
|
1700
|
+
var key = (r, c) => r * 16384 + c;
|
|
1701
|
+
var px = { row: (pt2) => Math.round(pt2 * 4 / 3 * 100) / 100, col: (w) => Math.round(w * 7 + 5) };
|
|
1702
|
+
var pt = { row: (h) => Math.round(h * 3 / 4 * 100) / 100, col: (w) => Math.max(0, Math.round((w - 5) / 7 * 100) / 100) };
|
|
1703
|
+
var decodeX = (s) => s.includes("_x") ? s.replace(/_x([0-9A-Fa-f]{4})_/g, (_, h) => String.fromCharCode(parseInt(h, 16))) : s;
|
|
1704
|
+
function runs(xml) {
|
|
1705
|
+
const clean = xml.includes("rPh") ? xml.replace(/<(\w+:)?rPh\b[\s\S]*?<\/(\w+:)?rPh>/g, "") : xml;
|
|
1706
|
+
let out = "";
|
|
1707
|
+
for (const m of clean.matchAll(/<(?:\w+:)?t(?:\s[^>]*)?(?:\/>|>([\s\S]*?)<\/(?:\w+:)?t>)/g)) out += m[1] ?? "";
|
|
1708
|
+
return decodeX(unescape(out));
|
|
1709
|
+
}
|
|
1710
|
+
var patterns = /* @__PURE__ */ new Map();
|
|
1711
|
+
var attr2 = (tag, name) => {
|
|
1712
|
+
let re = patterns.get(name);
|
|
1713
|
+
if (!re) patterns.set(name, re = new RegExp(`\\s${name}="([^"]*)"`));
|
|
1714
|
+
const m = re.exec(tag);
|
|
1715
|
+
return m ? unescape(m[1]) : null;
|
|
1716
|
+
};
|
|
1717
|
+
var element = (xml, name) => {
|
|
1718
|
+
const m = new RegExp(`<((?:\\w+:)?${name})\\b[^>]*?(\\/?)>`).exec(xml);
|
|
1719
|
+
if (!m) return null;
|
|
1720
|
+
if (m[2]) return { start: m.index, open: m.index + m[0].length, close: m.index + m[0].length, end: m.index + m[0].length, tag: m[0] };
|
|
1721
|
+
const close = xml.indexOf(`</${m[1]}>`, m.index);
|
|
1722
|
+
return { start: m.index, open: m.index + m[0].length, close, end: close + m[1].length + 3, tag: m[0] };
|
|
1723
|
+
};
|
|
1724
|
+
function worksheets(bytes) {
|
|
1725
|
+
const pack = new Pack(bytes);
|
|
1726
|
+
const part = pack.rels("").find((r) => r.type === "officeDocument")?.target ?? "xl/workbook.xml";
|
|
1727
|
+
const rels = pack.rels(part);
|
|
1728
|
+
return [...(pack.text(part) ?? "").matchAll(/<(?:\w+:)?sheet\b[^>]*\/?>/g)].filter((m) => rels.find((r) => r.id === /\s[\w]+:id="([^"]*)"/.exec(m[0])?.[1])?.type === "worksheet").map((m) => Number(attr2(m[0], "sheetId")));
|
|
1729
|
+
}
|
|
1730
|
+
function load(bytes) {
|
|
1731
|
+
var _a, _b;
|
|
1732
|
+
const pack = new Pack(bytes);
|
|
1733
|
+
const office = pack.rels("").find((r) => r.type === "officeDocument");
|
|
1734
|
+
const part = office?.target ?? "xl/workbook.xml";
|
|
1735
|
+
const xml = pack.text(part);
|
|
1736
|
+
if (!xml) throw new Error("No workbook");
|
|
1737
|
+
const rels = pack.rels(part);
|
|
1738
|
+
const target = (type) => rels.find((r) => r.type === type)?.target;
|
|
1739
|
+
const themePart = target("theme");
|
|
1740
|
+
const stylesPart = target("styles");
|
|
1741
|
+
const styles = new Styles(stylesPart ? pack.text(stylesPart) : null, themePart ? pack.text(themePart) : null);
|
|
1742
|
+
const stringsPart = target("sharedStrings");
|
|
1743
|
+
const strings = [];
|
|
1744
|
+
const sst = stringsPart ? pack.text(stringsPart) : null;
|
|
1745
|
+
if (sst) for (const m of sst.matchAll(/<(?:\w+:)?si\b[^>]*?(?:\/>|>([\s\S]*?)<\/(?:\w+:)?si>)/g)) strings.push(m[1] ? runs(m[1]) : "");
|
|
1746
|
+
const date1904 = /<(?:\w+:)?workbookPr\b[^>]*\bdate1904="(1|true)"/.test(xml);
|
|
1747
|
+
const entries2 = [];
|
|
1748
|
+
for (const m of xml.matchAll(/<(?:\w+:)?sheet\b[^>]*\/?>/g)) {
|
|
1749
|
+
const tag = m[0];
|
|
1750
|
+
const rid = /\s[\w]+:id="([^"]*)"/.exec(tag)?.[1] ?? "";
|
|
1751
|
+
const rel = rels.find((r) => r.id === rid);
|
|
1752
|
+
entries2.push({ name: attr2(tag, "name") ?? "", sheetId: Number(attr2(tag, "sheetId")), rid, xml: tag, sheet: rel?.type === "worksheet" });
|
|
1753
|
+
}
|
|
1754
|
+
const book = {
|
|
1755
|
+
id: "book",
|
|
1756
|
+
name: "",
|
|
1757
|
+
appVersion: "",
|
|
1758
|
+
locale: "enUS",
|
|
1759
|
+
styles: {},
|
|
1760
|
+
sheetOrder: [],
|
|
1761
|
+
sheets: {},
|
|
1762
|
+
resources: [],
|
|
1763
|
+
defaultStyle: styles.looks[0]
|
|
1764
|
+
};
|
|
1765
|
+
if (date1904) book.dateSystem = "date1904";
|
|
1766
|
+
const notes2 = {};
|
|
1767
|
+
const validations = {};
|
|
1768
|
+
const filters = {};
|
|
1769
|
+
const model = { book, lines: {}, origin: { sheets: {}, lines: {} } };
|
|
1770
|
+
const sheets = [];
|
|
1771
|
+
const active = Number(/<(?:\w+:)?workbookView\b[^>]*\bactiveTab="(\d+)"/.exec(xml)?.[1] ?? 0);
|
|
1772
|
+
const useStyle = (xf) => {
|
|
1773
|
+
const id = `x${xf}`;
|
|
1774
|
+
if (!(id in book.styles)) book.styles[id] = styles.looks[xf] ?? {};
|
|
1775
|
+
return id;
|
|
1776
|
+
};
|
|
1777
|
+
for (const entry2 of entries2) {
|
|
1778
|
+
if (!entry2.sheet) continue;
|
|
1779
|
+
const rel = rels.find((r) => r.id === entry2.rid);
|
|
1780
|
+
const sxml = pack.text(rel.target);
|
|
1781
|
+
if (sxml === null) continue;
|
|
1782
|
+
const sid = `s${entry2.sheetId}`;
|
|
1783
|
+
const p = /<(\w+:)?worksheet\b/.exec(sxml)?.[1] ?? "";
|
|
1784
|
+
const srels = pack.rels(rel.target);
|
|
1785
|
+
const sheet = { id: sid, name: entry2.name, cellData: {}, rowData: {}, columnData: {}, mergeData: [] };
|
|
1786
|
+
const state = attr2(entry2.xml, "state");
|
|
1787
|
+
if (state === "hidden") sheet.hidden = 1;
|
|
1788
|
+
if (state === "veryHidden") sheet.hidden = 2;
|
|
1789
|
+
const open = element(sxml, `${p}sheetData`);
|
|
1790
|
+
const bounds = open ? [open.start, open.open, open.close, open.end] : [sxml.length, sxml.length, sxml.length, sxml.length];
|
|
1791
|
+
const head = open ? sxml.slice(0, open.start) : sxml;
|
|
1792
|
+
const tail = open ? sxml.slice(open.end) : "";
|
|
1793
|
+
const format = /<(?:\w+:)?sheetFormatPr\b[^>]*>/.exec(head)?.[0];
|
|
1794
|
+
const defaultRow = format && attr2(format, "defaultRowHeight") ? px.row(Number(attr2(format, "defaultRowHeight"))) : 20;
|
|
1795
|
+
const defaultCol = format && attr2(format, "defaultColWidth") ? px.col(Number(attr2(format, "defaultColWidth"))) : format && attr2(format, "baseColWidth") ? px.col(Number(attr2(format, "baseColWidth")) + 0.71) : 64;
|
|
1796
|
+
sheet.defaultRowHeight = defaultRow;
|
|
1797
|
+
sheet.defaultColumnWidth = defaultCol;
|
|
1798
|
+
const view = /<(?:\w+:)?sheetView\b[^>]*>/.exec(head)?.[0];
|
|
1799
|
+
if (view && attr2(view, "showGridLines") === "0") sheet.showGridlines = 0;
|
|
1800
|
+
if (view && attr2(view, "rightToLeft") === "1") sheet.rightToLeft = 1;
|
|
1801
|
+
if (view && attr2(view, "zoomScale")) sheet.zoomRatio = Number(attr2(view, "zoomScale")) / 100;
|
|
1802
|
+
const pane = /<(?:\w+:)?pane\b[^>]*>/.exec(head)?.[0];
|
|
1803
|
+
if (pane && /^frozen/.test(attr2(pane, "state") ?? "")) {
|
|
1804
|
+
const x = Number(attr2(pane, "xSplit") ?? 0), y = Number(attr2(pane, "ySplit") ?? 0);
|
|
1805
|
+
sheet.freeze = { xSplit: x, ySplit: y, startRow: y, startColumn: x };
|
|
1806
|
+
}
|
|
1807
|
+
const tab = /<(?:\w+:)?tabColor\b[^>]*>/.exec(head)?.[0];
|
|
1808
|
+
if (tab) {
|
|
1809
|
+
const c = styles.color(tab);
|
|
1810
|
+
if (c) sheet.tabColor = c;
|
|
1811
|
+
}
|
|
1812
|
+
const cols = [];
|
|
1813
|
+
for (const m of head.matchAll(/<(?:\w+:)?col\b[^>]*\/?>/g)) {
|
|
1814
|
+
const t = m[0];
|
|
1815
|
+
const spec = { min: Number(attr2(t, "min")), max: Number(attr2(t, "max")), xml: t, hidden: /^(1|true)$/.test(attr2(t, "hidden") ?? "") };
|
|
1816
|
+
if (attr2(t, "width") !== null && /^(1|true)$/.test(attr2(t, "customWidth") ?? "1")) spec.width = px.col(Number(attr2(t, "width")));
|
|
1817
|
+
if (attr2(t, "style") !== null && attr2(t, "style") !== "0") spec.style = Number(attr2(t, "style"));
|
|
1818
|
+
cols.push(spec);
|
|
1819
|
+
}
|
|
1820
|
+
const cellData = {};
|
|
1821
|
+
const rowData = {};
|
|
1822
|
+
const rows = /* @__PURE__ */ new Map();
|
|
1823
|
+
const cells = /* @__PURE__ */ new Map();
|
|
1824
|
+
const masters = /* @__PURE__ */ new Map();
|
|
1825
|
+
const children = [];
|
|
1826
|
+
const rowStyles = /* @__PURE__ */ new Map();
|
|
1827
|
+
let maxRow = -1, maxCol = -1;
|
|
1828
|
+
if (open && open.close > open.open) {
|
|
1829
|
+
const end = open.close;
|
|
1830
|
+
let at = open.open, row2 = -1, col = -1;
|
|
1831
|
+
while (at < end) {
|
|
1832
|
+
const lt = sxml.indexOf("<", at);
|
|
1833
|
+
if (lt < 0 || lt >= end) break;
|
|
1834
|
+
const gt = sxml.indexOf(">", lt);
|
|
1835
|
+
if (sxml.charCodeAt(lt + 1) === 47) {
|
|
1836
|
+
at = gt + 1;
|
|
1837
|
+
continue;
|
|
1838
|
+
}
|
|
1839
|
+
let j = lt + 1;
|
|
1840
|
+
while (j < gt) {
|
|
1841
|
+
const ch = sxml.charCodeAt(j);
|
|
1842
|
+
if (ch === 32 || ch === 47 || ch === 9 || ch === 10 || ch === 13) break;
|
|
1843
|
+
j++;
|
|
1844
|
+
}
|
|
1845
|
+
const name = sxml.slice(lt + 1 + p.length, j);
|
|
1846
|
+
const tag = sxml.slice(lt, gt + 1);
|
|
1847
|
+
if (name === "row") {
|
|
1848
|
+
const r = attr2(tag, "r");
|
|
1849
|
+
row2 = r ? Number(r) - 1 : row2 + 1;
|
|
1850
|
+
col = -1;
|
|
1851
|
+
rows.set(row2, { open: tag });
|
|
1852
|
+
const rd = {};
|
|
1853
|
+
const ht = attr2(tag, "ht");
|
|
1854
|
+
if (ht !== null) rd.h = px.row(Number(ht));
|
|
1855
|
+
if (ht !== null && /^(1|true)$/.test(attr2(tag, "customHeight") ?? "")) rd.ia = 0;
|
|
1856
|
+
if (/^(1|true)$/.test(attr2(tag, "hidden") ?? "")) rd.hd = 1;
|
|
1857
|
+
const rs = attr2(tag, "s");
|
|
1858
|
+
if (rs !== null && /^(1|true)$/.test(attr2(tag, "customFormat") ?? "")) {
|
|
1859
|
+
rowStyles.set(row2, Number(rs));
|
|
1860
|
+
rd.s = useStyle(Number(rs));
|
|
1861
|
+
}
|
|
1862
|
+
if (Object.keys(rd).length) rowData[row2] = rd;
|
|
1863
|
+
if (rd.h !== void 0 || rd.hd || rd.s) maxRow = Math.max(maxRow, row2);
|
|
1864
|
+
at = gt + 1;
|
|
1865
|
+
continue;
|
|
1866
|
+
}
|
|
1867
|
+
if (name !== "c") {
|
|
1868
|
+
at = gt + 1;
|
|
1869
|
+
continue;
|
|
1870
|
+
}
|
|
1871
|
+
const ref = attr2(tag, "r");
|
|
1872
|
+
if (ref) [, col] = cell(ref);
|
|
1873
|
+
else col += 1;
|
|
1874
|
+
const self = sxml.charCodeAt(gt - 1) === 47;
|
|
1875
|
+
const close = self ? gt + 1 : sxml.indexOf(`</${p}c>`, gt);
|
|
1876
|
+
const stop = self ? gt + 1 : close + p.length + 4;
|
|
1877
|
+
const inner = self ? "" : sxml.slice(gt + 1, close);
|
|
1878
|
+
const t = attr2(tag, "t");
|
|
1879
|
+
const s = Number(attr2(tag, "s") ?? 0);
|
|
1880
|
+
const out = {};
|
|
1881
|
+
let shared = false;
|
|
1882
|
+
if (inner) {
|
|
1883
|
+
const f = /<(?:\w+:)?f\b([^>]*?)(?:\/>|>([\s\S]*?)<\/(?:\w+:)?f>)/.exec(inner);
|
|
1884
|
+
if (f) {
|
|
1885
|
+
const kind = attr2(f[0], "t");
|
|
1886
|
+
const formula = f[2] === void 0 ? "" : unescape(f[2]);
|
|
1887
|
+
if (kind === "shared") {
|
|
1888
|
+
shared = true;
|
|
1889
|
+
const si = attr2(f[0], "si") ?? "";
|
|
1890
|
+
if (formula) masters.set(si, { f: formula, r: row2, c: col });
|
|
1891
|
+
else children.push([row2, col, si]);
|
|
1892
|
+
if (formula) out.f = "=" + plain(formula);
|
|
1893
|
+
} else if (kind !== "dataTable" && formula) out.f = "=" + plain(formula);
|
|
1894
|
+
}
|
|
1895
|
+
const v = /<(?:\w+:)?v>([\s\S]*?)<\/(?:\w+:)?v>/.exec(inner)?.[1];
|
|
1896
|
+
if (t === "inlineStr") {
|
|
1897
|
+
const is = /<(?:\w+:)?is>([\s\S]*?)<\/(?:\w+:)?is>/.exec(inner)?.[1];
|
|
1898
|
+
if (is !== void 0) {
|
|
1899
|
+
out.v = runs(is);
|
|
1900
|
+
out.t = 1;
|
|
1901
|
+
}
|
|
1902
|
+
} else if (v !== void 0) {
|
|
1903
|
+
if (t === "s") {
|
|
1904
|
+
out.v = strings[Number(v)] ?? "";
|
|
1905
|
+
out.t = 1;
|
|
1906
|
+
} else if (t === "str" || t === "e") {
|
|
1907
|
+
out.v = decodeX(unescape(v));
|
|
1908
|
+
out.t = 1;
|
|
1909
|
+
} else if (t === "b") {
|
|
1910
|
+
out.v = v === "1" || v === "true";
|
|
1911
|
+
out.t = 3;
|
|
1912
|
+
} else if (t === "d") {
|
|
1913
|
+
const d = Date.parse(v);
|
|
1914
|
+
out.v = Number.isNaN(d) ? v : (d - Date.UTC(1899, 11, 30)) / 864e5;
|
|
1915
|
+
out.t = Number.isNaN(d) ? 1 : 2;
|
|
1916
|
+
} else {
|
|
1917
|
+
out.v = Number(v);
|
|
1918
|
+
out.t = 2;
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
const styled = s || rowStyles.has(row2) || cols.some((spec) => spec.style !== void 0 && col + 1 >= spec.min && col + 1 <= spec.max);
|
|
1923
|
+
if (styled) out.s = useStyle(s);
|
|
1924
|
+
if (out.v !== void 0 || out.f || out.s || shared) {
|
|
1925
|
+
(cellData[row2] ?? (cellData[row2] = {}))[col] = out;
|
|
1926
|
+
if (out.v !== void 0 || out.f || s) {
|
|
1927
|
+
maxRow = Math.max(maxRow, row2);
|
|
1928
|
+
maxCol = Math.max(maxCol, col);
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
cells.set(key(row2, col), { start: lt, end: stop, shared });
|
|
1932
|
+
at = stop;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
for (const [r, c, si] of children) {
|
|
1936
|
+
const m = masters.get(si);
|
|
1937
|
+
const target2 = (_a = cellData[r] ?? (cellData[r] = {}))[c] ?? (_a[c] = {});
|
|
1938
|
+
if (m) target2.f = "=" + plain(shifted(m.f, r - m.r, c - m.c));
|
|
1939
|
+
}
|
|
1940
|
+
for (const spec of cols) if (spec.max <= 1024) maxCol = Math.max(maxCol, spec.max - 1);
|
|
1941
|
+
const merges = [];
|
|
1942
|
+
for (const m of tail.matchAll(/<(?:\w+:)?mergeCell\b[^>]*\/?>/g)) {
|
|
1943
|
+
const ref = attr2(m[0], "ref");
|
|
1944
|
+
if (!ref) continue;
|
|
1945
|
+
merges.push(ref);
|
|
1946
|
+
for (const b of boxes(ref)) {
|
|
1947
|
+
sheet.mergeData.push({ startRow: b.startRow, startColumn: b.startColumn, endRow: b.endRow, endColumn: b.endColumn });
|
|
1948
|
+
maxRow = Math.max(maxRow, b.endRow);
|
|
1949
|
+
maxCol = Math.max(maxCol, b.endColumn);
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
const rules = [];
|
|
1953
|
+
const dvs = [];
|
|
1954
|
+
const dvBlock = element(tail, `${p}dataValidations`);
|
|
1955
|
+
if (dvBlock) for (const m of tail.slice(dvBlock.open, dvBlock.close).matchAll(/<(?:\w+:)?dataValidation\b[^>]*?(?:\/>|>[\s\S]*?<\/(?:\w+:)?dataValidation>)/g)) {
|
|
1956
|
+
const rule = validation(m[0], `dv${dvs.length}`);
|
|
1957
|
+
dvs.push(m[0]);
|
|
1958
|
+
if (rule) rules.push(rule);
|
|
1959
|
+
}
|
|
1960
|
+
if (rules.length) validations[sid] = rules;
|
|
1961
|
+
const af = /<(?:\w+:)?autoFilter\b[^>]*?(?:\/>|>[\s\S]*?<\/(?:\w+:)?autoFilter>)/.exec(tail)?.[0] ?? null;
|
|
1962
|
+
if (af) {
|
|
1963
|
+
const [b] = boxes(attr2(af, "ref") ?? "");
|
|
1964
|
+
if (b) filters[sid] = { ref: { ...b, rangeType: 0 }, filterColumns: criteria(af), cachedFilteredOut: [] };
|
|
1965
|
+
}
|
|
1966
|
+
const sheetNotes = [];
|
|
1967
|
+
const commentsRel = srels.find((r) => r.type === "comments");
|
|
1968
|
+
const vmlRel = srels.find((r) => r.type === "vmlDrawing");
|
|
1969
|
+
const authors = [];
|
|
1970
|
+
if (commentsRel) {
|
|
1971
|
+
const cx = pack.text(commentsRel.target) ?? "";
|
|
1972
|
+
for (const m of cx.matchAll(/<(?:\w+:)?author>([\s\S]*?)<\/(?:\w+:)?author>|<(?:\w+:)?author\/>/g)) authors.push(unescape(m[1] ?? ""));
|
|
1973
|
+
for (const m of cx.matchAll(/<(?:\w+:)?comment\b[^>]*>[\s\S]*?<\/(?:\w+:)?comment>/g)) {
|
|
1974
|
+
const ref = attr2(m[0], "ref") ?? "";
|
|
1975
|
+
const textXml = /<(?:\w+:)?text>([\s\S]*?)<\/(?:\w+:)?text>/.exec(m[0])?.[1] ?? "";
|
|
1976
|
+
const note = { ref, xml: m[0], text: runs(textXml) };
|
|
1977
|
+
sheetNotes.push(note);
|
|
1978
|
+
const [r, c] = cell(ref);
|
|
1979
|
+
if (r < 0) continue;
|
|
1980
|
+
((_b = notes2[sid] ?? (notes2[sid] = {}))[r] ?? (_b[r] = {}))[c] = { note: note.text, width: 160, height: 72, show: false, id: `n${sheetNotes.length - 1}`, row: r, col: c };
|
|
1981
|
+
maxRow = Math.max(maxRow, r);
|
|
1982
|
+
maxCol = Math.max(maxCol, c);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
const height = Math.max(maxRow + 1 + 100, 1e3);
|
|
1986
|
+
const width = Math.max(maxCol + 1 + 4, 26);
|
|
1987
|
+
for (const spec of cols) {
|
|
1988
|
+
for (let c = spec.min - 1; c < Math.min(spec.max, width); c++) {
|
|
1989
|
+
const cd = {};
|
|
1990
|
+
if (spec.width !== void 0) cd.w = spec.width;
|
|
1991
|
+
if (spec.hidden) cd.hd = 1;
|
|
1992
|
+
if (spec.style !== void 0) cd.s = useStyle(spec.style);
|
|
1993
|
+
if (Object.keys(cd).length) sheet.columnData[c] = cd;
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
sheet.rowCount = height;
|
|
1997
|
+
sheet.columnCount = width;
|
|
1998
|
+
sheet.cellData = cellData;
|
|
1999
|
+
sheet.rowData = rowData;
|
|
2000
|
+
book.sheets[sid] = sheet;
|
|
2001
|
+
book.sheetOrder.push(sid);
|
|
2002
|
+
model.lines[sid] = { rows: numbered("r", height), cols: numbered("c", width) };
|
|
2003
|
+
model.origin.lines[sid] = { rows: numbered("r", height), cols: numbered("c", width) };
|
|
2004
|
+
model.origin.sheets[sid] = entry2.sheetId;
|
|
2005
|
+
sheets.push({
|
|
2006
|
+
sid,
|
|
2007
|
+
name: entry2.name,
|
|
2008
|
+
sheetId: entry2.sheetId,
|
|
2009
|
+
part: rel.target,
|
|
2010
|
+
xml: sxml,
|
|
2011
|
+
p,
|
|
2012
|
+
rels: srels,
|
|
2013
|
+
bounds,
|
|
2014
|
+
rows,
|
|
2015
|
+
cells,
|
|
2016
|
+
cols,
|
|
2017
|
+
merges,
|
|
2018
|
+
validations: dvs,
|
|
2019
|
+
notes: sheetNotes,
|
|
2020
|
+
comments: commentsRel?.target ?? null,
|
|
2021
|
+
vml: vmlRel?.target ?? null,
|
|
2022
|
+
authors,
|
|
2023
|
+
width
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
2026
|
+
const names = {};
|
|
2027
|
+
for (const m of xml.matchAll(/<(?:\w+:)?definedName\b([^>]*)>([\s\S]*?)<\/(?:\w+:)?definedName>/g)) {
|
|
2028
|
+
const name = attr2(m[0], "name") ?? "";
|
|
2029
|
+
if (name.startsWith("_xlnm.") || /^(1|true)$/.test(attr2(m[0], "hidden") ?? "")) continue;
|
|
2030
|
+
const local = attr2(m[0], "localSheetId");
|
|
2031
|
+
const scoped = local === null ? null : entries2[Number(local)];
|
|
2032
|
+
const id = `d${Object.keys(names).length}`;
|
|
2033
|
+
names[id] = { id, name, formulaOrRefString: plain(unescape(m[2])), localSheetId: scoped ? `s${scoped.sheetId}` : "AllDefaultWorkbook" };
|
|
2034
|
+
}
|
|
2035
|
+
const resources = book.resources;
|
|
2036
|
+
if (Object.keys(names).length) resources.push({ name: "SHEET_DEFINED_NAME_PLUGIN", data: JSON.stringify(names) });
|
|
2037
|
+
if (Object.keys(notes2).length) resources.push({ name: "SHEET_NOTE_PLUGIN", data: JSON.stringify(notes2) });
|
|
2038
|
+
if (Object.keys(validations).length) resources.push({ name: "SHEET_DATA_VALIDATION_PLUGIN", data: JSON.stringify(validations) });
|
|
2039
|
+
if (Object.keys(filters).length) resources.push({ name: "SHEET_FILTER_PLUGIN", data: JSON.stringify(filters) });
|
|
2040
|
+
const shown = entries2[active];
|
|
2041
|
+
if (shown?.sheet && book.sheetOrder.includes(`s${shown.sheetId}`)) model.active = `s${shown.sheetId}`;
|
|
2042
|
+
return { model, book: { pack, part, xml, rels, styles, stylesPart: stylesPart ?? null, sheets, entries: entries2 } };
|
|
2043
|
+
}
|
|
2044
|
+
var kinds = { whole: "whole", decimal: "decimal", list: "list", textLength: "textLength", custom: "custom" };
|
|
2045
|
+
var stops = { information: 0, stop: 1, warning: 2 };
|
|
2046
|
+
function validation(xml, uid) {
|
|
2047
|
+
const type = attr2(xml, "type") ?? "none";
|
|
2048
|
+
const kind = kinds[type];
|
|
2049
|
+
const ranges = boxes(attr2(xml, "sqref") ?? "");
|
|
2050
|
+
if (!kind || !ranges.length) return null;
|
|
2051
|
+
const f = (n) => {
|
|
2052
|
+
const m = new RegExp(`<(?:\\w+:)?formula${n}>([\\s\\S]*?)</(?:\\w+:)?formula${n}>`).exec(xml)?.[1];
|
|
2053
|
+
return m === void 0 ? void 0 : plain(unescape(m));
|
|
2054
|
+
};
|
|
2055
|
+
let formula1 = f(1), formula2 = f(2);
|
|
2056
|
+
if (kind === "list" && formula1 !== void 0) formula1 = /^".*"$/.test(formula1) ? formula1.slice(1, -1).replace(/""/g, '"') : "=" + formula1;
|
|
2057
|
+
else if (kind === "custom" && formula1 !== void 0) formula1 = "=" + formula1;
|
|
2058
|
+
else if (formula1 !== void 0 && !/^-?[\d.]+$/.test(formula1)) formula1 = "=" + formula1;
|
|
2059
|
+
if (formula2 !== void 0 && !/^-?[\d.]+$/.test(formula2)) formula2 = "=" + formula2;
|
|
2060
|
+
const flag = (name) => /^(1|true)$/.test(attr2(xml, name) ?? "");
|
|
2061
|
+
const rule = { uid, type: kind, ranges: ranges.map((b) => ({ ...b, rangeType: 0 })) };
|
|
2062
|
+
const operator = attr2(xml, "operator");
|
|
2063
|
+
if (kind !== "list" && kind !== "custom") rule.operator = operator ?? "between";
|
|
2064
|
+
if (formula1 !== void 0) rule.formula1 = formula1;
|
|
2065
|
+
if (formula2 !== void 0) rule.formula2 = formula2;
|
|
2066
|
+
if (flag("allowBlank")) rule.allowBlank = true;
|
|
2067
|
+
if (kind === "list") rule.showDropDown = !flag("showDropDown");
|
|
2068
|
+
if (flag("showErrorMessage")) rule.showErrorMessage = true;
|
|
2069
|
+
if (flag("showInputMessage")) rule.showInputMessage = true;
|
|
2070
|
+
const style = attr2(xml, "errorStyle");
|
|
2071
|
+
if (style && style in stops) rule.errorStyle = stops[style];
|
|
2072
|
+
for (const name of ["error", "errorTitle", "prompt", "promptTitle"]) if (attr2(xml, name) !== null) rule[name] = attr2(xml, name);
|
|
2073
|
+
return rule;
|
|
2074
|
+
}
|
|
2075
|
+
function criteria(xml) {
|
|
2076
|
+
const out = [];
|
|
2077
|
+
for (const m of xml.matchAll(/<(?:\w+:)?filterColumn\b[^>]*>([\s\S]*?)<\/(?:\w+:)?filterColumn>/g)) {
|
|
2078
|
+
const colId = Number(attr2(m[0], "colId") ?? 0);
|
|
2079
|
+
const inner = m[1];
|
|
2080
|
+
if (/<(?:\w+:)?filters\b/.test(inner)) {
|
|
2081
|
+
const values = [...inner.matchAll(/<(?:\w+:)?filter\b[^>]*\/?>/g)].map((f) => attr2(f[0], "val") ?? "");
|
|
2082
|
+
const blank2 = /<(?:\w+:)?filters\b[^>]*\bblank="(1|true)"/.test(inner);
|
|
2083
|
+
out.push({ colId, filters: { ...values.length && { filters: values }, ...blank2 && { blank: true } } });
|
|
2084
|
+
} else if (/<(?:\w+:)?customFilters\b/.test(inner)) {
|
|
2085
|
+
const and = /<(?:\w+:)?customFilters\b[^>]*\band="(1|true)"/.test(inner);
|
|
2086
|
+
const list = [...inner.matchAll(/<(?:\w+:)?customFilter\b[^>]*\/?>/g)].map((f) => ({ ...attr2(f[0], "operator") && { operator: attr2(f[0], "operator") }, val: attr2(f[0], "val") ?? "" }));
|
|
2087
|
+
out.push({ colId, customFilters: { ...and && { and: 1 }, customFilters: list } });
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
return out;
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
// src/sheets/write.ts
|
|
2094
|
+
var order = [
|
|
2095
|
+
"sheetPr",
|
|
2096
|
+
"dimension",
|
|
2097
|
+
"sheetViews",
|
|
2098
|
+
"sheetFormatPr",
|
|
2099
|
+
"cols",
|
|
2100
|
+
"sheetData",
|
|
2101
|
+
"sheetCalcPr",
|
|
2102
|
+
"sheetProtection",
|
|
2103
|
+
"protectedRanges",
|
|
2104
|
+
"scenarios",
|
|
2105
|
+
"autoFilter",
|
|
2106
|
+
"sortState",
|
|
2107
|
+
"dataConsolidate",
|
|
2108
|
+
"customSheetViews",
|
|
2109
|
+
"mergeCells",
|
|
2110
|
+
"phoneticPr",
|
|
2111
|
+
"conditionalFormatting",
|
|
2112
|
+
"dataValidations",
|
|
2113
|
+
"hyperlinks",
|
|
2114
|
+
"printOptions",
|
|
2115
|
+
"pageMargins",
|
|
2116
|
+
"pageSetup",
|
|
2117
|
+
"headerFooter",
|
|
2118
|
+
"rowBreaks",
|
|
2119
|
+
"colBreaks",
|
|
2120
|
+
"customProperties",
|
|
2121
|
+
"cellWatches",
|
|
2122
|
+
"ignoredErrors",
|
|
2123
|
+
"smartTags",
|
|
2124
|
+
"drawing",
|
|
2125
|
+
"legacyDrawing",
|
|
2126
|
+
"legacyDrawingHF",
|
|
2127
|
+
"drawingHF",
|
|
2128
|
+
"picture",
|
|
2129
|
+
"oleObjects",
|
|
2130
|
+
"controls",
|
|
2131
|
+
"webPublishItems",
|
|
2132
|
+
"tableParts",
|
|
2133
|
+
"extLst"
|
|
2134
|
+
];
|
|
2135
|
+
var errors = /^#(NULL!|DIV\/0!|VALUE!|REF!|NAME\?|NUM!|N\/A|GETTING_DATA|SPILL!|CALC!)$/;
|
|
2136
|
+
var REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
2137
|
+
var blankSheet = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><dimension ref="A1"/><sheetViews><sheetView workbookViewId="0"/></sheetViews><sheetFormatPr defaultRowHeight="15"/><sheetData/><pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/></worksheet>';
|
|
2138
|
+
var same = (a, b) => JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
|
|
2139
|
+
var blank = (v) => v === void 0 || v === null || v === "";
|
|
2140
|
+
var patterns2 = /* @__PURE__ */ new Map();
|
|
2141
|
+
var setAttr = (tag, name, value2) => {
|
|
2142
|
+
let re = patterns2.get(name);
|
|
2143
|
+
if (!re) patterns2.set(name, re = new RegExp(`\\s${name}="[^"]*"`));
|
|
2144
|
+
if (value2 === null) return tag.replace(re, "");
|
|
2145
|
+
if (re.test(tag)) return tag.replace(re, () => ` ${name}="${escape(value2)}"`);
|
|
2146
|
+
return tag.replace(/\s*(\/?>)$/, (end) => ` ${name}="${escape(value2)}"${end.trim()}`);
|
|
2147
|
+
};
|
|
2148
|
+
var literal = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2149
|
+
function resource(book, name) {
|
|
2150
|
+
const found = book.resources?.find((r) => r.name === name);
|
|
2151
|
+
return found ? JSON.parse(found.data || "{}") : null;
|
|
2152
|
+
}
|
|
2153
|
+
function textOf(c) {
|
|
2154
|
+
if (!c) return null;
|
|
2155
|
+
const stream = c.p?.body?.dataStream;
|
|
2156
|
+
if (stream !== void 0 && blank(c.v)) return stream.replace(/\r?\n$/, "").replace(/\r\n?/g, "\n");
|
|
2157
|
+
if (c.t === 3 && typeof c.v === "number") return c.v === 1;
|
|
2158
|
+
return c.v ?? null;
|
|
2159
|
+
}
|
|
2160
|
+
function formulas(cells) {
|
|
2161
|
+
const masters = /* @__PURE__ */ new Map();
|
|
2162
|
+
for (const [r, line] of Object.entries(cells)) for (const [c, x] of Object.entries(line ?? {})) if (x?.si && x.f) masters.set(x.si, { f: x.f, r: +r, c: +c });
|
|
2163
|
+
return (r, c, x) => {
|
|
2164
|
+
if (x.f) return x.f;
|
|
2165
|
+
if (!x.si) return null;
|
|
2166
|
+
const m = masters.get(x.si);
|
|
2167
|
+
return m ? "=" + shifted(m.f.replace(/^=/, ""), r - m.r, c - m.c) : null;
|
|
2168
|
+
};
|
|
2169
|
+
}
|
|
2170
|
+
function equalValue(a, b) {
|
|
2171
|
+
if (blank(a) && blank(b)) return true;
|
|
2172
|
+
if (typeof a === "number" && typeof b === "number") return a === b || Math.abs(a - b) <= 1e-9 * Math.max(1, Math.abs(a), Math.abs(b));
|
|
2173
|
+
return a === b;
|
|
2174
|
+
}
|
|
2175
|
+
function lookup(book, s) {
|
|
2176
|
+
if (!s) return {};
|
|
2177
|
+
return (typeof s === "string" ? book.styles[s] : s) ?? {};
|
|
2178
|
+
}
|
|
2179
|
+
var Axis = class {
|
|
2180
|
+
constructor(old, now) {
|
|
2181
|
+
this.old = old;
|
|
2182
|
+
this.now = now;
|
|
2183
|
+
this.map = (i) => i < this.old.length ? this.at.get(this.old[i]) ?? -1 : i + this.shift;
|
|
2184
|
+
this.from = (i) => i < this.now.length ? this.back.get(this.now[i]) ?? -1 : i - this.shift;
|
|
2185
|
+
this.near = (i) => {
|
|
2186
|
+
for (let j = i; j < this.old.length; j++) if (this.map(j) >= 0) return this.map(j);
|
|
2187
|
+
for (let j = i; j >= 0; j--) if (this.map(j) >= 0) return this.map(j);
|
|
2188
|
+
return 0;
|
|
2189
|
+
};
|
|
2190
|
+
this.at = new Map(now.map((id, i) => [id, i]));
|
|
2191
|
+
this.back = new Map(old.map((id, i) => [id, i]));
|
|
2192
|
+
this.moved = old.some((id, i) => this.at.get(id) !== i);
|
|
2193
|
+
const last = old.length ? this.at.get(old[old.length - 1]) : void 0;
|
|
2194
|
+
this.shift = last === void 0 ? now.length - old.length : last - (old.length - 1);
|
|
2195
|
+
}
|
|
2196
|
+
};
|
|
2197
|
+
function find(xml, name) {
|
|
2198
|
+
const m = new RegExp(`<((?:\\w+:)?${name})\\b[^>]*?(\\/?)>`).exec(xml);
|
|
2199
|
+
if (!m) return null;
|
|
2200
|
+
if (m[2]) return { start: m.index, end: m.index + m[0].length, tag: m[0] };
|
|
2201
|
+
const close = xml.indexOf(`</${m[1]}>`, m.index);
|
|
2202
|
+
return { start: m.index, end: close + m[1].length + 3, tag: m[0] };
|
|
2203
|
+
}
|
|
2204
|
+
function place(xml, name, value2) {
|
|
2205
|
+
const found = find(xml, name);
|
|
2206
|
+
if (found) return xml.slice(0, found.start) + (value2 ?? "") + xml.slice(found.end);
|
|
2207
|
+
if (value2 === null) return xml;
|
|
2208
|
+
const rank = order.indexOf(name);
|
|
2209
|
+
let at = -1;
|
|
2210
|
+
for (const later of order.slice(rank + 1)) {
|
|
2211
|
+
const f = find(xml, later);
|
|
2212
|
+
if (f && (at < 0 || f.start < at)) at = f.start;
|
|
2213
|
+
}
|
|
2214
|
+
if (at < 0) at = xml.search(/<\/(?:\w+:)?worksheet>\s*$/);
|
|
2215
|
+
if (at < 0) at = xml.length;
|
|
2216
|
+
return xml.slice(0, at) + value2 + xml.slice(at);
|
|
2217
|
+
}
|
|
2218
|
+
function remapZone(xml, mine, rows, cols) {
|
|
2219
|
+
const ranges = (sqref) => boxes(sqref).map((b) => squeeze(b, rows.map, cols.map)).filter((b) => b !== null).map(span).join(" ");
|
|
2220
|
+
const formula = (f) => remapped(f, mine, rows.map, cols.map);
|
|
2221
|
+
let out = xml.replace(/<((?:\w+:)?)(conditionalFormatting|dataValidation|hyperlink|ignoredError|protectedRange)\b[^>]*?(?:\/>|>[\s\S]*?<\/\1\2>)/g, (all) => {
|
|
2222
|
+
const sq = attr2(all, "sqref");
|
|
2223
|
+
const ref = attr2(all, "ref");
|
|
2224
|
+
let next = all;
|
|
2225
|
+
if (sq !== null) {
|
|
2226
|
+
const s = ranges(sq);
|
|
2227
|
+
if (!s) return "";
|
|
2228
|
+
next = setAttr(next.slice(0, next.indexOf(">") + 1), "sqref", s) + next.slice(next.indexOf(">") + 1);
|
|
2229
|
+
}
|
|
2230
|
+
if (ref !== null) {
|
|
2231
|
+
const s = ranges(ref);
|
|
2232
|
+
if (!s) return "";
|
|
2233
|
+
next = setAttr(next.slice(0, next.indexOf(">") + 1), "ref", s) + next.slice(next.indexOf(">") + 1);
|
|
2234
|
+
}
|
|
2235
|
+
return next.replace(/<((?:\w+:)?)(formula|formula1|formula2)>([\s\S]*?)<\/\1\2>/g, (_, p, n, f) => `<${p}${n}>${escape(formula(unescape(f)))}</${p}${n}>`);
|
|
2236
|
+
});
|
|
2237
|
+
out = out.replace(/<((?:\w+:)?)(autoFilter|sortState|sortCondition)\b[^>]*?>/g, (tag) => {
|
|
2238
|
+
const ref = attr2(tag, "ref");
|
|
2239
|
+
return ref === null ? tag : setAttr(tag, "ref", ranges(ref) || ref);
|
|
2240
|
+
});
|
|
2241
|
+
out = out.replace(/<(xm:sqref)>([\s\S]*?)<\/xm:sqref>/g, (_, n, s) => `<${n}>${ranges(s)}</${n}>`);
|
|
2242
|
+
out = out.replace(/<(xm:f)>([\s\S]*?)<\/xm:f>/g, (_, n, f) => `<${n}>${escape(formula(unescape(f)))}</${n}>`);
|
|
2243
|
+
out = out.replace(/<((?:\w+:)?)(selection|pane)\b[^>]*?>/g, (tag) => {
|
|
2244
|
+
let next = tag;
|
|
2245
|
+
for (const name of ["activeCell", "topLeftCell"]) {
|
|
2246
|
+
const v = attr2(next, name);
|
|
2247
|
+
if (v === null) continue;
|
|
2248
|
+
const [r, c] = cell(v);
|
|
2249
|
+
if (r >= 0) next = setAttr(next, name, a1(rows.near(r), cols.near(c)));
|
|
2250
|
+
}
|
|
2251
|
+
const sq = attr2(next, "sqref");
|
|
2252
|
+
return sq === null ? next : setAttr(next, "sqref", ranges(sq) || "A1");
|
|
2253
|
+
});
|
|
2254
|
+
return out;
|
|
2255
|
+
}
|
|
2256
|
+
function anchors(xml, rows, cols) {
|
|
2257
|
+
return xml.replace(/<((?:\w+:)?)(from|to)>([\s\S]*?)<\/\1\2>/g, (all, p, n, inner) => {
|
|
2258
|
+
const next = inner.replace(/<((?:\w+:)?)col>(\d+)<\/\1col>/, (_, q, v) => `<${q}col>${cols.near(Number(v))}</${q}col>`).replace(/<((?:\w+:)?)row>(\d+)<\/\1row>/, (_, q, v) => `<${q}row>${rows.near(Number(v))}</${q}row>`);
|
|
2259
|
+
return `<${p}${n}>${next}</${p}${n}>`;
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2262
|
+
function writeXlsx(original, model) {
|
|
2263
|
+
const { model: base, book } = load(original);
|
|
2264
|
+
const { pack, styles } = book;
|
|
2265
|
+
const cur = model.book;
|
|
2266
|
+
const defaults = norm(styles.looks[0] ?? {});
|
|
2267
|
+
const bySheetId = new Map(book.sheets.map((s) => [s.sheetId, s]));
|
|
2268
|
+
const kept = new Set(cur.sheetOrder.map((sid) => model.origin.sheets[sid]).filter((id) => bySheetId.has(id)));
|
|
2269
|
+
const removed = book.sheets.filter((s) => !kept.has(s.sheetId));
|
|
2270
|
+
const charts = [...pack.names.keys()].filter((n) => /^xl\/charts\/chart[^/]*\.xml$/.test(n));
|
|
2271
|
+
const caches = book.rels.filter((r) => r.type === "pivotCacheDefinition").map((r) => r.target);
|
|
2272
|
+
for (const gone of removed) {
|
|
2273
|
+
const pattern = new RegExp(`(^|[^\\w.])(${literal(gone.name)}|'${literal(gone.name.replace(/'/g, "''"))}')!`);
|
|
2274
|
+
const own = new Set(gone.rels.filter((r) => r.type === "drawing").flatMap((r) => pack.rels(r.target)).filter((r) => r.type === "chart").map((r) => r.target));
|
|
2275
|
+
if (charts.some((c) => !own.has(c) && [...(pack.text(c) ?? "").matchAll(/<(?:\w+:)?f>([\s\S]*?)<\/(?:\w+:)?f>/g)].some((m) => pattern.test(unescape(m[1]))))) throw new SheetRefusal("chartSource", gone.name);
|
|
2276
|
+
if (caches.some((c) => new RegExp(`<(?:\\w+:)?worksheetSource\\b[^>]*\\bsheet="${literal(escape(gone.name))}"`).test(pack.text(c) ?? ""))) throw new SheetRefusal("pivotSheet", gone.name);
|
|
2277
|
+
}
|
|
2278
|
+
const names = /* @__PURE__ */ new Map();
|
|
2279
|
+
const axes = /* @__PURE__ */ new Map();
|
|
2280
|
+
let touched = false;
|
|
2281
|
+
const sheetParts = [];
|
|
2282
|
+
let nextSheetId = Math.max(0, ...book.entries.map((e) => e.sheetId)) + 1;
|
|
2283
|
+
let nextRid = Math.max(0, ...book.rels.map((r) => Number(/\d+$/.exec(r.id)?.[0] ?? 0))) + 1;
|
|
2284
|
+
const used = new Set(pack.names.keys());
|
|
2285
|
+
const fresh2 = (pattern) => {
|
|
2286
|
+
let n = 1;
|
|
2287
|
+
while (used.has(pattern(n)) || pack.changed.has(pattern(n))) n++;
|
|
2288
|
+
used.add(pattern(n));
|
|
2289
|
+
return pattern(n);
|
|
2290
|
+
};
|
|
2291
|
+
const types = [];
|
|
2292
|
+
const defaultsNeeded = /* @__PURE__ */ new Set();
|
|
2293
|
+
for (const sid of cur.sheetOrder) {
|
|
2294
|
+
const id = model.origin.sheets[sid];
|
|
2295
|
+
const rec = id !== void 0 ? bySheetId.get(id) ?? null : null;
|
|
2296
|
+
if (rec && [...axes.values()].every((a) => a.rec !== rec)) {
|
|
2297
|
+
const lines2 = model.lines[sid], old = model.origin.lines[sid] ?? base.lines[rec.sid];
|
|
2298
|
+
axes.set(sid, { rows: new Axis(old.rows, lines2.rows), cols: new Axis(old.cols, lines2.cols), rec });
|
|
2299
|
+
sheetParts.push({ sid, rec, part: rec.part, rid: book.entries.find((e) => e.sheetId === rec.sheetId).rid, sheetId: rec.sheetId });
|
|
2300
|
+
if (cur.sheets[sid].name !== rec.name) names.set(rec.name, cur.sheets[sid].name);
|
|
2301
|
+
} else {
|
|
2302
|
+
const part = fresh2((n) => `xl/worksheets/sheet${n}.xml`);
|
|
2303
|
+
sheetParts.push({ sid, rec: null, part, rid: `rId${nextRid++}`, sheetId: nextSheetId++ });
|
|
2304
|
+
types.push([`/${part}`, "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"]);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
const curNotes = resource(cur, "SHEET_NOTE_PLUGIN");
|
|
2308
|
+
const curRules = resource(cur, "SHEET_DATA_VALIDATION_PLUGIN");
|
|
2309
|
+
const curFilters = resource(cur, "SHEET_FILTER_PLUGIN");
|
|
2310
|
+
const baseRules = resource(base.book, "SHEET_DATA_VALIDATION_PLUGIN") ?? {};
|
|
2311
|
+
const baseFilters = resource(base.book, "SHEET_FILTER_PLUGIN") ?? {};
|
|
2312
|
+
const filterNames = /* @__PURE__ */ new Map();
|
|
2313
|
+
for (const entry2 of sheetParts) {
|
|
2314
|
+
const { sid, rec } = entry2;
|
|
2315
|
+
const sheet = cur.sheets[sid];
|
|
2316
|
+
const ax = axes.get(sid);
|
|
2317
|
+
const rows = ax?.rows ?? new Axis([], model.lines[sid]?.rows ?? []);
|
|
2318
|
+
const cols = ax?.cols ?? new Axis([], model.lines[sid]?.cols ?? []);
|
|
2319
|
+
const old = rec ? base.book.sheets[rec.sid] : {};
|
|
2320
|
+
const xml = rec?.xml ?? blankSheet;
|
|
2321
|
+
const p = rec?.p ?? "";
|
|
2322
|
+
const cells = sheet.cellData ?? {};
|
|
2323
|
+
const oldCells = old.cellData ?? {};
|
|
2324
|
+
const fOf = formulas(cells);
|
|
2325
|
+
const rowStyle = (sh, r) => sh.rowData?.[r]?.s;
|
|
2326
|
+
const colStyle = (sh, c) => sh.columnData?.[c]?.s;
|
|
2327
|
+
const seen2 = /* @__PURE__ */ new Map();
|
|
2328
|
+
const looks = (bk, sh, r, c, x) => {
|
|
2329
|
+
const s = x?.s ?? colStyle(sh, c) ?? rowStyle(sh, r);
|
|
2330
|
+
const id = typeof s === "string" ? (bk === cur ? "c" : "b") + s : "";
|
|
2331
|
+
const known = id && seen2.get(id);
|
|
2332
|
+
if (known) return known;
|
|
2333
|
+
const look = norm({ ...defaults, ...lookup(bk, s) });
|
|
2334
|
+
const made2 = { look, json: JSON.stringify(look) };
|
|
2335
|
+
if (id) seen2.set(id, made2);
|
|
2336
|
+
return made2;
|
|
2337
|
+
};
|
|
2338
|
+
const xfOf = (s) => typeof s === "string" && /^x\d+$/.test(s) ? Number(s.slice(1)) : 0;
|
|
2339
|
+
const xfFor = (look, was) => {
|
|
2340
|
+
if (same(norm(styles.looks[was] ?? {}), look) || was === 0 && same(defaults, look)) return was;
|
|
2341
|
+
return styles.find(look) ?? styles.derive(was, look);
|
|
2342
|
+
};
|
|
2343
|
+
let changed2 = !rec || rows.moved || cols.moved;
|
|
2344
|
+
let reused = 0, total = 0;
|
|
2345
|
+
for (const [r, line] of Object.entries(oldCells)) for (const c of Object.keys(line ?? {})) if (rows.map(+r) >= 0 && cols.map(+c) >= 0) total++;
|
|
2346
|
+
const body = [];
|
|
2347
|
+
const filtered = new Set(curFilters?.[sid]?.cachedFilteredOut ?? []);
|
|
2348
|
+
const indices = /* @__PURE__ */ new Set();
|
|
2349
|
+
for (const [r, line] of Object.entries(cells)) if (line && Object.keys(line).length) indices.add(+r);
|
|
2350
|
+
for (const [r, rd] of Object.entries(sheet.rowData ?? {})) if (rd && (rd.h !== void 0 || rd.hd || rd.s)) indices.add(+r);
|
|
2351
|
+
if (rec) for (const r0 of rec.rows.keys()) {
|
|
2352
|
+
const r = rows.map(r0);
|
|
2353
|
+
if (r >= 0) indices.add(r);
|
|
2354
|
+
}
|
|
2355
|
+
for (const r of filtered) indices.add(r);
|
|
2356
|
+
let minR = Infinity, minC = Infinity, maxR = -1, maxC = -1;
|
|
2357
|
+
for (const r of [...indices].sort((a, b) => a - b)) {
|
|
2358
|
+
const r0 = rows.from(r);
|
|
2359
|
+
const orow = r0 >= 0 ? rec?.rows.get(r0) : void 0;
|
|
2360
|
+
const rd = sheet.rowData?.[r] ?? {};
|
|
2361
|
+
const od = r0 >= 0 ? old.rowData?.[r0] ?? {} : {};
|
|
2362
|
+
let tag = orow ? orow.open.replace(/\s*\/>$/, ">") : `<${p}row>`;
|
|
2363
|
+
tag = setAttr(tag, "r", String(r + 1));
|
|
2364
|
+
if (orow && (rows.moved || cols.moved)) tag = setAttr(tag, "spans", null);
|
|
2365
|
+
if (Math.abs((rd.h ?? -1) - (od.h ?? -1)) > 0.5) {
|
|
2366
|
+
changed2 = true;
|
|
2367
|
+
tag = setAttr(setAttr(tag, "ht", rd.h === void 0 ? null : String(pt.row(rd.h))), "customHeight", rd.h === void 0 ? null : "1");
|
|
2368
|
+
}
|
|
2369
|
+
const hidden = !!rd.hd || filtered.has(r);
|
|
2370
|
+
if (hidden !== !!od.hd) {
|
|
2371
|
+
changed2 = true;
|
|
2372
|
+
tag = setAttr(tag, "hidden", hidden ? "1" : null);
|
|
2373
|
+
}
|
|
2374
|
+
const look = rd.s ? norm({ ...defaults, ...lookup(cur, rd.s) }) : null;
|
|
2375
|
+
const was = od.s ? norm({ ...defaults, ...lookup(base.book, od.s) }) : null;
|
|
2376
|
+
if (!same(look, was)) {
|
|
2377
|
+
changed2 = true;
|
|
2378
|
+
tag = setAttr(setAttr(tag, "s", look ? String(xfFor(look, xfOf(od.s))) : null), "customFormat", look ? "1" : null);
|
|
2379
|
+
}
|
|
2380
|
+
const line = cells[r] ?? {};
|
|
2381
|
+
const parts2 = [];
|
|
2382
|
+
for (const c of Object.keys(line).map(Number).sort((a, b) => a - b)) {
|
|
2383
|
+
const x = line[c];
|
|
2384
|
+
if (!x) continue;
|
|
2385
|
+
const c0 = cols.from(c);
|
|
2386
|
+
const ox = r0 >= 0 && c0 >= 0 ? oldCells[r0]?.[c0] : void 0;
|
|
2387
|
+
const f = fOf(r, c, x);
|
|
2388
|
+
const v = textOf(x);
|
|
2389
|
+
const look2 = looks(cur, sheet, r, c, x);
|
|
2390
|
+
const orec = r0 >= 0 && c0 >= 0 ? rec?.cells.get(key(r0, c0)) : void 0;
|
|
2391
|
+
const unchanged = !!ox && (ox.f ?? null) === f && equalValue(textOf(ox), v) && looks(base.book, old, r0, c0, ox).json === look2.json;
|
|
2392
|
+
if (unchanged) reused++;
|
|
2393
|
+
if (blank(v) && !f && !x.s) continue;
|
|
2394
|
+
if (unchanged && orec && !orec.shared) {
|
|
2395
|
+
const raw = xml.slice(orec.start, orec.end);
|
|
2396
|
+
parts2.push(rows.moved || cols.moved ? raw.replace(/^<[^>]*>/, (t) => setAttr(t, "r", a1(r, c))) : raw);
|
|
2397
|
+
} else {
|
|
2398
|
+
if (!unchanged) changed2 = true;
|
|
2399
|
+
const xf = xfFor(look2.look, xfOf(ox?.s ?? colStyle(sheet, c) ?? rowStyle(sheet, r)));
|
|
2400
|
+
const out = cellXml(p, a1(r, c), xf, x, f, v);
|
|
2401
|
+
if (!out) continue;
|
|
2402
|
+
parts2.push(out);
|
|
2403
|
+
}
|
|
2404
|
+
minR = Math.min(minR, r);
|
|
2405
|
+
maxR = Math.max(maxR, r);
|
|
2406
|
+
minC = Math.min(minC, c);
|
|
2407
|
+
maxC = Math.max(maxC, c);
|
|
2408
|
+
}
|
|
2409
|
+
if (!parts2.length && !orow && !rd.h && !hidden && !look) continue;
|
|
2410
|
+
body.push(parts2.length ? `${tag}${parts2.join("")}</${p}row>` : tag.replace(/>$/, "/>"));
|
|
2411
|
+
}
|
|
2412
|
+
if (rec && reused !== total) changed2 = true;
|
|
2413
|
+
let head = xml.slice(0, rec ? rec.bounds[0] : xml.indexOf("<sheetData"));
|
|
2414
|
+
let tail = xml.slice(rec ? rec.bounds[3] : xml.indexOf("<sheetData/>") + 12);
|
|
2415
|
+
const mine = (s) => s === null || s === rec?.name;
|
|
2416
|
+
if (rec && (rows.moved || cols.moved)) {
|
|
2417
|
+
head = remapZone(head, mine, rows, cols);
|
|
2418
|
+
tail = remapZone(tail, mine, rows, cols);
|
|
2419
|
+
}
|
|
2420
|
+
const colXml = columns(p, rec, sheet, old, cols, defaults, cur, base.book, xfFor, xfOf);
|
|
2421
|
+
if (colXml !== void 0) {
|
|
2422
|
+
changed2 = true;
|
|
2423
|
+
head = place(head, "cols", colXml);
|
|
2424
|
+
}
|
|
2425
|
+
const merges = (sheet.mergeData ?? []).map((m) => span(m)).sort();
|
|
2426
|
+
const oldMerges = [...rec?.merges ?? []].map((m) => span(box(m))).sort();
|
|
2427
|
+
if (!same(merges, oldMerges)) {
|
|
2428
|
+
changed2 = true;
|
|
2429
|
+
tail = place(tail, "mergeCells", merges.length ? `<${p}mergeCells count="${merges.length}">${merges.map((m) => `<${p}mergeCell ref="${m}"/>`).join("")}</${p}mergeCells>` : null);
|
|
2430
|
+
}
|
|
2431
|
+
const freeze = sheet.freeze && (sheet.freeze.xSplit > 0 || sheet.freeze.ySplit > 0) ? [sheet.freeze.xSplit, sheet.freeze.ySplit] : [0, 0];
|
|
2432
|
+
const oldFreeze = old.freeze ? [old.freeze.xSplit, old.freeze.ySplit] : [0, 0];
|
|
2433
|
+
if (!same(freeze, oldFreeze)) {
|
|
2434
|
+
changed2 = true;
|
|
2435
|
+
head = frozen(head, p, freeze[0], freeze[1]);
|
|
2436
|
+
}
|
|
2437
|
+
if ((sheet.showGridlines ?? 1) !== (old.showGridlines ?? 1)) {
|
|
2438
|
+
changed2 = true;
|
|
2439
|
+
head = head.replace(/<(?:\w+:)?sheetView\b[^>]*?>/, (t) => setAttr(t, "showGridLines", sheet.showGridlines === 0 ? "0" : null));
|
|
2440
|
+
}
|
|
2441
|
+
if ((sheet.tabColor ?? "") !== (old.tabColor ?? "")) {
|
|
2442
|
+
changed2 = true;
|
|
2443
|
+
head = tabColour(head, p, sheet.tabColor ?? "");
|
|
2444
|
+
}
|
|
2445
|
+
const rules = (curRules ? curRules[sid] ?? [] : rec ? baseRules[rec.sid] ?? [] : []).map((r) => ({ ...r, ranges: r.ranges.map((b) => ({ startRow: b.startRow, startColumn: b.startColumn, endRow: b.endRow, endColumn: b.endColumn })) }));
|
|
2446
|
+
const oldRules = (rec ? baseRules[rec.sid] ?? [] : []).map((r) => ({ ...r, ranges: r.ranges.map((b) => squeeze(b, rows.map, cols.map)).filter(Boolean) }));
|
|
2447
|
+
if (curRules && !same(rules.map(canonRule), oldRules.map(canonRule))) {
|
|
2448
|
+
changed2 = true;
|
|
2449
|
+
const known = new Map((rec?.validations ?? []).map((v, i) => [`dv${i}`, v]));
|
|
2450
|
+
const shown = new Set(rules.map((r) => r.uid));
|
|
2451
|
+
const hiddenRules = [...known].filter(([uid, v]) => !shown.has(uid) && !(rec && baseRules[rec.sid]?.some((r) => r.uid === uid)) && v).map(([, v]) => rows.moved || cols.moved ? remapZone(v, mine, rows, cols) : v);
|
|
2452
|
+
const list = [...hiddenRules, ...rules.map((r) => validationXml(p, r, known.get(r.uid)))].filter(Boolean);
|
|
2453
|
+
tail = place(tail, "dataValidations", list.length ? `<${p}dataValidations count="${list.length}">${list.join("")}</${p}dataValidations>` : null);
|
|
2454
|
+
}
|
|
2455
|
+
const oldFilter = rec ? baseFilters[rec.sid] ?? null : null;
|
|
2456
|
+
const filter = curFilters ? curFilters[sid] ?? null : oldFilter;
|
|
2457
|
+
const fref = filter?.ref ? span(filter.ref) : null;
|
|
2458
|
+
const oref = oldFilter?.ref ? (() => {
|
|
2459
|
+
const b = squeeze(oldFilter.ref, rows.map, cols.map);
|
|
2460
|
+
return b && span(b);
|
|
2461
|
+
})() : null;
|
|
2462
|
+
if (curFilters && (fref !== oref || !same(filter?.filterColumns ?? [], oldFilter?.filterColumns ?? []))) {
|
|
2463
|
+
changed2 = true;
|
|
2464
|
+
tail = place(tail, "autoFilter", filter?.ref ? filterXml(p, filter.ref, filter.filterColumns ?? []) : null);
|
|
2465
|
+
filterNames.set(entry2.sheetId, filter?.ref ? `${quoted(sheet.name)}!${span(filter.ref).split(":").map((s) => s.replace(/([A-Z]+)(\d+)/, "$$$1$$$2")).join(":")}` : null);
|
|
2466
|
+
}
|
|
2467
|
+
const notes2 = Object.values(curNotes?.[sid] ?? {}).flatMap((line) => Object.values(line ?? {})).filter((n) => n && !blank(n.note));
|
|
2468
|
+
const oldNotes = (rec?.notes ?? []).map((n) => ({ ref: n.ref, text: n.text }));
|
|
2469
|
+
const nowNotes = notes2.map((n) => ({ ref: a1(n.row, n.col), text: n.note })).sort((a, b) => a.ref.localeCompare(b.ref));
|
|
2470
|
+
if (curNotes && !same(nowNotes, [...oldNotes].sort((a, b) => a.ref.localeCompare(b.ref)))) {
|
|
2471
|
+
changed2 = true;
|
|
2472
|
+
tail = writeNotes(book, entry2, tail, p, notes2, rows, cols, types, defaultsNeeded, fresh2);
|
|
2473
|
+
}
|
|
2474
|
+
const rename = (s) => names.size ? s.replace(/<(xm:f|(?:\w+:)?formula\d?)>([\s\S]*?)<\/\1>/g, (_, n, f) => `<${n}>${escape([...names].reduce((g, [from, to]) => renamed(g, from, to), unescape(f)))}</${n}>`) : s;
|
|
2475
|
+
if (!changed2) {
|
|
2476
|
+
if (rec && rename(xml) !== xml) pack.put(entry2.part, rename(xml));
|
|
2477
|
+
continue;
|
|
2478
|
+
}
|
|
2479
|
+
touched = true;
|
|
2480
|
+
head = rename(head);
|
|
2481
|
+
tail = rename(tail);
|
|
2482
|
+
if (/\sr:id="/.test(tail) && !/xmlns:r=/.test(head)) head = head.replace(/<((?:\w+:)?worksheet)\b/, `<$1 xmlns:r="${REL}"`);
|
|
2483
|
+
const dim = maxR < 0 ? "A1" : span({ startRow: minR, startColumn: minC, endRow: maxR, endColumn: maxC });
|
|
2484
|
+
head = /<(?:\w+:)?dimension\b/.test(head) ? head.replace(/<((?:\w+:)?)dimension\b[^>]*\/?>/, `<$1dimension ref="${dim}"/>`) : place(head, "dimension", `<${p}dimension ref="${dim}"/>`);
|
|
2485
|
+
pack.put(entry2.part, head + (body.length ? `<${p}sheetData>${body.join("")}</${p}sheetData>` : `<${p}sheetData/>`) + tail);
|
|
2486
|
+
if (rec && (rows.moved || cols.moved)) {
|
|
2487
|
+
for (const rel of rec.rels) {
|
|
2488
|
+
if (rel.external) continue;
|
|
2489
|
+
if (rel.type === "drawing") {
|
|
2490
|
+
const d = pack.text(rel.target);
|
|
2491
|
+
if (d) pack.put(rel.target, anchors(d, rows, cols));
|
|
2492
|
+
}
|
|
2493
|
+
if (rel.type === "table") {
|
|
2494
|
+
const t = pack.text(rel.target);
|
|
2495
|
+
if (!t) continue;
|
|
2496
|
+
const ref = attr2(/<(?:\w+:)?table\b[^>]*>/.exec(t)?.[0] ?? "", "ref");
|
|
2497
|
+
const b = ref && box(ref);
|
|
2498
|
+
const moved = b && squeeze(b, rows.map, cols.map);
|
|
2499
|
+
if (b && moved && moved.endColumn - moved.startColumn !== b.endColumn - b.startColumn) throw new SheetRefusal("tableColumns", rec.name);
|
|
2500
|
+
if (moved) pack.put(rel.target, t.replace(/(<(?:\w+:)?(?:table|autoFilter)\b[^>]*?\sref=")([^"]*)"/g, (_, a, r) => `${a}${span(squeeze(box(r), rows.map, cols.map) ?? box(r))}"`));
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
const sheetStyles = styles.build();
|
|
2506
|
+
if (sheetStyles) {
|
|
2507
|
+
const target = book.stylesPart ?? "xl/styles.xml";
|
|
2508
|
+
pack.put(target, sheetStyles);
|
|
2509
|
+
if (!book.stylesPart) {
|
|
2510
|
+
types.push([`/${target}`, "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"]);
|
|
2511
|
+
pack.put(relsOf(book.part), (pack.text(relsOf(book.part)) ?? "").replace(/<\/(?:\w+:)?Relationships>/, (end) => `<Relationship Id="rId${nextRid++}" Type="${REL}/styles" Target="${relative(book.part, target)}"/>${end}`));
|
|
2512
|
+
}
|
|
2513
|
+
touched = true;
|
|
2514
|
+
}
|
|
2515
|
+
for (const [sid, ax] of axes) {
|
|
2516
|
+
if (!ax.rows.moved && !ax.cols.moved) continue;
|
|
2517
|
+
const name = ax.rec.name;
|
|
2518
|
+
const mine = (s) => s === name;
|
|
2519
|
+
for (const c of charts) {
|
|
2520
|
+
const t = pack.text(c);
|
|
2521
|
+
if (t && t.includes(name)) pack.put(c, t.replace(/<((?:\w+:)?)f>([\s\S]*?)<\/\1f>/g, (_, p, f) => `<${p}f>${escape(remapped(unescape(f), mine, ax.rows.map, ax.cols.map))}</${p}f>`));
|
|
2522
|
+
}
|
|
2523
|
+
for (const c of caches) {
|
|
2524
|
+
const t = pack.text(c);
|
|
2525
|
+
if (t) pack.put(c, t.replace(/<(?:\w+:)?worksheetSource\b[^>]*>/g, (tag) => attr2(tag, "sheet") === name && attr2(tag, "ref") ? setAttr(tag, "ref", span(squeeze(box(attr2(tag, "ref")), ax.rows.map, ax.cols.map) ?? box(attr2(tag, "ref")))) : tag));
|
|
2526
|
+
}
|
|
2527
|
+
for (const other of sheetParts) {
|
|
2528
|
+
if (other.sid === sid || !other.rec) continue;
|
|
2529
|
+
const t = pack.text(other.part);
|
|
2530
|
+
if (t && t.includes(name)) pack.put(other.part, t.replace(/<(xm:f|(?:\w+:)?formula\d?)>([\s\S]*?)<\/\1>/g, (_, n, f) => `<${n}>${escape(remapped(unescape(f), mine, ax.rows.map, ax.cols.map))}</${n}>`));
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
for (const [from, to] of names) {
|
|
2534
|
+
for (const c of charts) {
|
|
2535
|
+
const t = pack.text(c);
|
|
2536
|
+
if (t && t.includes(from)) pack.put(c, t.replace(/<((?:\w+:)?)f>([\s\S]*?)<\/\1f>/g, (_, p, f) => `<${p}f>${escape(renamed(unescape(f), from, to))}</${p}f>`));
|
|
2537
|
+
}
|
|
2538
|
+
for (const c of caches) {
|
|
2539
|
+
const t = pack.text(c);
|
|
2540
|
+
if (t) pack.put(c, t.replace(/(<(?:\w+:)?worksheetSource\b[^>]*\ssheet=")([^"]*)"/g, (all, a, s) => unescape(s) === from ? `${a}${escape(to)}"` : all));
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
const sheetsChanged = removed.length > 0 || names.size > 0 || sheetParts.some((s) => !s.rec) || sheetParts.map((s) => s.sheetId).join() !== book.entries.filter((e) => e.sheet && kept.has(e.sheetId)).map((e) => e.sheetId).join() || cur.sheetOrder.some((sid) => {
|
|
2544
|
+
const rec = axes.get(sid)?.rec;
|
|
2545
|
+
return !!rec && (cur.sheets[sid].hidden ?? 0) !== (base.book.sheets[rec.sid].hidden ?? 0);
|
|
2546
|
+
});
|
|
2547
|
+
if (!touched && !sheetsChanged && !filterNames.size) return original;
|
|
2548
|
+
let wb = book.xml;
|
|
2549
|
+
const listed = [];
|
|
2550
|
+
const nonSheets = book.entries.map((e, i) => ({ e, i })).filter((x) => !x.e.sheet);
|
|
2551
|
+
const indexOf = new Map(book.entries.map((e, i) => [e.sheetId, i]));
|
|
2552
|
+
const wp = /<(\w+:)?workbook\b/.exec(wb)?.[1] ?? "";
|
|
2553
|
+
const relPrefix = /xmlns:(\w+)="http:\/\/schemas\.openxmlformats\.org\/officeDocument\/2006\/relationships"/.exec(wb)?.[1] ?? "r";
|
|
2554
|
+
for (const s of sheetParts) {
|
|
2555
|
+
const sheet = cur.sheets[s.sid];
|
|
2556
|
+
const state = sheet.hidden === 2 ? "veryHidden" : sheet.hidden ? "hidden" : null;
|
|
2557
|
+
let tag = s.rec ? book.entries.find((e) => e.sheetId === s.sheetId).xml : `<${wp}sheet name="" sheetId="${s.sheetId}" ${relPrefix}:id="${s.rid}"/>`;
|
|
2558
|
+
tag = setAttr(setAttr(tag, "name", sheet.name ?? `Sheet${s.sheetId}`), "state", state);
|
|
2559
|
+
listed.push({ xml: tag, sheetId: s.sheetId, oldIndex: s.rec ? indexOf.get(s.sheetId) : -1 });
|
|
2560
|
+
}
|
|
2561
|
+
for (const { e, i } of nonSheets) {
|
|
2562
|
+
let at = listed.findIndex((x) => x.oldIndex > i);
|
|
2563
|
+
if (at < 0) at = listed.length;
|
|
2564
|
+
listed.splice(at, 0, { xml: e.xml, sheetId: e.sheetId, oldIndex: i });
|
|
2565
|
+
}
|
|
2566
|
+
wb = wb.replace(/(<(?:\w+:)?sheets\b[^>]*>)[\s\S]*?(<\/(?:\w+:)?sheets>)/, (_, a, b) => a + listed.map((x) => x.xml).join("") + b);
|
|
2567
|
+
const newIndex = new Map(listed.map((x, i) => [x.oldIndex, i]));
|
|
2568
|
+
const sheetIndex = new Map(listed.map((x, i) => [x.sheetId, i]));
|
|
2569
|
+
const removedNames = new Set(removed.map((r) => r.name));
|
|
2570
|
+
wb = wb.replace(/<((?:\w+:)?)definedName\b([^>]*)>([\s\S]*?)<\/\1definedName>/g, (all, p, attrs0, body) => {
|
|
2571
|
+
let tag = `<${p}definedName${attrs0}>`;
|
|
2572
|
+
const local = attr2(tag, "localSheetId");
|
|
2573
|
+
if (local !== null) {
|
|
2574
|
+
const next = newIndex.get(Number(local));
|
|
2575
|
+
if (next === void 0) return "";
|
|
2576
|
+
tag = setAttr(tag, "localSheetId", String(next));
|
|
2577
|
+
const owner = listed[next];
|
|
2578
|
+
if (attr2(tag, "name") === "_xlnm._FilterDatabase" && filterNames.has(owner.sheetId)) {
|
|
2579
|
+
const f2 = filterNames.get(owner.sheetId);
|
|
2580
|
+
filterNames.delete(owner.sheetId);
|
|
2581
|
+
return f2 ? `${tag}${escape(f2)}</${p}definedName>` : "";
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
let f = unescape(body);
|
|
2585
|
+
for (const gone of removedNames) f = f.replace(new RegExp(`(?:'${literal(gone.replace(/'/g, "''"))}'|${literal(gone)})![$A-Z0-9:]+`, "g"), "#REF!");
|
|
2586
|
+
for (const [, ax] of axes) if (ax.rows.moved || ax.cols.moved) f = remapped(f, (s) => s === ax.rec.name, ax.rows.map, ax.cols.map);
|
|
2587
|
+
for (const [from, to] of names) f = renamed(f, from, to);
|
|
2588
|
+
return `${tag}${escape(f)}</${p}definedName>`;
|
|
2589
|
+
});
|
|
2590
|
+
for (const [sheetId, f] of filterNames) {
|
|
2591
|
+
if (!f) continue;
|
|
2592
|
+
const def = `<${wp}definedName name="_xlnm._FilterDatabase" localSheetId="${sheetIndex.get(sheetId)}" hidden="1">${escape(f)}</${wp}definedName>`;
|
|
2593
|
+
wb = /<(?:\w+:)?definedNames\b/.test(wb) ? wb.replace(/<\/(?:\w+:)?definedNames>/, (end) => def + end) : wb.replace(/<\/(?:\w+:)?sheets>/, (end) => `${end}<${wp}definedNames>${def}</${wp}definedNames>`);
|
|
2594
|
+
}
|
|
2595
|
+
wb = wb.replace(/<((?:\w+:)?)definedNames>\s*<\/\1definedNames>/, "");
|
|
2596
|
+
wb = wb.replace(/<(?:\w+:)?workbookView\b[^>]*>/g, (tag) => {
|
|
2597
|
+
const total = listed.length;
|
|
2598
|
+
let next = tag;
|
|
2599
|
+
const tab = attr2(next, "activeTab");
|
|
2600
|
+
if (tab !== null) next = setAttr(next, "activeTab", String(Math.min(newIndex.get(Number(tab)) ?? 0, total - 1)));
|
|
2601
|
+
const first = attr2(next, "firstSheet");
|
|
2602
|
+
if (first !== null) next = setAttr(next, "firstSheet", String(Math.min(newIndex.get(Number(first)) ?? 0, total - 1)));
|
|
2603
|
+
return next;
|
|
2604
|
+
});
|
|
2605
|
+
if (touched) {
|
|
2606
|
+
wb = /<(?:\w+:)?calcPr\b/.test(wb) ? wb.replace(/<(?:\w+:)?calcPr\b[^>]*?\/?>/, (tag) => setAttr(tag, "fullCalcOnLoad", "1")) : wb.replace(/(<\/(?:\w+:)?sheets>(?:\s*<(?:\w+:)?(?:functionGroups|externalReferences|definedNames)\b[\s\S]*?<\/(?:\w+:)?(?:functionGroups|externalReferences|definedNames)>)*)/, `$1<${wp}calcPr fullCalcOnLoad="1"/>`);
|
|
2607
|
+
}
|
|
2608
|
+
pack.put(book.part, wb);
|
|
2609
|
+
let rels = pack.text(relsOf(book.part)) ?? "";
|
|
2610
|
+
for (const gone of removed) {
|
|
2611
|
+
const entry2 = book.entries.find((e) => e.sheetId === gone.sheetId);
|
|
2612
|
+
rels = rels.replace(new RegExp(`<(?:\\w+:)?Relationship\\b[^>]*\\bId="${entry2.rid}"[^>]*\\/>`), "");
|
|
2613
|
+
pack.put(gone.part, null);
|
|
2614
|
+
pack.put(relsOf(gone.part), null);
|
|
2615
|
+
types.push([`/${gone.part}`, null]);
|
|
2616
|
+
}
|
|
2617
|
+
const calc = book.rels.find((r) => r.type === "calcChain");
|
|
2618
|
+
if (calc && touched) {
|
|
2619
|
+
rels = rels.replace(new RegExp(`<(?:\\w+:)?Relationship\\b[^>]*\\bId="${calc.id}"[^>]*\\/>`), "");
|
|
2620
|
+
pack.put(calc.target, null);
|
|
2621
|
+
types.push([`/${calc.target}`, null]);
|
|
2622
|
+
}
|
|
2623
|
+
for (const s of sheetParts) if (!s.rec) rels = rels.replace(/<\/(?:\w+:)?Relationships>/, (end) => `<Relationship Id="${s.rid}" Type="${REL}/worksheet" Target="${relative(book.part, s.part)}"/>${end}`);
|
|
2624
|
+
pack.put(relsOf(book.part), rels);
|
|
2625
|
+
contentTypes(pack, types, defaultsNeeded);
|
|
2626
|
+
return copy(pack.build());
|
|
2627
|
+
}
|
|
2628
|
+
var copy = (u) => u.buffer.slice(u.byteOffset, u.byteOffset + u.byteLength);
|
|
2629
|
+
function contentTypes(pack, types, defaults) {
|
|
2630
|
+
if (!types.length && !defaults.size) return;
|
|
2631
|
+
let ct = pack.text("[Content_Types].xml") ?? "";
|
|
2632
|
+
for (const [name, type] of types) {
|
|
2633
|
+
ct = ct.replace(new RegExp(`<Override\\b[^>]*PartName="${literal(name)}"[^>]*\\/>`), "");
|
|
2634
|
+
if (type) ct = ct.replace("</Types>", () => `<Override PartName="${name}" ContentType="${type}"/></Types>`);
|
|
2635
|
+
}
|
|
2636
|
+
for (const ext of defaults) if (!new RegExp(`Extension="${ext}"`, "i").test(ct)) ct = ct.replace(/(<Types\b[^>]*>)/, `$1<Default Extension="${ext}" ContentType="application/vnd.openxmlformats-officedocument.vmlDrawing"/>`);
|
|
2637
|
+
pack.put("[Content_Types].xml", ct);
|
|
2638
|
+
}
|
|
2639
|
+
function cellXml(p, ref, xf, x, f, v) {
|
|
2640
|
+
const s = xf ? ` s="${xf}"` : "";
|
|
2641
|
+
if (f) {
|
|
2642
|
+
const body = escape(stored(f.replace(/^=/, "")));
|
|
2643
|
+
let t = "", val = "";
|
|
2644
|
+
if (typeof v === "number" && Number.isFinite(v)) val = `<${p}v>${v}</${p}v>`;
|
|
2645
|
+
else if (typeof v === "boolean" || x.t === 3) {
|
|
2646
|
+
t = ' t="b"';
|
|
2647
|
+
val = `<${p}v>${v === true || v === 1 ? 1 : 0}</${p}v>`;
|
|
2648
|
+
} else if (typeof v === "string" && v !== "") {
|
|
2649
|
+
t = errors.test(v) ? ' t="e"' : ' t="str"';
|
|
2650
|
+
val = `<${p}v>${escape(v)}</${p}v>`;
|
|
2651
|
+
}
|
|
2652
|
+
return `<${p}c r="${ref}"${s}${t}><${p}f>${body}</${p}f>${val}</${p}c>`;
|
|
2653
|
+
}
|
|
2654
|
+
if (blank(v)) return xf ? `<${p}c r="${ref}"${s}/>` : "";
|
|
2655
|
+
if (typeof v === "boolean") return `<${p}c r="${ref}"${s} t="b"><${p}v>${v ? 1 : 0}</${p}v></${p}c>`;
|
|
2656
|
+
if (typeof v === "number") return Number.isFinite(v) ? `<${p}c r="${ref}"${s}><${p}v>${v}</${p}v></${p}c>` : `<${p}c r="${ref}"${s} t="e"><${p}v>#NUM!</${p}v></${p}c>`;
|
|
2657
|
+
const str = String(v);
|
|
2658
|
+
if (x.t === 2 && str.trim() !== "" && Number.isFinite(Number(str))) return `<${p}c r="${ref}"${s}><${p}v>${Number(str)}</${p}v></${p}c>`;
|
|
2659
|
+
if (x.t !== 4 && errors.test(str)) return `<${p}c r="${ref}"${s} t="e"><${p}v>${escape(str)}</${p}v></${p}c>`;
|
|
2660
|
+
const space = /^\s|\s$|\n/.test(str) ? ' xml:space="preserve"' : "";
|
|
2661
|
+
return `<${p}c r="${ref}"${s} t="inlineStr"><${p}is><${p}t${space}>${escape(str)}</${p}t></${p}is></${p}c>`;
|
|
2662
|
+
}
|
|
2663
|
+
function columns(p, rec, sheet, old, cols, defaults, cur, baseBook, xfFor, xfOf) {
|
|
2664
|
+
const now = sheet.columnData ?? {}, was = old.columnData ?? {};
|
|
2665
|
+
const count = sheet.columnCount ?? 26;
|
|
2666
|
+
const look = (bk, s) => s ? norm({ ...defaults, ...lookup(bk, s) }) : null;
|
|
2667
|
+
let differs = cols.moved;
|
|
2668
|
+
for (let c = 0; c < count && !differs; c++) {
|
|
2669
|
+
const c0 = cols.from(c);
|
|
2670
|
+
const a = now[c] ?? {}, b = c0 >= 0 ? was[c0] ?? {} : {};
|
|
2671
|
+
if (Math.abs((a.w ?? -1) - (b.w ?? -1)) > 0.5 || !!a.hd !== !!b.hd || !same(look(cur, a.s), look(baseBook, b.s))) differs = true;
|
|
2672
|
+
}
|
|
2673
|
+
if (!differs) return void 0;
|
|
2674
|
+
const specs = rec?.cols ?? [];
|
|
2675
|
+
const specAt = (c0) => specs.find((s) => c0 + 1 >= s.min && c0 + 1 <= s.max);
|
|
2676
|
+
const out = [];
|
|
2677
|
+
for (let c = 0; c < count; c++) {
|
|
2678
|
+
const c0 = cols.from(c);
|
|
2679
|
+
const spec = c0 >= 0 ? specAt(c0) : void 0;
|
|
2680
|
+
const a = new Map(spec ? [...spec.xml.matchAll(/([\w:]+)="([^"]*)"/g)].map((m) => [m[1], m[2]]) : []);
|
|
2681
|
+
a.delete("min");
|
|
2682
|
+
a.delete("max");
|
|
2683
|
+
const n = now[c] ?? {}, o = c0 >= 0 ? was[c0] ?? {} : {};
|
|
2684
|
+
if (Math.abs((n.w ?? -1) - (o.w ?? -1)) > 0.5) {
|
|
2685
|
+
if (n.w === void 0) {
|
|
2686
|
+
a.delete("width");
|
|
2687
|
+
a.delete("customWidth");
|
|
2688
|
+
} else {
|
|
2689
|
+
a.set("width", String(pt.col(n.w)));
|
|
2690
|
+
a.set("customWidth", "1");
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
if (!!n.hd !== !!o.hd) n.hd ? a.set("hidden", "1") : a.delete("hidden");
|
|
2694
|
+
const ln = look(cur, n.s), lo = look(baseBook, o.s);
|
|
2695
|
+
if (!same(ln, lo)) ln ? a.set("style", String(xfFor(ln, xfOf(o.s)))) : a.delete("style");
|
|
2696
|
+
if (!a.size) continue;
|
|
2697
|
+
if (!a.has("width")) a.set("width", String(pt.col(sheet.defaultColumnWidth ?? 64)));
|
|
2698
|
+
out.push({ c, attrs: a });
|
|
2699
|
+
}
|
|
2700
|
+
const runs2 = [];
|
|
2701
|
+
for (let i = 0; i < out.length; i++) {
|
|
2702
|
+
let j = i;
|
|
2703
|
+
const k = JSON.stringify([...out[i].attrs]);
|
|
2704
|
+
while (j + 1 < out.length && out[j + 1].c === out[j].c + 1 && JSON.stringify([...out[j + 1].attrs]) === k) j++;
|
|
2705
|
+
runs2.push(`<${p}col min="${out[i].c + 1}" max="${out[j].c + 1}"${[...out[i].attrs].map(([n, v]) => ` ${n}="${v}"`).join("")}/>`);
|
|
2706
|
+
i = j;
|
|
2707
|
+
}
|
|
2708
|
+
const shift = count - (rec?.width ?? count);
|
|
2709
|
+
for (const spec of specs) {
|
|
2710
|
+
if (spec.max <= (rec?.width ?? 0)) continue;
|
|
2711
|
+
const min = Math.max(count + 1, spec.min + shift), max = Math.min(16384, spec.max + shift);
|
|
2712
|
+
if (min <= max) runs2.push(spec.xml.replace(/\smin="\d+"/, ` min="${min}"`).replace(/\smax="\d+"/, ` max="${max}"`));
|
|
2713
|
+
}
|
|
2714
|
+
return runs2.length ? `<${p}cols>${runs2.join("")}</${p}cols>` : null;
|
|
2715
|
+
}
|
|
2716
|
+
function frozen(head, p, x, y) {
|
|
2717
|
+
const pane = x || y ? `<${p}pane${x ? ` xSplit="${x}"` : ""}${y ? ` ySplit="${y}"` : ""} topLeftCell="${a1(y, x)}" activePane="${x && y ? "bottomRight" : y ? "bottomLeft" : "topRight"}" state="frozen"/>` : "";
|
|
2718
|
+
const selection = x || y ? `<${p}selection pane="${x && y ? "bottomRight" : y ? "bottomLeft" : "topRight"}" activeCell="${a1(y, x)}" sqref="${a1(y, x)}"/>` : `<${p}selection activeCell="A1" sqref="A1"/>`;
|
|
2719
|
+
const view = /<((?:\w+:)?)sheetView\b[^>]*?(\/?)>/.exec(head);
|
|
2720
|
+
if (!view) return place(head, "sheetViews", `<${p}sheetViews><${p}sheetView workbookViewId="0">${pane}${selection}</${p}sheetView></${p}sheetViews>`);
|
|
2721
|
+
if (view[2]) return head.slice(0, view.index) + view[0].replace(/\s*\/>$/, ">") + pane + selection + `</${view[1]}sheetView>` + head.slice(view.index + view[0].length);
|
|
2722
|
+
const close = head.indexOf(`</${view[1]}sheetView>`, view.index);
|
|
2723
|
+
const inner = head.slice(view.index + view[0].length, close).replace(/<(?:\w+:)?pane\b[^>]*\/>/g, "").replace(/<(?:\w+:)?selection\b[^>]*\/>/g, "");
|
|
2724
|
+
return head.slice(0, view.index) + view[0] + pane + selection + inner + head.slice(close);
|
|
2725
|
+
}
|
|
2726
|
+
function tabColour(head, p, colour) {
|
|
2727
|
+
const tag = colour ? `<${p}tabColor rgb="FF${colour.replace("#", "").toUpperCase()}"/>` : "";
|
|
2728
|
+
if (/<(?:\w+:)?tabColor\b/.test(head)) return head.replace(/<(?:\w+:)?tabColor\b[^>]*\/>/, tag);
|
|
2729
|
+
if (!colour) return head;
|
|
2730
|
+
const pr = /<((?:\w+:)?)sheetPr\b[^>]*?(\/?)>/.exec(head);
|
|
2731
|
+
if (!pr) return place(head, "sheetPr", `<${p}sheetPr>${tag}</${p}sheetPr>`);
|
|
2732
|
+
if (pr[2]) return head.slice(0, pr.index) + pr[0].replace(/\s*\/>$/, ">") + tag + `</${pr[1]}sheetPr>` + head.slice(pr.index + pr[0].length);
|
|
2733
|
+
return head.slice(0, pr.index + pr[0].length) + tag + head.slice(pr.index + pr[0].length);
|
|
2734
|
+
}
|
|
2735
|
+
function canonRule(r) {
|
|
2736
|
+
const out = {};
|
|
2737
|
+
for (const k of ["uid", "type", "operator", "formula1", "formula2", "allowBlank", "showDropDown", "showErrorMessage", "showInputMessage", "errorStyle", "error", "errorTitle", "prompt", "promptTitle"]) {
|
|
2738
|
+
const v = r[k];
|
|
2739
|
+
if (v !== void 0 && v !== null && v !== false && v !== "") out[k] = v;
|
|
2740
|
+
}
|
|
2741
|
+
if (out.type === "list" && out.showDropDown === void 0) out.showDropDown = true;
|
|
2742
|
+
out.ranges = r.ranges.map((b) => span(b)).sort();
|
|
2743
|
+
return out;
|
|
2744
|
+
}
|
|
2745
|
+
function validationXml(p, r, was) {
|
|
2746
|
+
if (!["whole", "decimal", "list", "textLength", "custom", "date"].includes(String(r.type))) return "";
|
|
2747
|
+
let tag = was ? was.slice(0, was.indexOf(">") + 1).replace(/\s*\/>$/, ">") : `<${p}dataValidation>`;
|
|
2748
|
+
const bool = (name, on) => {
|
|
2749
|
+
tag = setAttr(tag, name, on ? "1" : null);
|
|
2750
|
+
};
|
|
2751
|
+
tag = setAttr(tag, "type", String(r.type));
|
|
2752
|
+
tag = setAttr(tag, "operator", r.type === "list" || r.type === "custom" || !r.operator || r.operator === "between" ? null : String(r.operator));
|
|
2753
|
+
bool("allowBlank", r.allowBlank);
|
|
2754
|
+
bool("showDropDown", r.type === "list" && r.showDropDown === false);
|
|
2755
|
+
bool("showInputMessage", r.showInputMessage);
|
|
2756
|
+
bool("showErrorMessage", r.showErrorMessage);
|
|
2757
|
+
const style = Object.entries(stops).find(([, v]) => v === r.errorStyle)?.[0];
|
|
2758
|
+
tag = setAttr(tag, "errorStyle", style && style !== "stop" ? style : null);
|
|
2759
|
+
for (const name of ["errorTitle", "error", "promptTitle", "prompt"]) tag = setAttr(tag, name, blank(r[name]) ? null : String(r[name]));
|
|
2760
|
+
tag = setAttr(tag, "sqref", r.ranges.map(span).join(" "));
|
|
2761
|
+
const f1 = r.formula1 === void 0 ? "" : r.type === "list" && !String(r.formula1).startsWith("=") ? `"${listText(String(r.formula1)).replace(/"/g, '""')}"` : stored(String(r.formula1).replace(/^=/, ""));
|
|
2762
|
+
const f2 = r.formula2 === void 0 ? "" : stored(String(r.formula2).replace(/^=/, ""));
|
|
2763
|
+
return `${tag}${f1 ? `<${p}formula1>${escape(f1)}</${p}formula1>` : ""}${f2 ? `<${p}formula2>${escape(f2)}</${p}formula2>` : ""}</${p}dataValidation>`;
|
|
2764
|
+
}
|
|
2765
|
+
function listText(f) {
|
|
2766
|
+
try {
|
|
2767
|
+
const list = JSON.parse(f);
|
|
2768
|
+
if (Array.isArray(list)) return list.join(",");
|
|
2769
|
+
} catch {
|
|
2770
|
+
return f;
|
|
2771
|
+
}
|
|
2772
|
+
return f;
|
|
2773
|
+
}
|
|
2774
|
+
function filterXml(p, ref, columns2) {
|
|
2775
|
+
const body = columns2.map((c) => {
|
|
2776
|
+
if (c.filters) return `<${p}filterColumn colId="${c.colId}"><${p}filters${c.filters.blank ? ' blank="1"' : ""}>${(c.filters.filters ?? []).map((v) => `<${p}filter val="${escape(String(v))}"/>`).join("")}</${p}filters></${p}filterColumn>`;
|
|
2777
|
+
if (c.customFilters) return `<${p}filterColumn colId="${c.colId}"><${p}customFilters${c.customFilters.and ? ' and="1"' : ""}>${c.customFilters.customFilters.map((f) => `<${p}customFilter${f.operator ? ` operator="${f.operator}"` : ""} val="${escape(String(f.val))}"/>`).join("")}</${p}customFilters></${p}filterColumn>`;
|
|
2778
|
+
return "";
|
|
2779
|
+
}).join("");
|
|
2780
|
+
return body ? `<${p}autoFilter ref="${span(ref)}">${body}</${p}autoFilter>` : `<${p}autoFilter ref="${span(ref)}"/>`;
|
|
2781
|
+
}
|
|
2782
|
+
function writeNotes(book, entry2, tail, p, notes2, rows, cols, types, defaults, fresh2) {
|
|
2783
|
+
const { pack } = book;
|
|
2784
|
+
const rec = entry2.rec;
|
|
2785
|
+
const relsPart = relsOf(entry2.part);
|
|
2786
|
+
let rels = pack.text(relsPart) ?? '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"></Relationships>';
|
|
2787
|
+
let nextRid = Math.max(0, ...[...rels.matchAll(/\bId="rId(\d+)"/g)].map((m) => Number(m[1]))) + 1;
|
|
2788
|
+
let commentsPart = rec?.comments ?? null;
|
|
2789
|
+
let vmlPart = rec?.vml ?? null;
|
|
2790
|
+
if (!commentsPart) {
|
|
2791
|
+
commentsPart = fresh2((n) => `xl/comments${n}.xml`);
|
|
2792
|
+
rels = rels.replace("</Relationships>", () => `<Relationship Id="rId${nextRid++}" Type="${REL}/comments" Target="${relative(entry2.part, commentsPart)}"/></Relationships>`);
|
|
2793
|
+
types.push([`/${commentsPart}`, "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"]);
|
|
2794
|
+
}
|
|
2795
|
+
if (!vmlPart) {
|
|
2796
|
+
vmlPart = fresh2((n) => `xl/drawings/vmlDrawing${n}.vml`);
|
|
2797
|
+
const rid = `rId${nextRid++}`;
|
|
2798
|
+
rels = rels.replace("</Relationships>", () => `<Relationship Id="${rid}" Type="${REL}/vmlDrawing" Target="${relative(entry2.part, vmlPart)}"/></Relationships>`);
|
|
2799
|
+
defaults.add("vml");
|
|
2800
|
+
const relNs = /xmlns:(\w+)="http:\/\/schemas\.openxmlformats\.org\/officeDocument\/2006\/relationships"/.exec(rec?.xml ?? "")?.[1];
|
|
2801
|
+
tail = place(tail, "legacyDrawing", `<${p}legacyDrawing ${relNs ?? "r"}:id="${rid}"/>`);
|
|
2802
|
+
}
|
|
2803
|
+
pack.put(relsPart, rels);
|
|
2804
|
+
const authors = rec?.authors.length ? [...rec.authors] : ["Author"];
|
|
2805
|
+
const byOld = new Map((rec?.notes ?? []).map((n) => {
|
|
2806
|
+
const [r, c] = cell(n.ref);
|
|
2807
|
+
return [a1(rows.map(r), cols.map(c)), n];
|
|
2808
|
+
}));
|
|
2809
|
+
const list = [...notes2].sort((a, b) => a.row - b.row || a.col - b.col).map((n) => {
|
|
2810
|
+
const ref = a1(n.row, n.col);
|
|
2811
|
+
const was = byOld.get(ref);
|
|
2812
|
+
if (was && was.text === n.note) return setAttr(was.xml.slice(0, was.xml.indexOf(">") + 1), "ref", ref) + was.xml.slice(was.xml.indexOf(">") + 1);
|
|
2813
|
+
const authorId = was ? attr2(was.xml, "authorId") ?? "0" : "0";
|
|
2814
|
+
return `<${p}comment ref="${ref}" authorId="${authorId}"><${p}text><${p}r><${p}t xml:space="preserve">${escape(n.note)}</${p}t></${p}r></${p}text></${p}comment>`;
|
|
2815
|
+
});
|
|
2816
|
+
const existing = pack.text(commentsPart);
|
|
2817
|
+
const authorsXml = `<${p}authors>${authors.map((a) => `<${p}author>${escape(a)}</${p}author>`).join("")}</${p}authors>`;
|
|
2818
|
+
const commentsXml = existing ? existing.replace(/<((?:\w+:)?)commentList\b[^>]*?(?:\/>|>[\s\S]*?<\/\1commentList>)/, () => `<${p}commentList>${list.join("")}</${p}commentList>`) : `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
2819
|
+
<comments xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">${authorsXml}<commentList>${list.join("")}</commentList></comments>`;
|
|
2820
|
+
pack.put(commentsPart, commentsXml);
|
|
2821
|
+
const vml = pack.text(vmlPart) ?? '<xml xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel"><o:shapelayout v:ext="edit"><o:idmap v:ext="edit" data="1"/></o:shapelayout><v:shapetype id="_x0000_t202" coordsize="21600,21600" o:spt="202" path="m,l,21600r21600,l21600,xe"><v:stroke joinstyle="miter"/><v:path gradientshapeok="t" o:connecttype="rect"/></v:shapetype></xml>';
|
|
2822
|
+
const shapes = /* @__PURE__ */ new Map();
|
|
2823
|
+
let rest = vml.replace(/<v:shape\b[^>]*>[\s\S]*?<\/v:shape>/g, (shape) => {
|
|
2824
|
+
if (!/ObjectType="Note"/.test(shape)) return shape;
|
|
2825
|
+
const r = Number(/<x:Row>(\d+)<\/x:Row>/.exec(shape)?.[1] ?? -1), c = Number(/<x:Column>(\d+)<\/x:Column>/.exec(shape)?.[1] ?? -1);
|
|
2826
|
+
if (r >= 0 && c >= 0) shapes.set(a1(rows.map(r), cols.map(c)), shape);
|
|
2827
|
+
return "";
|
|
2828
|
+
});
|
|
2829
|
+
let id = Math.max(1024, ...[...vml.matchAll(/_x0000_s(\d+)/g)].map((m) => Number(m[1])));
|
|
2830
|
+
const out = notes2.map((n) => {
|
|
2831
|
+
const ref = a1(n.row, n.col);
|
|
2832
|
+
const was = shapes.get(ref);
|
|
2833
|
+
if (was) return was.replace(/<x:Row>\d+<\/x:Row>/, `<x:Row>${n.row}</x:Row>`).replace(/<x:Column>\d+<\/x:Column>/, `<x:Column>${n.col}</x:Column>`).replace(/<x:Anchor>([^<]*)<\/x:Anchor>/, `<x:Anchor>${n.col + 1}, 15, ${n.row}, 2, ${n.col + 3}, 15, ${n.row + 4}, 16</x:Anchor>`);
|
|
2834
|
+
return `<v:shape id="_x0000_s${++id}" type="#_x0000_t202" style="position:absolute;margin-left:59.25pt;margin-top:1.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden" fillcolor="#ffffe1" o:insetmode="auto"><v:fill color2="#ffffe1"/><v:shadow on="t" color="black" obscured="t"/><v:path o:connecttype="none"/><v:textbox style="mso-direction-alt:auto"><div style="text-align:left"></div></v:textbox><x:ClientData ObjectType="Note"><x:MoveWithCells/><x:SizeWithCells/><x:Anchor>${n.col + 1}, 15, ${n.row}, 2, ${n.col + 3}, 15, ${n.row + 4}, 16</x:Anchor><x:AutoFill>False</x:AutoFill><x:Row>${n.row}</x:Row><x:Column>${n.col}</x:Column></x:ClientData></v:shape>`;
|
|
2835
|
+
}).join("");
|
|
2836
|
+
rest = rest.replace(/<\/xml>\s*$/, () => `${out}</xml>`);
|
|
2837
|
+
pack.put(vmlPart, rest);
|
|
2838
|
+
return tail;
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
// src/sheets/book.ts
|
|
2842
|
+
function readSheet(bytes, kind) {
|
|
2843
|
+
return kind === "csv" ? readCsv(bytes) : load(bytes).model;
|
|
2844
|
+
}
|
|
2845
|
+
function writeSheet(original, model, kind) {
|
|
2846
|
+
return kind === "csv" ? writeCsv(original, model) : writeXlsx(original, model);
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
// src/sheets/shared.ts
|
|
2850
|
+
import * as Y from "yjs";
|
|
2851
|
+
var props = ["name", "hidden", "tabColor", "freeze", "showGridlines", "rightToLeft"];
|
|
2852
|
+
var spot = (row2, col) => `${row2}:${col}`;
|
|
2853
|
+
var canon = (x) => x === null || typeof x !== "object" ? JSON.stringify(x ?? null) : Array.isArray(x) ? `[${x.map(canon).join(",")}]` : `{${Object.keys(x).filter((k) => x[k] !== void 0).sort().map((k) => `${JSON.stringify(k)}:${canon(x[k])}`).join(",")}}`;
|
|
2854
|
+
var strip = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0 && v !== null));
|
|
2855
|
+
var fnv = (bytes, h = 2166136261) => {
|
|
2856
|
+
for (const b of bytes) h = Math.imul(h ^ b, 16777619) >>> 0;
|
|
2857
|
+
return h;
|
|
2858
|
+
};
|
|
2859
|
+
function parts(doc) {
|
|
2860
|
+
const book = doc.getMap("book");
|
|
2861
|
+
return {
|
|
2862
|
+
book,
|
|
2863
|
+
values: doc.getMap("values"),
|
|
2864
|
+
origin: doc.getMap("origin"),
|
|
2865
|
+
order: book.get("order"),
|
|
2866
|
+
sheets: book.get("sheets"),
|
|
2867
|
+
styles: book.get("styles")
|
|
2868
|
+
};
|
|
2869
|
+
}
|
|
2870
|
+
var pieces = (m) => ({
|
|
2871
|
+
rows: m.get("rows"),
|
|
2872
|
+
cols: m.get("cols"),
|
|
2873
|
+
cells: m.get("cells"),
|
|
2874
|
+
rowData: m.get("rowData"),
|
|
2875
|
+
colData: m.get("colData"),
|
|
2876
|
+
merges: m.get("merges"),
|
|
2877
|
+
notes: m.get("notes")
|
|
2878
|
+
});
|
|
2879
|
+
function made(config, lines2) {
|
|
2880
|
+
const m = new Y.Map();
|
|
2881
|
+
for (const name of props) if (config[name] !== void 0) m.set(name, config[name]);
|
|
2882
|
+
m.set("look", strip({ defaultRowHeight: config.defaultRowHeight, defaultColumnWidth: config.defaultColumnWidth, zoomRatio: config.zoomRatio }));
|
|
2883
|
+
m.set("rows", Y.Array.from(lines2.rows));
|
|
2884
|
+
m.set("cols", Y.Array.from(lines2.cols));
|
|
2885
|
+
for (const name of ["cells", "rowData", "colData", "merges", "notes"]) m.set(name, new Y.Map());
|
|
2886
|
+
return m;
|
|
2887
|
+
}
|
|
2888
|
+
function fill2(doc, model) {
|
|
2889
|
+
const { book: wb, lines: lines2 } = model;
|
|
2890
|
+
const book = doc.getMap("book");
|
|
2891
|
+
const notes2 = JSON.parse(wb.resources?.find((r) => r.name === "SHEET_NOTE_PLUGIN")?.data ?? "{}");
|
|
2892
|
+
doc.transact(() => {
|
|
2893
|
+
book.set("head", strip({ id: wb.id, name: wb.name, appVersion: wb.appVersion, locale: wb.locale, defaultStyle: wb.defaultStyle, dateSystem: wb.dateSystem }));
|
|
2894
|
+
book.set("extras", (wb.resources ?? []).filter((r) => r.name !== "SHEET_NOTE_PLUGIN"));
|
|
2895
|
+
book.set("active", model.active ?? null);
|
|
2896
|
+
book.set("styles", new Y.Map());
|
|
2897
|
+
book.set("order", Y.Array.from(wb.sheetOrder));
|
|
2898
|
+
book.set("sheets", new Y.Map());
|
|
2899
|
+
const { sheets, styles, values, origin } = parts(doc);
|
|
2900
|
+
for (const [id, look] of Object.entries(wb.styles)) if (look) styles.set(id, look);
|
|
2901
|
+
for (const sid of wb.sheetOrder) {
|
|
2902
|
+
const sheet = wb.sheets[sid];
|
|
2903
|
+
const l = lines2[sid];
|
|
2904
|
+
sheets.set(sid, made(sheet, l));
|
|
2905
|
+
origin.set(sid, { id: model.origin.sheets[sid], name: sheet.name ?? "", rows: l.rows.length, cols: l.cols.length });
|
|
2906
|
+
const { cells, rowData, colData, merges, notes: kept } = pieces(sheets.get(sid));
|
|
2907
|
+
for (const [r, line] of Object.entries(sheet.cellData ?? {})) for (const [c, x] of Object.entries(line ?? {})) {
|
|
2908
|
+
if (!x) continue;
|
|
2909
|
+
const at = spot(l.rows[+r], l.cols[+c]);
|
|
2910
|
+
const out = {};
|
|
2911
|
+
if (x.f) {
|
|
2912
|
+
out.f = x.f;
|
|
2913
|
+
values.set(`${sid}:${at}`, { v: x.v ?? null, t: x.t ?? null });
|
|
2914
|
+
} else {
|
|
2915
|
+
if (x.v !== void 0 && x.v !== null) out.v = x.v;
|
|
2916
|
+
if (x.t) out.t = x.t;
|
|
2917
|
+
}
|
|
2918
|
+
if (x.p) out.p = x.p;
|
|
2919
|
+
if (typeof x.s === "string") out.s = x.s;
|
|
2920
|
+
cells.set(at, out);
|
|
2921
|
+
}
|
|
2922
|
+
for (const [r, rd] of Object.entries(sheet.rowData ?? {})) if (rd) rowData.set(l.rows[+r], strip({ h: rd.h, hd: rd.hd, ia: rd.ia, s: typeof rd.s === "string" ? rd.s : void 0 }));
|
|
2923
|
+
for (const [c, cd] of Object.entries(sheet.columnData ?? {})) if (cd) colData.set(l.cols[+c], strip({ w: cd.w, hd: cd.hd, s: typeof cd.s === "string" ? cd.s : void 0 }));
|
|
2924
|
+
for (const b of sheet.mergeData ?? []) merges.set([l.rows[b.startRow], l.cols[b.startColumn], l.rows[b.endRow], l.cols[b.endColumn]].join(":"), 1);
|
|
2925
|
+
for (const [r, line] of Object.entries(notes2[sid] ?? {})) for (const [c, n] of Object.entries(line)) kept.set(spot(l.rows[+r], l.cols[+c]), { note: n.note, width: n.width, height: n.height });
|
|
2926
|
+
}
|
|
2927
|
+
});
|
|
2928
|
+
}
|
|
2929
|
+
function sheetOf(doc, sid, l) {
|
|
2930
|
+
const { sheets, values } = parts(doc);
|
|
2931
|
+
const m = sheets.get(sid);
|
|
2932
|
+
const { cells, rowData, colData, merges } = pieces(m);
|
|
2933
|
+
const rows = new Map(l.rows.map((id, i) => [id, i])), cols = new Map(l.cols.map((id, i) => [id, i]));
|
|
2934
|
+
const cellData = {};
|
|
2935
|
+
for (const [at, x] of cells) {
|
|
2936
|
+
const [row2, col] = at.split(":");
|
|
2937
|
+
const r = rows.get(row2), c = cols.get(col);
|
|
2938
|
+
if (r === void 0 || c === void 0) continue;
|
|
2939
|
+
const kept = x.f ? values.get(`${sid}:${at}`) : void 0;
|
|
2940
|
+
(cellData[r] ?? (cellData[r] = {}))[c] = kept ? { ...x, v: kept.v, t: kept.t } : { ...x };
|
|
2941
|
+
}
|
|
2942
|
+
const rowsOut = {}, colsOut = {};
|
|
2943
|
+
for (const [id, x] of rowData) if (rows.has(id)) rowsOut[rows.get(id)] = { ...x };
|
|
2944
|
+
for (const [id, x] of colData) if (cols.has(id)) colsOut[cols.get(id)] = { ...x };
|
|
2945
|
+
const mergeData = [...merges.keys()].map((k) => k.split(":")).map(([r0, c0, r1, c1]) => ({ startRow: rows.get(r0), startColumn: cols.get(c0), endRow: rows.get(r1), endColumn: cols.get(c1) })).filter((b) => [b.startRow, b.startColumn, b.endRow, b.endColumn].every((n) => n !== void 0));
|
|
2946
|
+
const out = { ...m.get("look"), id: sid, rowCount: l.rows.length, columnCount: l.cols.length, cellData, rowData: rowsOut, columnData: colsOut, mergeData };
|
|
2947
|
+
for (const name of props) if (m.has(name)) Object.assign(out, { [name]: m.get(name) });
|
|
2948
|
+
return out;
|
|
2949
|
+
}
|
|
2950
|
+
var notesOf = (m, l) => {
|
|
2951
|
+
const rows = new Map(l.rows.map((id, i) => [id, i])), cols = new Map(l.cols.map((id, i) => [id, i]));
|
|
2952
|
+
return [...pieces(m).notes].map(([at, n]) => ({ ...n, row: rows.get(at.split(":")[0]), col: cols.get(at.split(":")[1]) })).filter((n) => n.row !== void 0 && n.col !== void 0);
|
|
2953
|
+
};
|
|
2954
|
+
function build(doc) {
|
|
2955
|
+
const { book, order: order2, sheets, styles, origin } = parts(doc);
|
|
2956
|
+
const sheetOrder = [...new Set(order2.toArray())].filter((sid) => sheets.has(sid));
|
|
2957
|
+
const wb = { ...book.get("head"), styles: styles.toJSON(), sheetOrder, sheets: {}, resources: [] };
|
|
2958
|
+
const model = { book: wb, lines: {}, origin: { sheets: {}, lines: {} } };
|
|
2959
|
+
const notes2 = {};
|
|
2960
|
+
for (const sid of sheetOrder) {
|
|
2961
|
+
const { rows, cols } = pieces(sheets.get(sid));
|
|
2962
|
+
const l = { rows: rows.toArray(), cols: cols.toArray() };
|
|
2963
|
+
model.lines[sid] = l;
|
|
2964
|
+
wb.sheets[sid] = sheetOf(doc, sid, l);
|
|
2965
|
+
notesOf(sheets.get(sid), l).forEach((n, i) => {
|
|
2966
|
+
var _a, _b;
|
|
2967
|
+
((_a = notes2[sid] ?? (notes2[sid] = {}))[_b = n.row] ?? (_a[_b] = {}))[n.col] = { ...n, show: false, id: `n${i}` };
|
|
2968
|
+
});
|
|
2969
|
+
const o = origin.get(sid);
|
|
2970
|
+
if (!o) continue;
|
|
2971
|
+
model.origin.sheets[sid] = o.id;
|
|
2972
|
+
model.origin.lines[sid] = { rows: typeof o.rows === "number" ? numbered("r", o.rows) : o.rows, cols: typeof o.cols === "number" ? numbered("c", o.cols) : o.cols };
|
|
2973
|
+
}
|
|
2974
|
+
wb.resources.push({ name: "SHEET_NOTE_PLUGIN", data: JSON.stringify(notes2) });
|
|
2975
|
+
const active = book.get("active");
|
|
2976
|
+
if (active && sheetOrder.includes(active)) model.active = active;
|
|
2977
|
+
return model;
|
|
2978
|
+
}
|
|
2979
|
+
function extras(doc, model) {
|
|
2980
|
+
const { book, origin } = parts(doc);
|
|
2981
|
+
const own = new Map([...origin.entries()].filter(([sid]) => model.lines[sid]).map(([sid, o]) => {
|
|
2982
|
+
const old = model.origin.lines[sid], now = model.lines[sid];
|
|
2983
|
+
return [`s${o.id}`, { sid, name: o.name, rows: new Axis(old.rows, now.rows), cols: new Axis(old.cols, now.cols) }];
|
|
2984
|
+
}));
|
|
2985
|
+
const fix = (b, sid) => {
|
|
2986
|
+
const a = own.get(sid);
|
|
2987
|
+
return squeeze(b, a.rows.map, a.cols.map);
|
|
2988
|
+
};
|
|
2989
|
+
for (const r of book.get("extras")) {
|
|
2990
|
+
const parsed = JSON.parse(r.data);
|
|
2991
|
+
let out = {};
|
|
2992
|
+
if (r.name === "SHEET_DEFINED_NAME_PLUGIN") out = Object.fromEntries(Object.entries(parsed).map(([id, n]) => {
|
|
2993
|
+
let f = n.formulaOrRefString;
|
|
2994
|
+
for (const a of own.values()) {
|
|
2995
|
+
f = remapped(f, (s) => s === a.name, a.rows.map, a.cols.map);
|
|
2996
|
+
if (a.name !== model.book.sheets[a.sid].name) f = renamed(f, a.name, model.book.sheets[a.sid].name);
|
|
2997
|
+
}
|
|
2998
|
+
return [id, { ...n, formulaOrRefString: f, localSheetId: own.get(n.localSheetId)?.sid ?? n.localSheetId }];
|
|
2999
|
+
}));
|
|
3000
|
+
else for (const [base, x] of Object.entries(parsed)) {
|
|
3001
|
+
const a = own.get(base);
|
|
3002
|
+
if (!a) continue;
|
|
3003
|
+
if (r.name === "SHEET_DATA_VALIDATION_PLUGIN") out[a.sid] = x.map((rule) => ({ ...rule, ranges: rule.ranges.map((b) => fix(b, base)).filter(Boolean) })).filter((rule) => rule.ranges.length);
|
|
3004
|
+
else if (r.name === "SHEET_FILTER_PLUGIN") {
|
|
3005
|
+
const f = x;
|
|
3006
|
+
const ref = fix(f.ref, base);
|
|
3007
|
+
if (ref) out[a.sid] = { ...f, ref: { ...f.ref, ...ref }, cachedFilteredOut: (f.cachedFilteredOut ?? []).map(a.rows.map).filter((n) => n >= 0) };
|
|
3008
|
+
} else out[a.sid] = x;
|
|
3009
|
+
}
|
|
3010
|
+
model.book.resources.push({ name: r.name, data: JSON.stringify(out) });
|
|
3011
|
+
}
|
|
3012
|
+
return model;
|
|
3013
|
+
}
|
|
3014
|
+
function settle(doc, model, bytes, kind) {
|
|
3015
|
+
const { book, origin } = parts(doc);
|
|
3016
|
+
const ids = kind === "csv" ? [] : worksheets(bytes);
|
|
3017
|
+
const saved = readSheet(bytes, kind);
|
|
3018
|
+
const back = /* @__PURE__ */ new Map();
|
|
3019
|
+
model.book.sheetOrder.forEach((sid, i) => {
|
|
3020
|
+
const id = ids[i] ?? i + 1;
|
|
3021
|
+
back.set(`s${id}`, sid);
|
|
3022
|
+
origin.set(sid, { id, name: model.book.sheets[sid].name ?? "", rows: model.lines[sid].rows, cols: model.lines[sid].cols });
|
|
3023
|
+
});
|
|
3024
|
+
for (const sid of [...origin.keys()]) if (!model.lines[sid]) origin.delete(sid);
|
|
3025
|
+
book.set("extras", (saved.book.resources ?? []).filter((r) => r.name !== "SHEET_NOTE_PLUGIN"));
|
|
3026
|
+
}
|
|
3027
|
+
function applyCells(doc, list, origin) {
|
|
3028
|
+
const { order: order2, sheets, values } = parts(doc);
|
|
3029
|
+
let done = 0;
|
|
3030
|
+
doc.transact(() => {
|
|
3031
|
+
for (const x of list) {
|
|
3032
|
+
const sid = order2.toArray().find((id) => sheets.get(id)?.get("name") === x.sheet);
|
|
3033
|
+
const [r, c] = cell(x.ref);
|
|
3034
|
+
if (!sid || r < 0) continue;
|
|
3035
|
+
const { rows, cols, cells } = pieces(sheets.get(sid));
|
|
3036
|
+
if (r >= rows.length || c >= cols.length) continue;
|
|
3037
|
+
const at = spot(rows.get(r), cols.get(c));
|
|
3038
|
+
const next = {};
|
|
3039
|
+
if (x.formula !== void 0) next.f = x.formula.startsWith("=") ? x.formula : `=${x.formula}`;
|
|
3040
|
+
else if (typeof x.value === "boolean") Object.assign(next, { v: x.value ? 1 : 0, t: 3 });
|
|
3041
|
+
else if (x.value !== void 0 && x.value !== null && x.value !== "") Object.assign(next, { v: x.value, t: typeof x.value === "number" ? 2 : 1 });
|
|
3042
|
+
const s = cells.get(at)?.s;
|
|
3043
|
+
if (s) next.s = s;
|
|
3044
|
+
values.delete(`${sid}:${at}`);
|
|
3045
|
+
if (Object.keys(next).length) cells.set(at, next);
|
|
3046
|
+
else cells.delete(at);
|
|
3047
|
+
done++;
|
|
3048
|
+
}
|
|
3049
|
+
}, origin);
|
|
3050
|
+
return done;
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
// src/sheets/text.ts
|
|
3054
|
+
var en = {
|
|
3055
|
+
tools: "Sheet tools",
|
|
3056
|
+
loading: "Opening the sheet",
|
|
3057
|
+
failed: "This sheet could not be opened",
|
|
3058
|
+
retry: "Try again",
|
|
3059
|
+
undo: "Undo",
|
|
3060
|
+
redo: "Redo",
|
|
3061
|
+
bold: "Bold",
|
|
3062
|
+
italic: "Italic",
|
|
3063
|
+
underline: "Underline",
|
|
3064
|
+
strike: "Strike out",
|
|
3065
|
+
textColour: "Text colour",
|
|
3066
|
+
fill: "Fill colour",
|
|
3067
|
+
automatic: "Automatic",
|
|
3068
|
+
noFill: "No fill",
|
|
3069
|
+
borders: "Borders",
|
|
3070
|
+
borderAll: "All borders",
|
|
3071
|
+
borderOuter: "Outer border",
|
|
3072
|
+
borderBottom: "Bottom border",
|
|
3073
|
+
borderNone: "No borders",
|
|
3074
|
+
alignLeft: "Align left",
|
|
3075
|
+
alignCenter: "Centre",
|
|
3076
|
+
alignRight: "Align right",
|
|
3077
|
+
wrap: "Wrap text",
|
|
3078
|
+
merge: "Merge cells",
|
|
3079
|
+
unmerge: "Split cells",
|
|
3080
|
+
format: "Number format",
|
|
3081
|
+
general: "General",
|
|
3082
|
+
number: "Number",
|
|
3083
|
+
percent: "Percent",
|
|
3084
|
+
currency: "Currency",
|
|
3085
|
+
date: "Date",
|
|
3086
|
+
time: "Time",
|
|
3087
|
+
text: "Text",
|
|
3088
|
+
rowAbove: "Row above",
|
|
3089
|
+
rowBelow: "Row below",
|
|
3090
|
+
columnLeft: "Column on the left",
|
|
3091
|
+
columnRight: "Column on the right",
|
|
3092
|
+
deleteRows: "Delete rows",
|
|
3093
|
+
deleteColumns: "Delete columns",
|
|
3094
|
+
freeze: "Freeze",
|
|
3095
|
+
freezeNone: "Unfreeze",
|
|
3096
|
+
freezeRow: "First row",
|
|
3097
|
+
freezeColumn: "First column",
|
|
3098
|
+
freezeHere: "Up to the selected cell",
|
|
3099
|
+
sortUp: "Sort A to Z",
|
|
3100
|
+
sortDown: "Sort Z to A",
|
|
3101
|
+
filter: "Filter",
|
|
3102
|
+
find: "Find and replace",
|
|
3103
|
+
note: "Note",
|
|
3104
|
+
save: "Save",
|
|
3105
|
+
saving: "Saving",
|
|
3106
|
+
saved: "Saved",
|
|
3107
|
+
saveFailed: "Could not save",
|
|
3108
|
+
editedNote: "Sheet edited",
|
|
3109
|
+
viewOnly: "View only",
|
|
3110
|
+
notesOnly: "You can add notes",
|
|
3111
|
+
offline: "Offline",
|
|
3112
|
+
offlineHint: "Your changes stay here and sync when the connection is back",
|
|
3113
|
+
liveOff: "Live editing is unavailable",
|
|
3114
|
+
people: "People in this sheet",
|
|
3115
|
+
you: "you",
|
|
3116
|
+
refused: {
|
|
3117
|
+
chartSource: "A chart on another sheet uses data from \u201C{sheet}\u201D. Bring that sheet back to save.",
|
|
3118
|
+
pivotSheet: "A pivot table reads its data from \u201C{sheet}\u201D. Bring that sheet back to save.",
|
|
3119
|
+
tableColumns: "Columns changed inside a table on \u201C{sheet}\u201D. Undo that change to save."
|
|
3120
|
+
}
|
|
3121
|
+
};
|
|
3122
|
+
var pl = {
|
|
3123
|
+
tools: "Narz\u0119dzia arkusza",
|
|
3124
|
+
loading: "Otwieranie arkusza",
|
|
3125
|
+
failed: "Nie uda\u0142o si\u0119 otworzy\u0107 tego arkusza",
|
|
3126
|
+
retry: "Spr\xF3buj ponownie",
|
|
3127
|
+
undo: "Cofnij",
|
|
3128
|
+
redo: "Pon\xF3w",
|
|
3129
|
+
bold: "Pogrubienie",
|
|
3130
|
+
italic: "Kursywa",
|
|
3131
|
+
underline: "Podkre\u015Blenie",
|
|
3132
|
+
strike: "Przekre\u015Blenie",
|
|
3133
|
+
textColour: "Kolor tekstu",
|
|
3134
|
+
fill: "Kolor wype\u0142nienia",
|
|
3135
|
+
automatic: "Automatyczny",
|
|
3136
|
+
noFill: "Bez wype\u0142nienia",
|
|
3137
|
+
borders: "Obramowanie",
|
|
3138
|
+
borderAll: "Wszystkie kraw\u0119dzie",
|
|
3139
|
+
borderOuter: "Kraw\u0119dzie zewn\u0119trzne",
|
|
3140
|
+
borderBottom: "Dolna kraw\u0119d\u017A",
|
|
3141
|
+
borderNone: "Bez kraw\u0119dzi",
|
|
3142
|
+
alignLeft: "Do lewej",
|
|
3143
|
+
alignCenter: "Wy\u015Brodkuj",
|
|
3144
|
+
alignRight: "Do prawej",
|
|
3145
|
+
wrap: "Zawijaj tekst",
|
|
3146
|
+
merge: "Scal kom\xF3rki",
|
|
3147
|
+
unmerge: "Rozdziel kom\xF3rki",
|
|
3148
|
+
format: "Format liczb",
|
|
3149
|
+
general: "Og\xF3lny",
|
|
3150
|
+
number: "Liczba",
|
|
3151
|
+
percent: "Procent",
|
|
3152
|
+
currency: "Waluta",
|
|
3153
|
+
date: "Data",
|
|
3154
|
+
time: "Godzina",
|
|
3155
|
+
text: "Tekst",
|
|
3156
|
+
rowAbove: "Wiersz powy\u017Cej",
|
|
3157
|
+
rowBelow: "Wiersz poni\u017Cej",
|
|
3158
|
+
columnLeft: "Kolumna po lewej",
|
|
3159
|
+
columnRight: "Kolumna po prawej",
|
|
3160
|
+
deleteRows: "Usu\u0144 wiersze",
|
|
3161
|
+
deleteColumns: "Usu\u0144 kolumny",
|
|
3162
|
+
freeze: "Zablokuj",
|
|
3163
|
+
freezeNone: "Odblokuj",
|
|
3164
|
+
freezeRow: "Pierwszy wiersz",
|
|
3165
|
+
freezeColumn: "Pierwsza kolumna",
|
|
3166
|
+
freezeHere: "Do zaznaczonej kom\xF3rki",
|
|
3167
|
+
sortUp: "Sortuj od A do Z",
|
|
3168
|
+
sortDown: "Sortuj od Z do A",
|
|
3169
|
+
filter: "Filtr",
|
|
3170
|
+
find: "Znajd\u017A i zamie\u0144",
|
|
3171
|
+
note: "Notatka",
|
|
3172
|
+
save: "Zapisz",
|
|
3173
|
+
saving: "Zapisywanie",
|
|
3174
|
+
saved: "Zapisano",
|
|
3175
|
+
saveFailed: "Nie uda\u0142o si\u0119 zapisa\u0107",
|
|
3176
|
+
editedNote: "Edycja arkusza",
|
|
3177
|
+
viewOnly: "Tylko podgl\u0105d",
|
|
3178
|
+
notesOnly: "Mo\u017Cesz dodawa\u0107 notatki",
|
|
3179
|
+
offline: "Offline",
|
|
3180
|
+
offlineHint: "Zmiany zostaj\u0105 tutaj i zsynchronizuj\u0105 si\u0119 po powrocie po\u0142\u0105czenia",
|
|
3181
|
+
liveOff: "Wsp\xF3lna edycja jest niedost\u0119pna",
|
|
3182
|
+
people: "Osoby w tym arkuszu",
|
|
3183
|
+
you: "ty",
|
|
3184
|
+
refused: {
|
|
3185
|
+
chartSource: "Wykres na innym arkuszu korzysta z danych arkusza \u201E{sheet}\u201D. Przywr\xF3\u0107 ten arkusz, aby zapisa\u0107.",
|
|
3186
|
+
pivotSheet: "Tabela przestawna pobiera dane z arkusza \u201E{sheet}\u201D. Przywr\xF3\u0107 ten arkusz, aby zapisa\u0107.",
|
|
3187
|
+
tableColumns: "Kolumny zmieni\u0142y si\u0119 wewn\u0105trz tabeli na arkuszu \u201E{sheet}\u201D. Cofnij t\u0119 zmian\u0119, aby zapisa\u0107."
|
|
3188
|
+
}
|
|
3189
|
+
};
|
|
3190
|
+
var uk = {
|
|
3191
|
+
tools: "\u0406\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0438 \u0442\u0430\u0431\u043B\u0438\u0446\u0456",
|
|
3192
|
+
loading: "\u0412\u0456\u0434\u043A\u0440\u0438\u0432\u0430\u0454\u043C\u043E \u0442\u0430\u0431\u043B\u0438\u0446\u044E",
|
|
3193
|
+
failed: "\u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044F \u0432\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0446\u044E \u0442\u0430\u0431\u043B\u0438\u0446\u044E",
|
|
3194
|
+
retry: "\u0421\u043F\u0440\u043E\u0431\u0443\u0432\u0430\u0442\u0438 \u0449\u0435",
|
|
3195
|
+
undo: "\u0412\u0456\u0434\u043C\u0456\u043D\u0438\u0442\u0438",
|
|
3196
|
+
redo: "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0438",
|
|
3197
|
+
bold: "\u0416\u0438\u0440\u043D\u0438\u0439",
|
|
3198
|
+
italic: "\u041A\u0443\u0440\u0441\u0438\u0432",
|
|
3199
|
+
underline: "\u041F\u0456\u0434\u043A\u0440\u0435\u0441\u043B\u0435\u043D\u0438\u0439",
|
|
3200
|
+
strike: "\u0417\u0430\u043A\u0440\u0435\u0441\u043B\u0435\u043D\u0438\u0439",
|
|
3201
|
+
textColour: "\u041A\u043E\u043B\u0456\u0440 \u0442\u0435\u043A\u0441\u0442\u0443",
|
|
3202
|
+
fill: "\u041A\u043E\u043B\u0456\u0440 \u0437\u0430\u043B\u0438\u0432\u043A\u0438",
|
|
3203
|
+
automatic: "\u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u0438\u0439",
|
|
3204
|
+
noFill: "\u0411\u0435\u0437 \u0437\u0430\u043B\u0438\u0432\u043A\u0438",
|
|
3205
|
+
borders: "\u041C\u0435\u0436\u0456",
|
|
3206
|
+
borderAll: "\u0423\u0441\u0456 \u043C\u0435\u0436\u0456",
|
|
3207
|
+
borderOuter: "\u0417\u043E\u0432\u043D\u0456\u0448\u043D\u0456 \u043C\u0435\u0436\u0456",
|
|
3208
|
+
borderBottom: "\u041D\u0438\u0436\u043D\u044F \u043C\u0435\u0436\u0430",
|
|
3209
|
+
borderNone: "\u0411\u0435\u0437 \u043C\u0435\u0436",
|
|
3210
|
+
alignLeft: "\u041B\u0456\u0432\u043E\u0440\u0443\u0447",
|
|
3211
|
+
alignCenter: "\u041F\u043E \u0446\u0435\u043D\u0442\u0440\u0443",
|
|
3212
|
+
alignRight: "\u041F\u0440\u0430\u0432\u043E\u0440\u0443\u0447",
|
|
3213
|
+
wrap: "\u041F\u0435\u0440\u0435\u043D\u043E\u0441\u0438\u0442\u0438 \u0442\u0435\u043A\u0441\u0442",
|
|
3214
|
+
merge: "\u041E\u0431\u2019\u0454\u0434\u043D\u0430\u0442\u0438 \u043A\u043B\u0456\u0442\u0438\u043D\u043A\u0438",
|
|
3215
|
+
unmerge: "\u0420\u043E\u0437\u2019\u0454\u0434\u043D\u0430\u0442\u0438 \u043A\u043B\u0456\u0442\u0438\u043D\u043A\u0438",
|
|
3216
|
+
format: "\u0424\u043E\u0440\u043C\u0430\u0442 \u0447\u0438\u0441\u0435\u043B",
|
|
3217
|
+
general: "\u0417\u0430\u0433\u0430\u043B\u044C\u043D\u0438\u0439",
|
|
3218
|
+
number: "\u0427\u0438\u0441\u043B\u043E",
|
|
3219
|
+
percent: "\u0412\u0456\u0434\u0441\u043E\u0442\u043E\u043A",
|
|
3220
|
+
currency: "\u0412\u0430\u043B\u044E\u0442\u0430",
|
|
3221
|
+
date: "\u0414\u0430\u0442\u0430",
|
|
3222
|
+
time: "\u0427\u0430\u0441",
|
|
3223
|
+
text: "\u0422\u0435\u043A\u0441\u0442",
|
|
3224
|
+
rowAbove: "\u0420\u044F\u0434\u043E\u043A \u0432\u0438\u0449\u0435",
|
|
3225
|
+
rowBelow: "\u0420\u044F\u0434\u043E\u043A \u043D\u0438\u0436\u0447\u0435",
|
|
3226
|
+
columnLeft: "\u0421\u0442\u043E\u0432\u043F\u0435\u0446\u044C \u043B\u0456\u0432\u043E\u0440\u0443\u0447",
|
|
3227
|
+
columnRight: "\u0421\u0442\u043E\u0432\u043F\u0435\u0446\u044C \u043F\u0440\u0430\u0432\u043E\u0440\u0443\u0447",
|
|
3228
|
+
deleteRows: "\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u0440\u044F\u0434\u043A\u0438",
|
|
3229
|
+
deleteColumns: "\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u0441\u0442\u043E\u0432\u043F\u0446\u0456",
|
|
3230
|
+
freeze: "\u0417\u0430\u043A\u0440\u0456\u043F\u0438\u0442\u0438",
|
|
3231
|
+
freezeNone: "\u0412\u0456\u0434\u043A\u0440\u0456\u043F\u0438\u0442\u0438",
|
|
3232
|
+
freezeRow: "\u041F\u0435\u0440\u0448\u0438\u0439 \u0440\u044F\u0434\u043E\u043A",
|
|
3233
|
+
freezeColumn: "\u041F\u0435\u0440\u0448\u0438\u0439 \u0441\u0442\u043E\u0432\u043F\u0435\u0446\u044C",
|
|
3234
|
+
freezeHere: "\u0414\u043E \u0432\u0438\u0434\u0456\u043B\u0435\u043D\u043E\u0457 \u043A\u043B\u0456\u0442\u0438\u043D\u043A\u0438",
|
|
3235
|
+
sortUp: "\u0421\u043E\u0440\u0442\u0443\u0432\u0430\u0442\u0438 \u0432\u0456\u0434 \u0410 \u0434\u043E \u042F",
|
|
3236
|
+
sortDown: "\u0421\u043E\u0440\u0442\u0443\u0432\u0430\u0442\u0438 \u0432\u0456\u0434 \u042F \u0434\u043E \u0410",
|
|
3237
|
+
filter: "\u0424\u0456\u043B\u044C\u0442\u0440",
|
|
3238
|
+
find: "\u0417\u043D\u0430\u0439\u0442\u0438 \u0439 \u0437\u0430\u043C\u0456\u043D\u0438\u0442\u0438",
|
|
3239
|
+
note: "\u041F\u0440\u0438\u043C\u0456\u0442\u043A\u0430",
|
|
3240
|
+
save: "\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438",
|
|
3241
|
+
saving: "\u0417\u0431\u0435\u0440\u0435\u0436\u0435\u043D\u043D\u044F",
|
|
3242
|
+
saved: "\u0417\u0431\u0435\u0440\u0435\u0436\u0435\u043D\u043E",
|
|
3243
|
+
saveFailed: "\u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044F \u0437\u0431\u0435\u0440\u0435\u0433\u0442\u0438",
|
|
3244
|
+
editedNote: "\u041F\u0440\u0430\u0432\u043A\u0430 \u0442\u0430\u0431\u043B\u0438\u0446\u0456",
|
|
3245
|
+
viewOnly: "\u041B\u0438\u0448\u0435 \u043F\u0435\u0440\u0435\u0433\u043B\u044F\u0434",
|
|
3246
|
+
notesOnly: "\u041C\u043E\u0436\u043D\u0430 \u0434\u043E\u0434\u0430\u0432\u0430\u0442\u0438 \u043F\u0440\u0438\u043C\u0456\u0442\u043A\u0438",
|
|
3247
|
+
offline: "\u041E\u0444\u043B\u0430\u0439\u043D",
|
|
3248
|
+
offlineHint: "\u0417\u043C\u0456\u043D\u0438 \u043B\u0438\u0448\u0430\u044E\u0442\u044C\u0441\u044F \u0442\u0443\u0442 \u0456 \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0456\u0437\u0443\u044E\u0442\u044C\u0441\u044F, \u043A\u043E\u043B\u0438 \u0437\u2019\u044F\u0432\u0438\u0442\u044C\u0441\u044F \u0437\u0432\u2019\u044F\u0437\u043E\u043A",
|
|
3249
|
+
liveOff: "\u0421\u043F\u0456\u043B\u044C\u043D\u0435 \u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u043D\u043D\u044F \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0435",
|
|
3250
|
+
people: "\u041B\u044E\u0434\u0438 \u0432 \u0446\u0456\u0439 \u0442\u0430\u0431\u043B\u0438\u0446\u0456",
|
|
3251
|
+
you: "\u0432\u0438",
|
|
3252
|
+
refused: {
|
|
3253
|
+
chartSource: "\u0414\u0456\u0430\u0433\u0440\u0430\u043C\u0430 \u043D\u0430 \u0456\u043D\u0448\u043E\u043C\u0443 \u0430\u0440\u043A\u0443\u0448\u0456 \u0431\u0435\u0440\u0435 \u0434\u0430\u043D\u0456 \u0437 \u0430\u0440\u043A\u0443\u0448\u0430 \xAB{sheet}\xBB. \u041F\u043E\u0432\u0435\u0440\u043D\u0456\u0442\u044C \u0446\u0435\u0439 \u0430\u0440\u043A\u0443\u0448, \u0449\u043E\u0431 \u0437\u0431\u0435\u0440\u0435\u0433\u0442\u0438.",
|
|
3254
|
+
pivotSheet: "\u0417\u0432\u0435\u0434\u0435\u043D\u0430 \u0442\u0430\u0431\u043B\u0438\u0446\u044F \u0431\u0435\u0440\u0435 \u0434\u0430\u043D\u0456 \u0437 \u0430\u0440\u043A\u0443\u0448\u0430 \xAB{sheet}\xBB. \u041F\u043E\u0432\u0435\u0440\u043D\u0456\u0442\u044C \u0446\u0435\u0439 \u0430\u0440\u043A\u0443\u0448, \u0449\u043E\u0431 \u0437\u0431\u0435\u0440\u0435\u0433\u0442\u0438.",
|
|
3255
|
+
tableColumns: "\u0421\u0442\u043E\u0432\u043F\u0446\u0456 \u0437\u043C\u0456\u043D\u0438\u043B\u0438\u0441\u044F \u0432\u0441\u0435\u0440\u0435\u0434\u0438\u043D\u0456 \u0442\u0430\u0431\u043B\u0438\u0446\u0456 \u043D\u0430 \u0430\u0440\u043A\u0443\u0448\u0456 \xAB{sheet}\xBB. \u0412\u0456\u0434\u043C\u0456\u043D\u0456\u0442\u044C \u0446\u044E \u0437\u043C\u0456\u043D\u0443, \u0449\u043E\u0431 \u0437\u0431\u0435\u0440\u0435\u0433\u0442\u0438."
|
|
3256
|
+
}
|
|
3257
|
+
};
|
|
3258
|
+
var sheetTexts = { en, pl, uk };
|
|
3259
|
+
|
|
3260
|
+
// src/collab.ts
|
|
3261
|
+
var ours = "w100n-collab";
|
|
3262
|
+
var schemas = /* @__PURE__ */ new Map();
|
|
3263
|
+
var schemaOf = (kind) => schemas.get(kind) ?? schemas.set(kind, getSchema(kit(kind, texts.en))).get(kind);
|
|
3264
|
+
var parse2 = async (kind, bytes) => kind === "docx" ? (await readDocx(bytes)).doc : fromMarkdown(new TextDecoder().decode(bytes)).doc;
|
|
3265
|
+
var edits = (tr) => tr.changedParentTypes.has(tr.doc.get("default")) || tr.changedParentTypes.has(tr.doc.get("book"));
|
|
3266
|
+
var filled = (doc) => doc.getXmlFragment("default").length > 0 || doc.getMap("book").size > 0;
|
|
3267
|
+
function seed(doc, kind, bytes, json) {
|
|
3268
|
+
if (filled(doc)) return false;
|
|
3269
|
+
const fixed = new Y2.Doc();
|
|
3270
|
+
fixed.clientID = fnv(new Uint8Array(bytes), fnv(new TextEncoder().encode(`${version}:${kind}`)));
|
|
3271
|
+
if (kind === "xlsx" || kind === "csv") fill2(fixed, readSheet(bytes, kind));
|
|
3272
|
+
else prosemirrorJSONToYXmlFragment(schemaOf(kind), json, fixed.getXmlFragment("default"));
|
|
3273
|
+
Y2.applyUpdate(doc, Y2.encodeStateAsUpdate(fixed), ours);
|
|
3274
|
+
return true;
|
|
3275
|
+
}
|
|
3276
|
+
function follow(doc, author) {
|
|
3277
|
+
const editors = doc.getMap("editors");
|
|
3278
|
+
const before = (tr) => tr.meta.set("fresh", !filled(doc));
|
|
3279
|
+
const after = (tr) => {
|
|
3280
|
+
const who = !tr.meta.get("fresh") && edits(tr) ? author(tr.origin) : null;
|
|
3281
|
+
if (who && !editors.has(who.id)) doc.transact(() => editors.set(who.id, who), ours);
|
|
3282
|
+
};
|
|
3283
|
+
doc.on("beforeTransaction", before);
|
|
3284
|
+
doc.on("afterTransaction", after);
|
|
3285
|
+
return () => {
|
|
3286
|
+
doc.off("beforeTransaction", before);
|
|
3287
|
+
doc.off("afterTransaction", after);
|
|
3288
|
+
};
|
|
3289
|
+
}
|
|
3290
|
+
var pending = (doc) => doc.getMap("editors").size > 0;
|
|
3291
|
+
var Refusal = class extends Error {
|
|
3292
|
+
};
|
|
3293
|
+
function applyText(doc, kind, changes2, origin) {
|
|
3294
|
+
const schema = schemaOf(kind);
|
|
3295
|
+
const fragment = doc.getXmlFragment("default");
|
|
3296
|
+
const step = new Transform(yXmlFragmentToProseMirrorRootNode(fragment, schema));
|
|
3297
|
+
for (const c of changes2) {
|
|
3298
|
+
const hits = [];
|
|
3299
|
+
step.doc.descendants((node, pos) => {
|
|
3300
|
+
if (!node.isTextblock) return true;
|
|
3301
|
+
const text = node.textBetween(0, node.content.size, void 0, "\uFFFC");
|
|
3302
|
+
for (let i = text.indexOf(c.find); c.find && i >= 0; i = text.indexOf(c.find, i + 1)) hits.push(pos + 1 + i);
|
|
3303
|
+
return false;
|
|
3304
|
+
});
|
|
3305
|
+
if (hits.length !== 1) throw new Refusal(`${hits.length ? "more than once" : "not"} in the document: ${c.find.slice(0, 80)}`);
|
|
3306
|
+
const [at] = hits;
|
|
3307
|
+
if (c.replace) step.replaceWith(at, at + c.find.length, schema.text(c.replace, step.doc.resolve(at + 1).marks()));
|
|
3308
|
+
else step.delete(at, at + c.find.length);
|
|
3309
|
+
}
|
|
3310
|
+
updateYFragment({ transact: (run) => doc.transact(run, origin) }, fragment, step.doc, { mapping: /* @__PURE__ */ new Map(), isOMark: /* @__PURE__ */ new Map() });
|
|
3311
|
+
return changes2.length;
|
|
3312
|
+
}
|
|
3313
|
+
async function write(kind, base, node, load2) {
|
|
3314
|
+
if (kind === "docx") return writeDocx(base, node.toJSON(), load2);
|
|
3315
|
+
const parsed = fromMarkdown(new TextDecoder().decode(base));
|
|
3316
|
+
return new TextEncoder().encode(toMarkdown(node, track(parsed, node.type.schema.nodeFromJSON(parsed.doc))).text).buffer;
|
|
3317
|
+
}
|
|
3318
|
+
var blocks2 = (fragment, schema) => {
|
|
3319
|
+
const out = [];
|
|
3320
|
+
const walk = (parent) => parent.toArray().forEach((child) => {
|
|
3321
|
+
if (!(child instanceof Y2.XmlElement) || !schema.nodes[child.nodeName]?.isBlock) return;
|
|
3322
|
+
out.push(child);
|
|
3323
|
+
walk(child);
|
|
3324
|
+
});
|
|
3325
|
+
walk(fragment);
|
|
3326
|
+
return out;
|
|
3327
|
+
};
|
|
3328
|
+
var same2 = (a, b) => {
|
|
3329
|
+
const [x, y] = [new Uint8Array(a), new Uint8Array(b)];
|
|
3330
|
+
return x.length === y.length && x.every((v, i) => v === y[i]);
|
|
3331
|
+
};
|
|
3332
|
+
var named = (label, who) => {
|
|
3333
|
+
const names = who.map((w) => w.name).join(", ");
|
|
3334
|
+
return `${label}: ${names.length > 180 ? `${names.slice(0, 177)}...` : names}`;
|
|
3335
|
+
};
|
|
3336
|
+
async function save(doc, kind, base, put, load2, note) {
|
|
3337
|
+
const editors = doc.getMap("editors");
|
|
3338
|
+
const who = [...editors.values()];
|
|
3339
|
+
if (!who.length) return null;
|
|
3340
|
+
if (kind === "xlsx" || kind === "csv") return workbook(doc, kind, base, put, who, note);
|
|
3341
|
+
const schema = schemaOf(kind);
|
|
3342
|
+
const fragment = doc.getXmlFragment("default");
|
|
3343
|
+
const list = blocks2(fragment, schema);
|
|
3344
|
+
const node = yXmlFragmentToProseMirrorRootNode(fragment, schema);
|
|
3345
|
+
let touched = false;
|
|
3346
|
+
const watch = (tr) => {
|
|
3347
|
+
touched || (touched = tr.origin !== ours && edits(tr));
|
|
3348
|
+
};
|
|
3349
|
+
doc.on("afterTransaction", watch);
|
|
3350
|
+
try {
|
|
3351
|
+
const bytes = await write(kind, base, node, load2);
|
|
3352
|
+
const changed2 = !same2(bytes, base);
|
|
3353
|
+
const id = changed2 ? await put(bytes, note ?? named((texts[who[0].language] ?? texts.en).editedNote, who)) : null;
|
|
3354
|
+
const refs = [];
|
|
3355
|
+
if (changed2) schema.nodeFromJSON(await parse2(kind, bytes)).descendants((n) => {
|
|
3356
|
+
if (n.isBlock) refs.push([n.type.name, n.attrs.ref ?? null]);
|
|
3357
|
+
});
|
|
3358
|
+
doc.transact(() => {
|
|
3359
|
+
if (refs.length === list.length && list.every((el, i) => el.nodeName === refs[i][0])) list.forEach((el, i) => {
|
|
3360
|
+
const ref = refs[i][1];
|
|
3361
|
+
if ((el.getAttribute("ref") ?? null) === ref) return;
|
|
3362
|
+
if (ref === null) el.removeAttribute("ref");
|
|
3363
|
+
else el.setAttribute("ref", ref);
|
|
3364
|
+
});
|
|
3365
|
+
if (id) doc.getMap("meta").set("version", id);
|
|
3366
|
+
if (!touched) who.forEach((w) => editors.delete(w.id));
|
|
3367
|
+
}, ours);
|
|
3368
|
+
return { bytes: changed2 ? bytes : base, version: id };
|
|
3369
|
+
} finally {
|
|
3370
|
+
doc.off("afterTransaction", watch);
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
async function workbook(doc, kind, base, put, who, note) {
|
|
3374
|
+
const editors = doc.getMap("editors");
|
|
3375
|
+
const model = build(doc);
|
|
3376
|
+
let touched = false;
|
|
3377
|
+
const watch = (tr) => {
|
|
3378
|
+
touched || (touched = tr.origin !== ours && edits(tr));
|
|
3379
|
+
};
|
|
3380
|
+
doc.on("afterTransaction", watch);
|
|
3381
|
+
try {
|
|
3382
|
+
const bytes = writeSheet(base, model, kind);
|
|
3383
|
+
const changed2 = !same2(bytes, base);
|
|
3384
|
+
const id = changed2 ? await put(bytes, note ?? named((sheetTexts[who[0].language] ?? sheetTexts.en).editedNote, who)) : null;
|
|
3385
|
+
doc.transact(() => {
|
|
3386
|
+
if (changed2) settle(doc, model, bytes, kind);
|
|
3387
|
+
if (id) doc.getMap("meta").set("version", id);
|
|
3388
|
+
if (!touched) who.forEach((w) => editors.delete(w.id));
|
|
3389
|
+
}, ours);
|
|
3390
|
+
return { bytes: changed2 ? bytes : base, version: id };
|
|
3391
|
+
} finally {
|
|
3392
|
+
doc.off("afterTransaction", watch);
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
export {
|
|
3397
|
+
a4,
|
|
3398
|
+
letter,
|
|
3399
|
+
paging,
|
|
3400
|
+
notes,
|
|
3401
|
+
entries,
|
|
3402
|
+
changes,
|
|
3403
|
+
decide,
|
|
3404
|
+
suggesting,
|
|
3405
|
+
kit,
|
|
3406
|
+
align,
|
|
3407
|
+
indent,
|
|
3408
|
+
clear,
|
|
3409
|
+
locate,
|
|
3410
|
+
fromMarkdown,
|
|
3411
|
+
track,
|
|
3412
|
+
toMarkdown,
|
|
3413
|
+
SheetRefusal,
|
|
3414
|
+
fresh,
|
|
3415
|
+
insert,
|
|
3416
|
+
move,
|
|
3417
|
+
resize,
|
|
3418
|
+
rebase,
|
|
3419
|
+
worksheets,
|
|
3420
|
+
readSheet,
|
|
3421
|
+
writeSheet,
|
|
3422
|
+
props,
|
|
3423
|
+
spot,
|
|
3424
|
+
canon,
|
|
3425
|
+
strip,
|
|
3426
|
+
fnv,
|
|
3427
|
+
parts,
|
|
3428
|
+
pieces,
|
|
3429
|
+
made,
|
|
3430
|
+
sheetOf,
|
|
3431
|
+
notesOf,
|
|
3432
|
+
build,
|
|
3433
|
+
extras,
|
|
3434
|
+
applyCells,
|
|
3435
|
+
sheetTexts,
|
|
3436
|
+
ours,
|
|
3437
|
+
parse2 as parse,
|
|
3438
|
+
edits,
|
|
3439
|
+
filled,
|
|
3440
|
+
seed,
|
|
3441
|
+
follow,
|
|
3442
|
+
pending,
|
|
3443
|
+
Refusal,
|
|
3444
|
+
applyText,
|
|
3445
|
+
save
|
|
3446
|
+
};
|
|
3447
|
+
//# sourceMappingURL=chunk-CE3AADY6.js.map
|