@pixerate/editor 0.18.0 → 0.20.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/README.md +91 -2
- package/dist/agent/index.cjs +625 -2
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +286 -2
- package/dist/agent/index.d.ts +286 -2
- package/dist/agent/index.js +624 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +1240 -22
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +515 -3
- package/dist/canvas/index.d.ts +515 -3
- package/dist/canvas/index.js +1219 -1
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-3TYMNULT.js +1367 -0
- package/dist/chunk-3TYMNULT.js.map +1 -0
- package/dist/chunk-4QPLEUL2.cjs +4480 -0
- package/dist/chunk-4QPLEUL2.cjs.map +1 -0
- package/dist/chunk-4SUNJZWB.cjs +553 -0
- package/dist/chunk-4SUNJZWB.cjs.map +1 -0
- package/dist/chunk-A7DKIA72.js +2657 -0
- package/dist/chunk-A7DKIA72.js.map +1 -0
- package/dist/chunk-AXV2ZW34.cjs +118 -0
- package/dist/chunk-AXV2ZW34.cjs.map +1 -0
- package/dist/chunk-B2ZRLN4S.js +118 -0
- package/dist/chunk-B2ZRLN4S.js.map +1 -0
- package/dist/chunk-CYFJCKC4.js +4480 -0
- package/dist/chunk-CYFJCKC4.js.map +1 -0
- package/dist/chunk-GVW4P7BG.js +2706 -0
- package/dist/chunk-GVW4P7BG.js.map +1 -0
- package/dist/chunk-JACER6TE.cjs +1 -0
- package/dist/chunk-JACER6TE.cjs.map +1 -0
- package/dist/chunk-JYRIOFEN.cjs +2657 -0
- package/dist/chunk-JYRIOFEN.cjs.map +1 -0
- package/dist/chunk-KYRZDWM4.js +299 -0
- package/dist/chunk-KYRZDWM4.js.map +1 -0
- package/dist/chunk-LA7PEGU3.cjs +299 -0
- package/dist/chunk-LA7PEGU3.cjs.map +1 -0
- package/dist/chunk-N7FG6CBO.js +1 -0
- package/dist/chunk-N7FG6CBO.js.map +1 -0
- package/dist/chunk-OYXSKQFR.js +553 -0
- package/dist/chunk-OYXSKQFR.js.map +1 -0
- package/dist/chunk-TVRC4KVT.cjs +1367 -0
- package/dist/chunk-TVRC4KVT.cjs.map +1 -0
- package/dist/chunk-U6NDQFOK.cjs +2706 -0
- package/dist/chunk-U6NDQFOK.cjs.map +1 -0
- package/dist/controller-OUdxPY-X.d.cts +754 -0
- package/dist/controller-OUdxPY-X.d.ts +754 -0
- package/dist/extensions/index.cjs +144 -3
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +9 -144
- package/dist/extensions/index.d.ts +9 -144
- package/dist/extensions/index.js +145 -4
- package/dist/grammar/index.cjs +31 -3
- package/dist/grammar/index.cjs.map +1 -1
- package/dist/grammar/index.d.cts +239 -19
- package/dist/grammar/index.d.ts +239 -19
- package/dist/grammar/index.js +31 -3
- package/dist/history/index.d.cts +2 -41
- package/dist/history/index.d.ts +2 -41
- package/dist/image-editor/index.cjs +732 -497
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +105 -9
- package/dist/image-editor/index.d.ts +105 -9
- package/dist/image-editor/index.js +721 -486
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index-Ng1pG7JE.d.ts +899 -0
- package/dist/index-k3mFbPx_.d.cts +899 -0
- package/dist/index.cjs +457 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -12
- package/dist/index.d.ts +99 -12
- package/dist/index.js +457 -20
- package/dist/index.js.map +1 -1
- package/dist/registry-iAHbqkYt.d.cts +128 -0
- package/dist/registry-iAHbqkYt.d.ts +128 -0
- package/dist/serializers/index.cjs +26 -3
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.d.cts +119 -6
- package/dist/serializers/index.d.ts +119 -6
- package/dist/serializers/index.js +24 -1
- package/dist/spreadsheet/index.cjs +122 -2
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +371 -313
- package/dist/spreadsheet/index.d.ts +371 -313
- package/dist/spreadsheet/index.js +127 -7
- package/dist/tokens-CyLZmIei.d.cts +76 -0
- package/dist/tokens-CyLZmIei.d.ts +76 -0
- package/dist/track-changes-G8JcWB8b.d.cts +306 -0
- package/dist/track-changes-G8JcWB8b.d.ts +306 -0
- package/dist/types-BZgcDsC5.d.cts +42 -0
- package/dist/types-BZgcDsC5.d.ts +42 -0
- package/dist/{types-JV3S8VeR.d.cts → types-DMe0vFB1.d.cts} +1 -1
- package/dist/{types-JV3S8VeR.d.ts → types-DMe0vFB1.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-7FWEWE6T.js +0 -1888
- package/dist/chunk-7FWEWE6T.js.map +0 -1
- package/dist/chunk-AIZUKWTL.js +0 -1715
- package/dist/chunk-AIZUKWTL.js.map +0 -1
- package/dist/chunk-GLSIZKOX.js +0 -17
- package/dist/chunk-GLSIZKOX.js.map +0 -1
- package/dist/chunk-LDES3EOS.cjs +0 -1888
- package/dist/chunk-LDES3EOS.cjs.map +0 -1
- package/dist/chunk-LLUAKTLW.cjs +0 -532
- package/dist/chunk-LLUAKTLW.cjs.map +0 -1
- package/dist/chunk-MPPXH7U5.cjs +0 -336
- package/dist/chunk-MPPXH7U5.cjs.map +0 -1
- package/dist/chunk-O7LOPQMH.js +0 -336
- package/dist/chunk-O7LOPQMH.js.map +0 -1
- package/dist/chunk-QGVMBCT5.js +0 -532
- package/dist/chunk-QGVMBCT5.js.map +0 -1
- package/dist/chunk-SEDR75VH.cjs +0 -17
- package/dist/chunk-SEDR75VH.cjs.map +0 -1
- package/dist/chunk-YQCI4CCN.cjs +0 -1715
- package/dist/chunk-YQCI4CCN.cjs.map +0 -1
- package/dist/mention-Dcevh3ff.d.cts +0 -32
- package/dist/mention-Dcevh3ff.d.ts +0 -32
- package/dist/tokens-7kRTEtPb.d.cts +0 -39
- package/dist/tokens-7kRTEtPb.d.ts +0 -39
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import {
|
|
2
|
+
escapeHtml,
|
|
3
|
+
sanitizeHtml
|
|
4
|
+
} from "./chunk-3TYMNULT.js";
|
|
5
|
+
|
|
6
|
+
// src/serializers/html.ts
|
|
7
|
+
var DROP_WITH_CONTENT_REGEX = /<(script|style|template|noscript|iframe|object|embed|head|title|svg|math|textarea|select|button)\b[^>]*>[\s\S]*?<\/\1\s*>/gi;
|
|
8
|
+
var UNCLOSED_RAW_TEXT_REGEX = /<(script|style)\b[^>]*>[\s\S]*$/i;
|
|
9
|
+
var BODY_REGEX = /<body\b[^>]*>([\s\S]*?)(?:<\/body\s*>|$)/i;
|
|
10
|
+
var NAMESPACED_TAG_REGEX = /<\/?[a-zA-Z][\w-]*:[\w-]+\b[^>]*>/g;
|
|
11
|
+
function sanitizeImportedHtml(html) {
|
|
12
|
+
if (!html) return "<p></p>";
|
|
13
|
+
let content = html.replace(/^/, "");
|
|
14
|
+
content = content.replace(/<!--[\s\S]*?(?:-->|$)/g, "").replace(/<!\[CDATA\[[\s\S]*?(?:\]\]>|$)/g, "").replace(/<![^>]*>/g, "").replace(/<\?[\s\S]*?(?:\?>|$)/g, "");
|
|
15
|
+
const body = BODY_REGEX.exec(content);
|
|
16
|
+
if (body) content = body[1];
|
|
17
|
+
content = content.replace(DROP_WITH_CONTENT_REGEX, "").replace(UNCLOSED_RAW_TEXT_REGEX, "").replace(NAMESPACED_TAG_REGEX, "");
|
|
18
|
+
const sanitized = sanitizeHtml(content, { disallowedTags: "strip" }).trim();
|
|
19
|
+
return sanitized || "<p></p>";
|
|
20
|
+
}
|
|
21
|
+
function plainTextToParagraphHtml(text) {
|
|
22
|
+
if (!text) return "<p></p>";
|
|
23
|
+
return text.replace(/\r\n?/g, "\n").split("\n").map((line) => `<p>${escapeHtml(line)}</p>`).join("");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/serializers/rtf.ts
|
|
27
|
+
var SKIPPED_DESTINATIONS = /* @__PURE__ */ new Set([
|
|
28
|
+
"author",
|
|
29
|
+
"bkmkend",
|
|
30
|
+
"bkmkstart",
|
|
31
|
+
"colortbl",
|
|
32
|
+
"comment",
|
|
33
|
+
"datastore",
|
|
34
|
+
"doccomm",
|
|
35
|
+
"falt",
|
|
36
|
+
"fldinst",
|
|
37
|
+
"filetbl",
|
|
38
|
+
"fonttbl",
|
|
39
|
+
"footer",
|
|
40
|
+
"footerf",
|
|
41
|
+
"footerl",
|
|
42
|
+
"footerr",
|
|
43
|
+
"footnote",
|
|
44
|
+
"generator",
|
|
45
|
+
"header",
|
|
46
|
+
"headerf",
|
|
47
|
+
"headerl",
|
|
48
|
+
"headerr",
|
|
49
|
+
"info",
|
|
50
|
+
"keywords",
|
|
51
|
+
"latentstyles",
|
|
52
|
+
"listoverridetable",
|
|
53
|
+
"listtable",
|
|
54
|
+
"nonshppict",
|
|
55
|
+
"object",
|
|
56
|
+
"operator",
|
|
57
|
+
"pict",
|
|
58
|
+
"private",
|
|
59
|
+
"revtbl",
|
|
60
|
+
"rsidtbl",
|
|
61
|
+
"shppict",
|
|
62
|
+
"stylesheet",
|
|
63
|
+
"subject",
|
|
64
|
+
"themedata",
|
|
65
|
+
"title",
|
|
66
|
+
"xmlnstbl",
|
|
67
|
+
"colorschememapping"
|
|
68
|
+
]);
|
|
69
|
+
var CONTROL_WORD_TEXT = {
|
|
70
|
+
par: "\n",
|
|
71
|
+
sect: "\n",
|
|
72
|
+
page: "\n",
|
|
73
|
+
line: "\n",
|
|
74
|
+
row: "\n",
|
|
75
|
+
cell: " ",
|
|
76
|
+
tab: " ",
|
|
77
|
+
emdash: "\u2014",
|
|
78
|
+
endash: "\u2013",
|
|
79
|
+
emspace: "\u2003",
|
|
80
|
+
enspace: "\u2002",
|
|
81
|
+
bullet: "\u2022",
|
|
82
|
+
lquote: "\u2018",
|
|
83
|
+
rquote: "\u2019",
|
|
84
|
+
ldblquote: "\u201C",
|
|
85
|
+
rdblquote: "\u201D"
|
|
86
|
+
};
|
|
87
|
+
var CP1252 = {
|
|
88
|
+
128: "\u20AC",
|
|
89
|
+
130: "\u201A",
|
|
90
|
+
131: "\u0192",
|
|
91
|
+
132: "\u201E",
|
|
92
|
+
133: "\u2026",
|
|
93
|
+
134: "\u2020",
|
|
94
|
+
135: "\u2021",
|
|
95
|
+
136: "\u02C6",
|
|
96
|
+
137: "\u2030",
|
|
97
|
+
138: "\u0160",
|
|
98
|
+
139: "\u2039",
|
|
99
|
+
140: "\u0152",
|
|
100
|
+
142: "\u017D",
|
|
101
|
+
145: "\u2018",
|
|
102
|
+
146: "\u2019",
|
|
103
|
+
147: "\u201C",
|
|
104
|
+
148: "\u201D",
|
|
105
|
+
149: "\u2022",
|
|
106
|
+
150: "\u2013",
|
|
107
|
+
151: "\u2014",
|
|
108
|
+
152: "\u02DC",
|
|
109
|
+
153: "\u2122",
|
|
110
|
+
154: "\u0161",
|
|
111
|
+
155: "\u203A",
|
|
112
|
+
156: "\u0153",
|
|
113
|
+
158: "\u017E",
|
|
114
|
+
159: "\u0178"
|
|
115
|
+
};
|
|
116
|
+
var CONTROL_WORD_REGEX = /\\([a-zA-Z]{1,32})(-?\d{1,10})? ?/y;
|
|
117
|
+
function rtfToPlainText(rtf) {
|
|
118
|
+
if (!rtf) return "";
|
|
119
|
+
if (!/^\s*\{\\rtf/.test(rtf)) return rtf;
|
|
120
|
+
let out = "";
|
|
121
|
+
const stack = [];
|
|
122
|
+
let skip = false;
|
|
123
|
+
let uc = 1;
|
|
124
|
+
let pendingFallback = 0;
|
|
125
|
+
let groupStart = false;
|
|
126
|
+
const emit = (text) => {
|
|
127
|
+
if (skip) return;
|
|
128
|
+
if (pendingFallback > 0) {
|
|
129
|
+
pendingFallback--;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
out += text;
|
|
133
|
+
};
|
|
134
|
+
let i = 0;
|
|
135
|
+
while (i < rtf.length) {
|
|
136
|
+
const ch = rtf[i];
|
|
137
|
+
if (ch === "{") {
|
|
138
|
+
stack.push({ skip, uc });
|
|
139
|
+
groupStart = true;
|
|
140
|
+
i++;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (ch === "}") {
|
|
144
|
+
const prev = stack.pop();
|
|
145
|
+
if (prev) {
|
|
146
|
+
skip = prev.skip;
|
|
147
|
+
uc = prev.uc;
|
|
148
|
+
}
|
|
149
|
+
pendingFallback = 0;
|
|
150
|
+
groupStart = false;
|
|
151
|
+
i++;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const atGroupStart = groupStart;
|
|
155
|
+
groupStart = false;
|
|
156
|
+
if (ch === "\\") {
|
|
157
|
+
const next = rtf[i + 1];
|
|
158
|
+
if (next === "\\" || next === "{" || next === "}") {
|
|
159
|
+
emit(next);
|
|
160
|
+
i += 2;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (next === "*") {
|
|
164
|
+
skip = true;
|
|
165
|
+
i += 2;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (next === "'") {
|
|
169
|
+
const code = parseInt(rtf.slice(i + 2, i + 4), 16);
|
|
170
|
+
if (!Number.isNaN(code)) emit(CP1252[code] ?? String.fromCharCode(code));
|
|
171
|
+
i += 4;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (next === "~") {
|
|
175
|
+
emit("\xA0");
|
|
176
|
+
i += 2;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (next === "_") {
|
|
180
|
+
emit("\u2011");
|
|
181
|
+
i += 2;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (next === "\n" || next === "\r") {
|
|
185
|
+
emit("\n");
|
|
186
|
+
i += 2;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
CONTROL_WORD_REGEX.lastIndex = i;
|
|
190
|
+
const match = CONTROL_WORD_REGEX.exec(rtf);
|
|
191
|
+
if (!match) {
|
|
192
|
+
i += 2;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
i = CONTROL_WORD_REGEX.lastIndex;
|
|
196
|
+
const word = match[1];
|
|
197
|
+
const param = match[2] !== void 0 ? parseInt(match[2], 10) : void 0;
|
|
198
|
+
if (atGroupStart && SKIPPED_DESTINATIONS.has(word)) {
|
|
199
|
+
skip = true;
|
|
200
|
+
} else if (word === "u" && param !== void 0) {
|
|
201
|
+
emit(String.fromCharCode(param < 0 ? param + 65536 : param));
|
|
202
|
+
if (!skip) pendingFallback = uc;
|
|
203
|
+
} else if (word === "uc" && param !== void 0) {
|
|
204
|
+
uc = param;
|
|
205
|
+
} else if (word === "bin" && param !== void 0) {
|
|
206
|
+
i += param;
|
|
207
|
+
} else if (CONTROL_WORD_TEXT[word] !== void 0) {
|
|
208
|
+
emit(CONTROL_WORD_TEXT[word]);
|
|
209
|
+
}
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (ch === "\n" || ch === "\r") {
|
|
213
|
+
i++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
emit(ch);
|
|
217
|
+
i++;
|
|
218
|
+
}
|
|
219
|
+
return out.replace(/\n+$/, "");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/serializers/clipboard.ts
|
|
223
|
+
import { Slice } from "@tiptap/pm/model";
|
|
224
|
+
var PIXERATE_DOCUMENT_MIME = "application/x.pixerate.document+json";
|
|
225
|
+
var signatureCache = /* @__PURE__ */ new WeakMap();
|
|
226
|
+
function fnv1a(text) {
|
|
227
|
+
let hash = 2166136261;
|
|
228
|
+
for (let i = 0; i < text.length; i++) {
|
|
229
|
+
hash ^= text.charCodeAt(i);
|
|
230
|
+
hash = Math.imul(hash, 16777619);
|
|
231
|
+
}
|
|
232
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
233
|
+
}
|
|
234
|
+
function getSchemaSignature(schema) {
|
|
235
|
+
const cached = signatureCache.get(schema);
|
|
236
|
+
if (cached) return cached;
|
|
237
|
+
const parts = [];
|
|
238
|
+
for (const [name, type] of Object.entries(schema.nodes)) {
|
|
239
|
+
const spec = type.spec;
|
|
240
|
+
parts.push(
|
|
241
|
+
`n:${name}|${spec.content ?? ""}|${spec.group ?? ""}|${spec.marks ?? ""}|${Object.keys(type.spec.attrs ?? {}).sort().join(",")}`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
for (const [name, type] of Object.entries(schema.marks)) {
|
|
245
|
+
parts.push(`m:${name}|${Object.keys(type.spec.attrs ?? {}).sort().join(",")}`);
|
|
246
|
+
}
|
|
247
|
+
const signature = `pm1-${fnv1a(parts.join(";"))}`;
|
|
248
|
+
signatureCache.set(schema, signature);
|
|
249
|
+
return signature;
|
|
250
|
+
}
|
|
251
|
+
function serializeRichClipboardPayload(slice, schema) {
|
|
252
|
+
const payload = {
|
|
253
|
+
version: 1,
|
|
254
|
+
schema: getSchemaSignature(schema),
|
|
255
|
+
slice: slice.toJSON()
|
|
256
|
+
};
|
|
257
|
+
return JSON.stringify(payload);
|
|
258
|
+
}
|
|
259
|
+
function parseRichClipboardPayload(data, schema) {
|
|
260
|
+
if (!data) return null;
|
|
261
|
+
try {
|
|
262
|
+
const payload = JSON.parse(data);
|
|
263
|
+
if (!payload || payload.version !== 1) return null;
|
|
264
|
+
if (payload.schema !== getSchemaSignature(schema)) return null;
|
|
265
|
+
if (!payload.slice) return null;
|
|
266
|
+
return Slice.fromJSON(schema, payload.slice);
|
|
267
|
+
} catch {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function getClipboardData(event) {
|
|
272
|
+
if (!event || typeof event !== "object") return null;
|
|
273
|
+
const native = "nativeEvent" in event ? event.nativeEvent : event;
|
|
274
|
+
return event.clipboardData ?? native?.clipboardData ?? null;
|
|
275
|
+
}
|
|
276
|
+
function readRichClipboard(event, schema, mimeType = PIXERATE_DOCUMENT_MIME) {
|
|
277
|
+
const data = getClipboardData(event);
|
|
278
|
+
if (!data) return null;
|
|
279
|
+
let raw;
|
|
280
|
+
try {
|
|
281
|
+
raw = data.getData(mimeType);
|
|
282
|
+
} catch {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
return parseRichClipboardPayload(raw, schema);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export {
|
|
289
|
+
sanitizeImportedHtml,
|
|
290
|
+
plainTextToParagraphHtml,
|
|
291
|
+
rtfToPlainText,
|
|
292
|
+
PIXERATE_DOCUMENT_MIME,
|
|
293
|
+
getSchemaSignature,
|
|
294
|
+
serializeRichClipboardPayload,
|
|
295
|
+
parseRichClipboardPayload,
|
|
296
|
+
getClipboardData,
|
|
297
|
+
readRichClipboard
|
|
298
|
+
};
|
|
299
|
+
//# sourceMappingURL=chunk-KYRZDWM4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/serializers/html.ts","../src/serializers/rtf.ts","../src/serializers/clipboard.ts"],"sourcesContent":["import { sanitizeHtml } from \"./markdown\";\nimport { escapeHtml } from \"./plain-text\";\n\n/**\n * Elements whose content is never document text (scripts, styles, metadata,\n * embedded objects, form controls). They are removed together with their\n * content before sanitizing, so e.g. CSS rules don't show up as paragraphs.\n */\nconst DROP_WITH_CONTENT_REGEX =\n /<(script|style|template|noscript|iframe|object|embed|head|title|svg|math|textarea|select|button)\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>/gi;\n/** An unclosed `<script>` / `<style>` swallows the rest of the document. */\nconst UNCLOSED_RAW_TEXT_REGEX = /<(script|style)\\b[^>]*>[\\s\\S]*$/i;\nconst BODY_REGEX = /<body\\b[^>]*>([\\s\\S]*?)(?:<\\/body\\s*>|$)/i;\n/** Namespaced tags such as Word's `<o:p>`, which the sanitizer cannot parse. */\nconst NAMESPACED_TAG_REGEX = /<\\/?[a-zA-Z][\\w-]*:[\\w-]+\\b[^>]*>/g;\n\n/**\n * Sanitizes a full HTML document or fragment for insertion into the editor,\n * e.g. an imported `.html` file or HTML from another application.\n *\n * - Keeps only the `<body>` content when the input is a full document.\n * - Removes comments, doctype/XML declarations, CDATA, scripts, styles and\n * other non-text elements together with their content.\n * - Applies the same tag/attribute/URL allowlist as embedded HTML in markdown\n * (see `sanitizeHtml`), but strips disallowed tags instead of escaping them,\n * so wrappers such as `<section>` or `<font>` keep their text.\n *\n * It is string-based (no live DOM), so handlers such as `<img onerror>` never run.\n */\nexport function sanitizeImportedHtml(html: string): string {\n if (!html) return \"<p></p>\";\n let content = html.replace(/^/, \"\");\n content = content\n .replace(/<!--[\\s\\S]*?(?:-->|$)/g, \"\")\n .replace(/<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>|$)/g, \"\")\n .replace(/<![^>]*>/g, \"\")\n .replace(/<\\?[\\s\\S]*?(?:\\?>|$)/g, \"\");\n const body = BODY_REGEX.exec(content);\n if (body) content = body[1];\n content = content\n .replace(DROP_WITH_CONTENT_REGEX, \"\")\n .replace(UNCLOSED_RAW_TEXT_REGEX, \"\")\n .replace(NAMESPACED_TAG_REGEX, \"\");\n const sanitized = sanitizeHtml(content, { disallowedTags: \"strip\" }).trim();\n return sanitized || \"<p></p>\";\n}\n\n/**\n * Converts untrusted plain text to TipTap paragraph HTML, always escaping it.\n *\n * Unlike `plainTextToTipTapHtml`, text that already looks like `<p>…</p>` is\n * not passed through as HTML, which matters for imported files.\n */\nexport function plainTextToParagraphHtml(text: string): string {\n if (!text) return \"<p></p>\";\n return text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n","/**\n * Destinations whose content is metadata or binary data rather than document\n * text. A group starting with one of these control words (or with `\\*`) is\n * skipped entirely.\n */\nconst SKIPPED_DESTINATIONS = new Set([\n \"author\", \"bkmkend\", \"bkmkstart\", \"colortbl\", \"comment\", \"datastore\",\n \"doccomm\", \"falt\", \"fldinst\", \"filetbl\", \"fonttbl\", \"footer\", \"footerf\",\n \"footerl\", \"footerr\", \"footnote\", \"generator\", \"header\", \"headerf\",\n \"headerl\", \"headerr\", \"info\", \"keywords\", \"latentstyles\", \"listoverridetable\",\n \"listtable\", \"nonshppict\", \"object\", \"operator\", \"pict\", \"private\", \"revtbl\",\n \"rsidtbl\", \"shppict\", \"stylesheet\", \"subject\", \"themedata\", \"title\",\n \"xmlnstbl\", \"colorschememapping\",\n]);\n\n/** Control words that map to a literal character. */\nconst CONTROL_WORD_TEXT: Record<string, string> = {\n par: \"\\n\",\n sect: \"\\n\",\n page: \"\\n\",\n line: \"\\n\",\n row: \"\\n\",\n cell: \"\\t\",\n tab: \"\\t\",\n emdash: \"—\",\n endash: \"–\",\n emspace: \" \",\n enspace: \" \",\n bullet: \"•\",\n lquote: \"‘\",\n rquote: \"’\",\n ldblquote: \"“\",\n rdblquote: \"”\",\n};\n\n/** Windows-1252 code points in 0x80–0x9F that differ from Latin-1. */\nconst CP1252: Record<number, string> = {\n 0x80: \"€\", 0x82: \"‚\", 0x83: \"ƒ\", 0x84: \"„\", 0x85: \"…\",\n 0x86: \"†\", 0x87: \"‡\", 0x88: \"ˆ\", 0x89: \"‰\", 0x8a: \"Š\",\n 0x8b: \"‹\", 0x8c: \"Œ\", 0x8e: \"Ž\", 0x91: \"‘\", 0x92: \"’\",\n 0x93: \"“\", 0x94: \"”\", 0x95: \"•\", 0x96: \"–\", 0x97: \"—\",\n 0x98: \"˜\", 0x99: \"™\", 0x9a: \"š\", 0x9b: \"›\", 0x9c: \"œ\",\n 0x9e: \"ž\", 0x9f: \"Ÿ\",\n};\n\nconst CONTROL_WORD_REGEX = /\\\\([a-zA-Z]{1,32})(-?\\d{1,10})? ?/y;\n\n/**\n * Best-effort plain-text extraction from an RTF document.\n *\n * Handles paragraphs/line breaks/tabs, escaped braces and backslashes,\n * `\\'hh` hex escapes (decoded as Windows-1252), `\\uN` Unicode escapes with\n * their `\\ucN` fallback characters, common typographic control words, and\n * skips metadata destinations (font/colour tables, `\\info`, pictures, field\n * instructions, `\\*` destinations). Formatting (bold, lists, tables) is not\n * preserved. Input that does not start with `{\\rtf` is returned unchanged.\n */\nexport function rtfToPlainText(rtf: string): string {\n if (!rtf) return \"\";\n if (!/^\\s*\\{\\\\rtf/.test(rtf)) return rtf;\n\n let out = \"\";\n const stack: Array<{ skip: boolean; uc: number }> = [];\n let skip = false;\n // Number of fallback characters that follow a \\uN escape.\n let uc = 1;\n let pendingFallback = 0;\n // True right after `{`, so a destination control word can mark the group.\n let groupStart = false;\n\n const emit = (text: string) => {\n if (skip) return;\n if (pendingFallback > 0) {\n pendingFallback--;\n return;\n }\n out += text;\n };\n\n let i = 0;\n while (i < rtf.length) {\n const ch = rtf[i];\n if (ch === \"{\") {\n stack.push({ skip, uc });\n groupStart = true;\n i++;\n continue;\n }\n if (ch === \"}\") {\n const prev = stack.pop();\n if (prev) {\n skip = prev.skip;\n uc = prev.uc;\n }\n pendingFallback = 0;\n groupStart = false;\n i++;\n continue;\n }\n const atGroupStart = groupStart;\n groupStart = false;\n\n if (ch === \"\\\\\") {\n const next = rtf[i + 1];\n if (next === \"\\\\\" || next === \"{\" || next === \"}\") {\n emit(next);\n i += 2;\n continue;\n }\n if (next === \"*\") {\n // `{\\*\\dest …}`: an ignorable destination this reader doesn't know.\n skip = true;\n i += 2;\n continue;\n }\n if (next === \"'\") {\n const code = parseInt(rtf.slice(i + 2, i + 4), 16);\n if (!Number.isNaN(code)) emit(CP1252[code] ?? String.fromCharCode(code));\n i += 4;\n continue;\n }\n if (next === \"~\") {\n emit(\" \");\n i += 2;\n continue;\n }\n if (next === \"_\") {\n emit(\"‑\");\n i += 2;\n continue;\n }\n if (next === \"\\n\" || next === \"\\r\") {\n emit(\"\\n\");\n i += 2;\n continue;\n }\n CONTROL_WORD_REGEX.lastIndex = i;\n const match = CONTROL_WORD_REGEX.exec(rtf);\n if (!match) {\n // Other control symbols (`\\-`, `\\|`, `\\:`) produce no text.\n i += 2;\n continue;\n }\n i = CONTROL_WORD_REGEX.lastIndex;\n const word = match[1];\n const param = match[2] !== undefined ? parseInt(match[2], 10) : undefined;\n if (atGroupStart && SKIPPED_DESTINATIONS.has(word)) {\n skip = true;\n } else if (word === \"u\" && param !== undefined) {\n emit(String.fromCharCode(param < 0 ? param + 65536 : param));\n if (!skip) pendingFallback = uc;\n } else if (word === \"uc\" && param !== undefined) {\n uc = param;\n } else if (word === \"bin\" && param !== undefined) {\n // Raw binary data: skip it.\n i += param;\n } else if (CONTROL_WORD_TEXT[word] !== undefined) {\n emit(CONTROL_WORD_TEXT[word]);\n }\n continue;\n }\n // Raw newlines are formatting in RTF; only control words break lines.\n if (ch === \"\\n\" || ch === \"\\r\") {\n i++;\n continue;\n }\n emit(ch);\n i++;\n }\n\n return out.replace(/\\n+$/, \"\");\n}\n","import { Slice, type Schema } from \"@tiptap/pm/model\";\n\n/**\n * Custom clipboard MIME type for content copied from a @pixerate/editor\n * rich-text editor. It carries the ProseMirror slice as JSON so pasting back\n * into a compatible editor is lossless (no HTML round trip).\n */\nexport const PIXERATE_DOCUMENT_MIME = \"application/x.pixerate.document+json\";\n\n/** Payload written under {@link PIXERATE_DOCUMENT_MIME}. */\nexport interface RichClipboardPayload {\n version: 1;\n /** {@link getSchemaSignature} of the source editor's schema. */\n schema: string;\n /** `Slice.toJSON()` of the copied selection. */\n slice: { content?: unknown[]; openStart?: number; openEnd?: number } | null;\n}\n\nconst signatureCache = new WeakMap<Schema, string>();\n\n/** 32-bit FNV-1a, enough to tell schemas apart without a crypto dependency. */\nfunction fnv1a(text: string): string {\n let hash = 0x811c9dc5;\n for (let i = 0; i < text.length; i++) {\n hash ^= text.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Returns a stable signature for a ProseMirror schema: node names, content\n * expressions, groups, attribute names and mark names. Two editors with the\n * same extensions produce the same signature, so a slice copied from one can\n * be deserialized in the other without losing or rejecting nodes.\n */\nexport function getSchemaSignature(schema: Schema): string {\n const cached = signatureCache.get(schema);\n if (cached) return cached;\n const parts: string[] = [];\n for (const [name, type] of Object.entries(schema.nodes)) {\n const spec = type.spec;\n parts.push(\n `n:${name}|${spec.content ?? \"\"}|${spec.group ?? \"\"}|${spec.marks ?? \"\"}|${Object.keys(type.spec.attrs ?? {}).sort().join(\",\")}`,\n );\n }\n for (const [name, type] of Object.entries(schema.marks)) {\n parts.push(`m:${name}|${Object.keys(type.spec.attrs ?? {}).sort().join(\",\")}`);\n }\n const signature = `pm1-${fnv1a(parts.join(\";\"))}`;\n signatureCache.set(schema, signature);\n return signature;\n}\n\n/** Serializes a slice into the {@link PIXERATE_DOCUMENT_MIME} payload string. */\nexport function serializeRichClipboardPayload(slice: Slice, schema: Schema): string {\n const payload: RichClipboardPayload = {\n version: 1,\n schema: getSchemaSignature(schema),\n slice: slice.toJSON(),\n };\n return JSON.stringify(payload);\n}\n\n/**\n * Parses a {@link PIXERATE_DOCUMENT_MIME} payload into a slice for `schema`.\n * Returns `null` (so callers fall back to HTML / plain text) when the payload\n * is malformed, from another payload version, or from an editor whose schema\n * signature differs.\n */\nexport function parseRichClipboardPayload(data: string | null | undefined, schema: Schema): Slice | null {\n if (!data) return null;\n try {\n const payload = JSON.parse(data) as Partial<RichClipboardPayload>;\n if (!payload || payload.version !== 1) return null;\n if (payload.schema !== getSchemaSignature(schema)) return null;\n if (!payload.slice) return null;\n return Slice.fromJSON(schema, payload.slice as any);\n } catch {\n return null;\n }\n}\n\n/** Minimal clipboard data surface (`DataTransfer`). */\nexport interface ClipboardDataLike {\n getData(format: string): string;\n setData(format: string, data: string): void;\n clearData?(format?: string): void;\n}\n\n/**\n * Returns the `clipboardData` of a native `ClipboardEvent` or of a React\n * synthetic clipboard event (which wraps the native event in `nativeEvent`).\n */\nexport function getClipboardData(event: unknown): ClipboardDataLike | null {\n if (!event || typeof event !== \"object\") return null;\n const native = \"nativeEvent\" in event ? (event as any).nativeEvent : event;\n return ((event as any).clipboardData ?? native?.clipboardData ?? null) as ClipboardDataLike | null;\n}\n\n/**\n * Reads a slice from a paste event's {@link PIXERATE_DOCUMENT_MIME} data.\n * Returns `null` when the data is missing or its schema does not match.\n */\nexport function readRichClipboard(\n event: unknown,\n schema: Schema,\n mimeType: string = PIXERATE_DOCUMENT_MIME,\n): Slice | null {\n const data = getClipboardData(event);\n if (!data) return null;\n let raw: string | undefined;\n try {\n raw = data.getData(mimeType);\n } catch {\n return null;\n }\n return parseRichClipboardPayload(raw, schema);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkTVRC4KVTcjs = require('./chunk-TVRC4KVT.cjs');
|
|
5
|
+
|
|
6
|
+
// src/serializers/html.ts
|
|
7
|
+
var DROP_WITH_CONTENT_REGEX = /<(script|style|template|noscript|iframe|object|embed|head|title|svg|math|textarea|select|button)\b[^>]*>[\s\S]*?<\/\1\s*>/gi;
|
|
8
|
+
var UNCLOSED_RAW_TEXT_REGEX = /<(script|style)\b[^>]*>[\s\S]*$/i;
|
|
9
|
+
var BODY_REGEX = /<body\b[^>]*>([\s\S]*?)(?:<\/body\s*>|$)/i;
|
|
10
|
+
var NAMESPACED_TAG_REGEX = /<\/?[a-zA-Z][\w-]*:[\w-]+\b[^>]*>/g;
|
|
11
|
+
function sanitizeImportedHtml(html) {
|
|
12
|
+
if (!html) return "<p></p>";
|
|
13
|
+
let content = html.replace(/^/, "");
|
|
14
|
+
content = content.replace(/<!--[\s\S]*?(?:-->|$)/g, "").replace(/<!\[CDATA\[[\s\S]*?(?:\]\]>|$)/g, "").replace(/<![^>]*>/g, "").replace(/<\?[\s\S]*?(?:\?>|$)/g, "");
|
|
15
|
+
const body = BODY_REGEX.exec(content);
|
|
16
|
+
if (body) content = body[1];
|
|
17
|
+
content = content.replace(DROP_WITH_CONTENT_REGEX, "").replace(UNCLOSED_RAW_TEXT_REGEX, "").replace(NAMESPACED_TAG_REGEX, "");
|
|
18
|
+
const sanitized = _chunkTVRC4KVTcjs.sanitizeHtml.call(void 0, content, { disallowedTags: "strip" }).trim();
|
|
19
|
+
return sanitized || "<p></p>";
|
|
20
|
+
}
|
|
21
|
+
function plainTextToParagraphHtml(text) {
|
|
22
|
+
if (!text) return "<p></p>";
|
|
23
|
+
return text.replace(/\r\n?/g, "\n").split("\n").map((line) => `<p>${_chunkTVRC4KVTcjs.escapeHtml.call(void 0, line)}</p>`).join("");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/serializers/rtf.ts
|
|
27
|
+
var SKIPPED_DESTINATIONS = /* @__PURE__ */ new Set([
|
|
28
|
+
"author",
|
|
29
|
+
"bkmkend",
|
|
30
|
+
"bkmkstart",
|
|
31
|
+
"colortbl",
|
|
32
|
+
"comment",
|
|
33
|
+
"datastore",
|
|
34
|
+
"doccomm",
|
|
35
|
+
"falt",
|
|
36
|
+
"fldinst",
|
|
37
|
+
"filetbl",
|
|
38
|
+
"fonttbl",
|
|
39
|
+
"footer",
|
|
40
|
+
"footerf",
|
|
41
|
+
"footerl",
|
|
42
|
+
"footerr",
|
|
43
|
+
"footnote",
|
|
44
|
+
"generator",
|
|
45
|
+
"header",
|
|
46
|
+
"headerf",
|
|
47
|
+
"headerl",
|
|
48
|
+
"headerr",
|
|
49
|
+
"info",
|
|
50
|
+
"keywords",
|
|
51
|
+
"latentstyles",
|
|
52
|
+
"listoverridetable",
|
|
53
|
+
"listtable",
|
|
54
|
+
"nonshppict",
|
|
55
|
+
"object",
|
|
56
|
+
"operator",
|
|
57
|
+
"pict",
|
|
58
|
+
"private",
|
|
59
|
+
"revtbl",
|
|
60
|
+
"rsidtbl",
|
|
61
|
+
"shppict",
|
|
62
|
+
"stylesheet",
|
|
63
|
+
"subject",
|
|
64
|
+
"themedata",
|
|
65
|
+
"title",
|
|
66
|
+
"xmlnstbl",
|
|
67
|
+
"colorschememapping"
|
|
68
|
+
]);
|
|
69
|
+
var CONTROL_WORD_TEXT = {
|
|
70
|
+
par: "\n",
|
|
71
|
+
sect: "\n",
|
|
72
|
+
page: "\n",
|
|
73
|
+
line: "\n",
|
|
74
|
+
row: "\n",
|
|
75
|
+
cell: " ",
|
|
76
|
+
tab: " ",
|
|
77
|
+
emdash: "\u2014",
|
|
78
|
+
endash: "\u2013",
|
|
79
|
+
emspace: "\u2003",
|
|
80
|
+
enspace: "\u2002",
|
|
81
|
+
bullet: "\u2022",
|
|
82
|
+
lquote: "\u2018",
|
|
83
|
+
rquote: "\u2019",
|
|
84
|
+
ldblquote: "\u201C",
|
|
85
|
+
rdblquote: "\u201D"
|
|
86
|
+
};
|
|
87
|
+
var CP1252 = {
|
|
88
|
+
128: "\u20AC",
|
|
89
|
+
130: "\u201A",
|
|
90
|
+
131: "\u0192",
|
|
91
|
+
132: "\u201E",
|
|
92
|
+
133: "\u2026",
|
|
93
|
+
134: "\u2020",
|
|
94
|
+
135: "\u2021",
|
|
95
|
+
136: "\u02C6",
|
|
96
|
+
137: "\u2030",
|
|
97
|
+
138: "\u0160",
|
|
98
|
+
139: "\u2039",
|
|
99
|
+
140: "\u0152",
|
|
100
|
+
142: "\u017D",
|
|
101
|
+
145: "\u2018",
|
|
102
|
+
146: "\u2019",
|
|
103
|
+
147: "\u201C",
|
|
104
|
+
148: "\u201D",
|
|
105
|
+
149: "\u2022",
|
|
106
|
+
150: "\u2013",
|
|
107
|
+
151: "\u2014",
|
|
108
|
+
152: "\u02DC",
|
|
109
|
+
153: "\u2122",
|
|
110
|
+
154: "\u0161",
|
|
111
|
+
155: "\u203A",
|
|
112
|
+
156: "\u0153",
|
|
113
|
+
158: "\u017E",
|
|
114
|
+
159: "\u0178"
|
|
115
|
+
};
|
|
116
|
+
var CONTROL_WORD_REGEX = /\\([a-zA-Z]{1,32})(-?\d{1,10})? ?/y;
|
|
117
|
+
function rtfToPlainText(rtf) {
|
|
118
|
+
if (!rtf) return "";
|
|
119
|
+
if (!/^\s*\{\\rtf/.test(rtf)) return rtf;
|
|
120
|
+
let out = "";
|
|
121
|
+
const stack = [];
|
|
122
|
+
let skip = false;
|
|
123
|
+
let uc = 1;
|
|
124
|
+
let pendingFallback = 0;
|
|
125
|
+
let groupStart = false;
|
|
126
|
+
const emit = (text) => {
|
|
127
|
+
if (skip) return;
|
|
128
|
+
if (pendingFallback > 0) {
|
|
129
|
+
pendingFallback--;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
out += text;
|
|
133
|
+
};
|
|
134
|
+
let i = 0;
|
|
135
|
+
while (i < rtf.length) {
|
|
136
|
+
const ch = rtf[i];
|
|
137
|
+
if (ch === "{") {
|
|
138
|
+
stack.push({ skip, uc });
|
|
139
|
+
groupStart = true;
|
|
140
|
+
i++;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (ch === "}") {
|
|
144
|
+
const prev = stack.pop();
|
|
145
|
+
if (prev) {
|
|
146
|
+
skip = prev.skip;
|
|
147
|
+
uc = prev.uc;
|
|
148
|
+
}
|
|
149
|
+
pendingFallback = 0;
|
|
150
|
+
groupStart = false;
|
|
151
|
+
i++;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const atGroupStart = groupStart;
|
|
155
|
+
groupStart = false;
|
|
156
|
+
if (ch === "\\") {
|
|
157
|
+
const next = rtf[i + 1];
|
|
158
|
+
if (next === "\\" || next === "{" || next === "}") {
|
|
159
|
+
emit(next);
|
|
160
|
+
i += 2;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (next === "*") {
|
|
164
|
+
skip = true;
|
|
165
|
+
i += 2;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (next === "'") {
|
|
169
|
+
const code = parseInt(rtf.slice(i + 2, i + 4), 16);
|
|
170
|
+
if (!Number.isNaN(code)) emit(_nullishCoalesce(CP1252[code], () => ( String.fromCharCode(code))));
|
|
171
|
+
i += 4;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (next === "~") {
|
|
175
|
+
emit("\xA0");
|
|
176
|
+
i += 2;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (next === "_") {
|
|
180
|
+
emit("\u2011");
|
|
181
|
+
i += 2;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (next === "\n" || next === "\r") {
|
|
185
|
+
emit("\n");
|
|
186
|
+
i += 2;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
CONTROL_WORD_REGEX.lastIndex = i;
|
|
190
|
+
const match = CONTROL_WORD_REGEX.exec(rtf);
|
|
191
|
+
if (!match) {
|
|
192
|
+
i += 2;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
i = CONTROL_WORD_REGEX.lastIndex;
|
|
196
|
+
const word = match[1];
|
|
197
|
+
const param = match[2] !== void 0 ? parseInt(match[2], 10) : void 0;
|
|
198
|
+
if (atGroupStart && SKIPPED_DESTINATIONS.has(word)) {
|
|
199
|
+
skip = true;
|
|
200
|
+
} else if (word === "u" && param !== void 0) {
|
|
201
|
+
emit(String.fromCharCode(param < 0 ? param + 65536 : param));
|
|
202
|
+
if (!skip) pendingFallback = uc;
|
|
203
|
+
} else if (word === "uc" && param !== void 0) {
|
|
204
|
+
uc = param;
|
|
205
|
+
} else if (word === "bin" && param !== void 0) {
|
|
206
|
+
i += param;
|
|
207
|
+
} else if (CONTROL_WORD_TEXT[word] !== void 0) {
|
|
208
|
+
emit(CONTROL_WORD_TEXT[word]);
|
|
209
|
+
}
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (ch === "\n" || ch === "\r") {
|
|
213
|
+
i++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
emit(ch);
|
|
217
|
+
i++;
|
|
218
|
+
}
|
|
219
|
+
return out.replace(/\n+$/, "");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/serializers/clipboard.ts
|
|
223
|
+
var _model = require('@tiptap/pm/model');
|
|
224
|
+
var PIXERATE_DOCUMENT_MIME = "application/x.pixerate.document+json";
|
|
225
|
+
var signatureCache = /* @__PURE__ */ new WeakMap();
|
|
226
|
+
function fnv1a(text) {
|
|
227
|
+
let hash = 2166136261;
|
|
228
|
+
for (let i = 0; i < text.length; i++) {
|
|
229
|
+
hash ^= text.charCodeAt(i);
|
|
230
|
+
hash = Math.imul(hash, 16777619);
|
|
231
|
+
}
|
|
232
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
233
|
+
}
|
|
234
|
+
function getSchemaSignature(schema) {
|
|
235
|
+
const cached = signatureCache.get(schema);
|
|
236
|
+
if (cached) return cached;
|
|
237
|
+
const parts = [];
|
|
238
|
+
for (const [name, type] of Object.entries(schema.nodes)) {
|
|
239
|
+
const spec = type.spec;
|
|
240
|
+
parts.push(
|
|
241
|
+
`n:${name}|${_nullishCoalesce(spec.content, () => ( ""))}|${_nullishCoalesce(spec.group, () => ( ""))}|${_nullishCoalesce(spec.marks, () => ( ""))}|${Object.keys(_nullishCoalesce(type.spec.attrs, () => ( {}))).sort().join(",")}`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
for (const [name, type] of Object.entries(schema.marks)) {
|
|
245
|
+
parts.push(`m:${name}|${Object.keys(_nullishCoalesce(type.spec.attrs, () => ( {}))).sort().join(",")}`);
|
|
246
|
+
}
|
|
247
|
+
const signature = `pm1-${fnv1a(parts.join(";"))}`;
|
|
248
|
+
signatureCache.set(schema, signature);
|
|
249
|
+
return signature;
|
|
250
|
+
}
|
|
251
|
+
function serializeRichClipboardPayload(slice, schema) {
|
|
252
|
+
const payload = {
|
|
253
|
+
version: 1,
|
|
254
|
+
schema: getSchemaSignature(schema),
|
|
255
|
+
slice: slice.toJSON()
|
|
256
|
+
};
|
|
257
|
+
return JSON.stringify(payload);
|
|
258
|
+
}
|
|
259
|
+
function parseRichClipboardPayload(data, schema) {
|
|
260
|
+
if (!data) return null;
|
|
261
|
+
try {
|
|
262
|
+
const payload = JSON.parse(data);
|
|
263
|
+
if (!payload || payload.version !== 1) return null;
|
|
264
|
+
if (payload.schema !== getSchemaSignature(schema)) return null;
|
|
265
|
+
if (!payload.slice) return null;
|
|
266
|
+
return _model.Slice.fromJSON(schema, payload.slice);
|
|
267
|
+
} catch (e) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function getClipboardData(event) {
|
|
272
|
+
if (!event || typeof event !== "object") return null;
|
|
273
|
+
const native = "nativeEvent" in event ? event.nativeEvent : event;
|
|
274
|
+
return _nullishCoalesce(_nullishCoalesce(event.clipboardData, () => ( _optionalChain([native, 'optionalAccess', _ => _.clipboardData]))), () => ( null));
|
|
275
|
+
}
|
|
276
|
+
function readRichClipboard(event, schema, mimeType = PIXERATE_DOCUMENT_MIME) {
|
|
277
|
+
const data = getClipboardData(event);
|
|
278
|
+
if (!data) return null;
|
|
279
|
+
let raw;
|
|
280
|
+
try {
|
|
281
|
+
raw = data.getData(mimeType);
|
|
282
|
+
} catch (e2) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
return parseRichClipboardPayload(raw, schema);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
exports.sanitizeImportedHtml = sanitizeImportedHtml; exports.plainTextToParagraphHtml = plainTextToParagraphHtml; exports.rtfToPlainText = rtfToPlainText; exports.PIXERATE_DOCUMENT_MIME = PIXERATE_DOCUMENT_MIME; exports.getSchemaSignature = getSchemaSignature; exports.serializeRichClipboardPayload = serializeRichClipboardPayload; exports.parseRichClipboardPayload = parseRichClipboardPayload; exports.getClipboardData = getClipboardData; exports.readRichClipboard = readRichClipboard;
|
|
299
|
+
//# sourceMappingURL=chunk-LA7PEGU3.cjs.map
|