@kedataindo/docflow-core 0.0.2 → 0.0.4
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/LICENSE +44 -0
- package/dist/index.cjs +1519 -28
- package/dist/index.d.cts +337 -1
- package/dist/index.d.ts +337 -1
- package/dist/index.js +1499 -21
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/Editor.ts
|
|
2
|
-
import { Editor as TiptapEditor
|
|
2
|
+
import { Extension as Extension5, Editor as TiptapEditor } from "@tiptap/core";
|
|
3
|
+
import { Plugin as Plugin4, PluginKey as PluginKey4 } from "@tiptap/pm/state";
|
|
3
4
|
import StarterKit from "@tiptap/starter-kit";
|
|
4
5
|
import TextStyle from "@tiptap/extension-text-style";
|
|
5
|
-
import { prosemirrorJSONToYXmlFragment } from "y-prosemirror";
|
|
6
6
|
|
|
7
7
|
// src/PluginSystem.ts
|
|
8
8
|
function definePlugin(plugin) {
|
|
@@ -55,9 +55,23 @@ function createActionMap(editor, plugins) {
|
|
|
55
55
|
import { Collaboration } from "@tiptap/extension-collaboration";
|
|
56
56
|
import { CollaborationCursor } from "@tiptap/extension-collaboration-cursor";
|
|
57
57
|
import { Awareness } from "y-protocols/awareness";
|
|
58
|
+
import { IndexeddbPersistence } from "y-indexeddb";
|
|
58
59
|
import { WebrtcProvider } from "y-webrtc";
|
|
59
60
|
import { WebsocketProvider } from "y-websocket";
|
|
60
61
|
import * as Y from "yjs";
|
|
62
|
+
var LOCAL_SIGNALING = ["ws://localhost:4444"];
|
|
63
|
+
var warnedLocalSignaling = false;
|
|
64
|
+
function resolveSignalingUrls(signaling) {
|
|
65
|
+
if (signaling && signaling.length > 0) return signaling;
|
|
66
|
+
if (!warnedLocalSignaling) {
|
|
67
|
+
warnedLocalSignaling = true;
|
|
68
|
+
console.warn(
|
|
69
|
+
'[docflow] webrtc provider has no `signaling` configured \u2014 falling back to localhost-only sync (ws://localhost:4444 + same-browser tabs). For production self-host, run your own signaling server and pass `signaling`, or use `provider: "websocket"` with your own websocketUrl.'
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return LOCAL_SIGNALING;
|
|
73
|
+
}
|
|
74
|
+
var LOCAL_PRESENT_DEFAULT = true;
|
|
61
75
|
function createAwarenessStates(awareness) {
|
|
62
76
|
const states = [];
|
|
63
77
|
awareness.getStates().forEach((state, clientId) => {
|
|
@@ -65,7 +79,11 @@ function createAwarenessStates(awareness) {
|
|
|
65
79
|
states.push({
|
|
66
80
|
clientId,
|
|
67
81
|
user: raw.user ?? { name: "", color: "" },
|
|
68
|
-
cursor: raw.cursor ?? null
|
|
82
|
+
cursor: raw.cursor ?? null,
|
|
83
|
+
// `present` defaults to true for backwards compat (legacy states
|
|
84
|
+
// don't set it) and for the local user (always considered present
|
|
85
|
+
// until PR2 toggles it off).
|
|
86
|
+
present: raw.present ?? LOCAL_PRESENT_DEFAULT
|
|
69
87
|
});
|
|
70
88
|
});
|
|
71
89
|
return states;
|
|
@@ -75,14 +93,14 @@ function createCollaboration(options) {
|
|
|
75
93
|
if (options.initialStorageState) {
|
|
76
94
|
Y.applyUpdate(ydoc, options.initialStorageState);
|
|
77
95
|
}
|
|
96
|
+
let persistence;
|
|
97
|
+
if (options.offline) {
|
|
98
|
+
persistence = new IndexeddbPersistence(`docflow-${options.room}`, ydoc);
|
|
99
|
+
}
|
|
78
100
|
let provider = null;
|
|
79
101
|
if (options.provider === "webrtc") {
|
|
80
102
|
provider = new WebrtcProvider(options.room, ydoc, {
|
|
81
|
-
signaling: options.signaling
|
|
82
|
-
"ws://localhost:4444",
|
|
83
|
-
"wss://signaling.yjs.dev",
|
|
84
|
-
"wss://y-webrtc-eu.fly.dev"
|
|
85
|
-
]
|
|
103
|
+
signaling: resolveSignalingUrls(options.signaling)
|
|
86
104
|
});
|
|
87
105
|
} else if (options.provider === "websocket") {
|
|
88
106
|
if (!options.websocketUrl) {
|
|
@@ -92,6 +110,16 @@ function createCollaboration(options) {
|
|
|
92
110
|
}
|
|
93
111
|
const awareness = provider?.awareness ?? new Awareness(ydoc);
|
|
94
112
|
awareness.setLocalStateField("user", options.user);
|
|
113
|
+
let emitCursor = options.emitCursor ?? true;
|
|
114
|
+
const setLocalCursorEnabled = (enabled) => {
|
|
115
|
+
if (emitCursor === enabled) return;
|
|
116
|
+
emitCursor = enabled;
|
|
117
|
+
if (!enabled) {
|
|
118
|
+
awareness.setLocalStateField("cursor", null);
|
|
119
|
+
}
|
|
120
|
+
awareness.setLocalStateField("present", enabled);
|
|
121
|
+
};
|
|
122
|
+
awareness.setLocalStateField("present", emitCursor);
|
|
95
123
|
let awarenessHandler;
|
|
96
124
|
if (options.onAwarenessChange) {
|
|
97
125
|
const notify = () => {
|
|
@@ -108,9 +136,10 @@ function createCollaboration(options) {
|
|
|
108
136
|
awareness.setLocalState(null);
|
|
109
137
|
provider?.destroy?.();
|
|
110
138
|
awareness.destroy?.();
|
|
139
|
+
void persistence?.destroy();
|
|
111
140
|
ydoc.destroy();
|
|
112
141
|
};
|
|
113
|
-
return { ydoc, provider, awareness, destroy };
|
|
142
|
+
return { ydoc, provider, awareness, persistence, destroy, setLocalCursorEnabled };
|
|
114
143
|
}
|
|
115
144
|
function collaborationExtensions(options) {
|
|
116
145
|
const setup = "ydoc" in options ? options : createCollaboration(options);
|
|
@@ -189,8 +218,1016 @@ var BlockAttributesExtension = Extension.create({
|
|
|
189
218
|
}
|
|
190
219
|
});
|
|
191
220
|
|
|
221
|
+
// src/EditorContext.ts
|
|
222
|
+
import { Extension as Extension2 } from "@tiptap/core";
|
|
223
|
+
var EditorContextExtension = Extension2.create({
|
|
224
|
+
name: "editorContext",
|
|
225
|
+
addOptions() {
|
|
226
|
+
return {
|
|
227
|
+
onImageUpload: void 0,
|
|
228
|
+
citation: void 0,
|
|
229
|
+
aiStream: void 0,
|
|
230
|
+
aiDraft: void 0
|
|
231
|
+
};
|
|
232
|
+
},
|
|
233
|
+
addStorage() {
|
|
234
|
+
return {
|
|
235
|
+
onImageUpload: this.options.onImageUpload,
|
|
236
|
+
citation: this.options.citation,
|
|
237
|
+
aiStream: this.options.aiStream,
|
|
238
|
+
aiDraft: this.options.aiDraft
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// src/SearchAndReplace.ts
|
|
244
|
+
import { Extension as Extension3 } from "@tiptap/core";
|
|
245
|
+
import { Plugin as Plugin2, PluginKey as PluginKey2, TextSelection } from "@tiptap/pm/state";
|
|
246
|
+
import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
|
|
247
|
+
var searchAndReplaceKey = new PluginKey2("searchAndReplace");
|
|
248
|
+
var EMPTY_STATE = { query: "", matches: [], activeIndex: 0 };
|
|
249
|
+
function findMatches(doc, query) {
|
|
250
|
+
const matches = [];
|
|
251
|
+
if (!query) return matches;
|
|
252
|
+
const needle = query.toLowerCase();
|
|
253
|
+
doc.descendants((node, pos) => {
|
|
254
|
+
if (!node.isText || !node.text) return;
|
|
255
|
+
const hay = node.text.toLowerCase();
|
|
256
|
+
let idx = hay.indexOf(needle);
|
|
257
|
+
while (idx !== -1) {
|
|
258
|
+
matches.push({ from: pos + idx, to: pos + idx + needle.length });
|
|
259
|
+
idx = hay.indexOf(needle, idx + needle.length);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
return matches;
|
|
263
|
+
}
|
|
264
|
+
function clampIndex(index, matches) {
|
|
265
|
+
if (matches.length === 0) return 0;
|
|
266
|
+
return Math.min(Math.max(index, 0), matches.length - 1);
|
|
267
|
+
}
|
|
268
|
+
function computeState(doc, query, activeIndex = 0) {
|
|
269
|
+
const matches = findMatches(doc, query);
|
|
270
|
+
return { query, matches, activeIndex: clampIndex(activeIndex, matches) };
|
|
271
|
+
}
|
|
272
|
+
var searchPlugin = new Plugin2({
|
|
273
|
+
key: searchAndReplaceKey,
|
|
274
|
+
state: {
|
|
275
|
+
init: () => EMPTY_STATE,
|
|
276
|
+
apply: (tr, prev) => {
|
|
277
|
+
const meta = tr.getMeta(searchAndReplaceKey);
|
|
278
|
+
if (meta) {
|
|
279
|
+
if (meta.type === "clear") return EMPTY_STATE;
|
|
280
|
+
if (meta.type === "set") return computeState(tr.doc, meta.query);
|
|
281
|
+
return { ...prev, activeIndex: clampIndex(meta.index, prev.matches) };
|
|
282
|
+
}
|
|
283
|
+
if (tr.docChanged && prev.query) {
|
|
284
|
+
return computeState(tr.doc, prev.query, prev.activeIndex);
|
|
285
|
+
}
|
|
286
|
+
return prev;
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
props: {
|
|
290
|
+
decorations: (state) => {
|
|
291
|
+
const s = searchAndReplaceKey.getState(state);
|
|
292
|
+
if (!s || s.matches.length === 0) return null;
|
|
293
|
+
return DecorationSet2.create(
|
|
294
|
+
state.doc,
|
|
295
|
+
s.matches.map(
|
|
296
|
+
(m, i) => Decoration2.inline(m.from, m.to, {
|
|
297
|
+
class: i === s.activeIndex ? "find-match find-match-active" : "find-match"
|
|
298
|
+
})
|
|
299
|
+
)
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
var SearchAndReplaceExtension = Extension3.create({
|
|
305
|
+
name: "searchAndReplace",
|
|
306
|
+
addProseMirrorPlugins() {
|
|
307
|
+
return [searchPlugin];
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
function getSearchState(editor) {
|
|
311
|
+
return searchAndReplaceKey.getState(editor.state) ?? EMPTY_STATE;
|
|
312
|
+
}
|
|
313
|
+
function setSearchQuery(editor, query) {
|
|
314
|
+
editor.view.dispatch(editor.state.tr.setMeta(searchAndReplaceKey, { type: "set", query }));
|
|
315
|
+
}
|
|
316
|
+
function clearSearch(editor) {
|
|
317
|
+
editor.view.dispatch(editor.state.tr.setMeta(searchAndReplaceKey, { type: "clear" }));
|
|
318
|
+
}
|
|
319
|
+
function activateMatch(editor, index) {
|
|
320
|
+
const s = getSearchState(editor);
|
|
321
|
+
const match = s.matches[index];
|
|
322
|
+
const tr = editor.state.tr.setMeta(searchAndReplaceKey, { type: "setActive", index });
|
|
323
|
+
if (match) {
|
|
324
|
+
tr.setSelection(TextSelection.create(editor.state.doc, match.from, match.to));
|
|
325
|
+
tr.scrollIntoView();
|
|
326
|
+
}
|
|
327
|
+
editor.view.dispatch(tr);
|
|
328
|
+
}
|
|
329
|
+
function searchNext(editor) {
|
|
330
|
+
const s = getSearchState(editor);
|
|
331
|
+
if (s.matches.length === 0) return null;
|
|
332
|
+
const next = (s.activeIndex + 1) % s.matches.length;
|
|
333
|
+
activateMatch(editor, next);
|
|
334
|
+
return s.matches[next];
|
|
335
|
+
}
|
|
336
|
+
function searchPrev(editor) {
|
|
337
|
+
const s = getSearchState(editor);
|
|
338
|
+
if (s.matches.length === 0) return null;
|
|
339
|
+
const prev = (s.activeIndex - 1 + s.matches.length) % s.matches.length;
|
|
340
|
+
activateMatch(editor, prev);
|
|
341
|
+
return s.matches[prev];
|
|
342
|
+
}
|
|
343
|
+
function replaceCurrent(editor, replacement) {
|
|
344
|
+
const s = getSearchState(editor);
|
|
345
|
+
const match = s.matches[s.activeIndex];
|
|
346
|
+
if (!match) return false;
|
|
347
|
+
editor.view.dispatch(editor.state.tr.insertText(replacement, match.from, match.to));
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
function replaceAll(editor, replacement) {
|
|
351
|
+
const s = getSearchState(editor);
|
|
352
|
+
if (s.matches.length === 0) return 0;
|
|
353
|
+
const tr = editor.state.tr;
|
|
354
|
+
for (let i = s.matches.length - 1; i >= 0; i--) {
|
|
355
|
+
tr.insertText(replacement, s.matches[i].from, s.matches[i].to);
|
|
356
|
+
}
|
|
357
|
+
editor.view.dispatch(tr);
|
|
358
|
+
return s.matches.length;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ../../node_modules/.pnpm/tiptap-pagination-plus@3.1.0_@tiptap+core@2.27.2_@tiptap+pm@2.27.2__@tiptap+pm@2.27.2/node_modules/tiptap-pagination-plus/dist/PaginationPlus.js
|
|
362
|
+
import { Extension as Extension4 } from "@tiptap/core";
|
|
363
|
+
import { Plugin as Plugin3, PluginKey as PluginKey3 } from "@tiptap/pm/state";
|
|
364
|
+
import { ReplaceStep, ReplaceAroundStep, AddMarkStep, RemoveMarkStep, RemoveNodeMarkStep, AttrStep } from "@tiptap/pm/transform";
|
|
365
|
+
import { Decoration as Decoration3, DecorationSet as DecorationSet3 } from "@tiptap/pm/view";
|
|
366
|
+
|
|
367
|
+
// ../../node_modules/.pnpm/tiptap-pagination-plus@3.1.0_@tiptap+core@2.27.2_@tiptap+pm@2.27.2__@tiptap+pm@2.27.2/node_modules/tiptap-pagination-plus/dist/utils.js
|
|
368
|
+
var updateCssVariables = (targetNode, config) => {
|
|
369
|
+
const cssVariables = {
|
|
370
|
+
"rm-page-height": `${config.pageHeight}px`,
|
|
371
|
+
"rm-margin-top": `${config.marginTop}px`,
|
|
372
|
+
"rm-margin-bottom": `${config.marginBottom}px`,
|
|
373
|
+
"rm-margin-left": `${config.marginLeft}px`,
|
|
374
|
+
"rm-margin-right": `${config.marginRight}px`,
|
|
375
|
+
"rm-content-margin-top": `${config.contentMarginTop}px`,
|
|
376
|
+
"rm-content-margin-bottom": `${config.contentMarginBottom}px`,
|
|
377
|
+
"rm-page-gap-border-color": `${config.pageGapBorderColor}`,
|
|
378
|
+
"rm-page-width": `${config.pageWidth}px`
|
|
379
|
+
};
|
|
380
|
+
Object.entries(cssVariables).forEach(([key2, value]) => {
|
|
381
|
+
targetNode.style.setProperty(`--${key2}`, value);
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
var getPageSize = (height, width, marginTop, marginBottom, marginLeft, marginRight) => {
|
|
385
|
+
return {
|
|
386
|
+
pageHeight: height,
|
|
387
|
+
pageWidth: width,
|
|
388
|
+
marginTop,
|
|
389
|
+
marginBottom,
|
|
390
|
+
marginLeft,
|
|
391
|
+
marginRight
|
|
392
|
+
};
|
|
393
|
+
};
|
|
394
|
+
var getHeaderHeight = (targetNode, pageNumbers, type) => {
|
|
395
|
+
const headerHeightMap = /* @__PURE__ */ new Map();
|
|
396
|
+
const clientHeader = targetNode.querySelector(getHeaderHeightSelector(0, type));
|
|
397
|
+
headerHeightMap.set(0, clientHeader ? clientHeader.clientHeight : 0);
|
|
398
|
+
pageNumbers.forEach((pageNumber) => {
|
|
399
|
+
const clientHeader2 = targetNode.querySelector(getHeaderHeightSelector(pageNumber, type));
|
|
400
|
+
const headerHeight = clientHeader2 ? clientHeader2.clientHeight : 0;
|
|
401
|
+
headerHeightMap.set(pageNumber, headerHeight);
|
|
402
|
+
});
|
|
403
|
+
return headerHeightMap;
|
|
404
|
+
};
|
|
405
|
+
var getHeaderHeightSelector = (pageNumber, type) => {
|
|
406
|
+
return type === "actual" ? `.rm-page-header-${pageNumber}` : `.rm-page-header-${pageNumber} .rm-page-header-content`;
|
|
407
|
+
};
|
|
408
|
+
var getFooterHeight = (targetNode, pageNumbers, type) => {
|
|
409
|
+
const footerHeightMap = /* @__PURE__ */ new Map();
|
|
410
|
+
const clientFooter = targetNode.querySelector(getFooterHeightSelector(0, type));
|
|
411
|
+
footerHeightMap.set(0, clientFooter ? clientFooter.clientHeight : 0);
|
|
412
|
+
pageNumbers.forEach((pageNumber) => {
|
|
413
|
+
const clientFooter2 = targetNode.querySelector(getFooterHeightSelector(pageNumber, type));
|
|
414
|
+
const footerHeight = clientFooter2 ? clientFooter2.clientHeight : 0;
|
|
415
|
+
footerHeightMap.set(pageNumber, footerHeight);
|
|
416
|
+
});
|
|
417
|
+
return footerHeightMap;
|
|
418
|
+
};
|
|
419
|
+
var getFooterHeightSelector = (pageNumber, type) => {
|
|
420
|
+
return type === "actual" ? `.rm-page-footer-${pageNumber}` : `.rm-page-footer-${pageNumber} .rm-page-footer-content`;
|
|
421
|
+
};
|
|
422
|
+
function deepEqualIterative(a, b) {
|
|
423
|
+
if (a === b)
|
|
424
|
+
return true;
|
|
425
|
+
if (typeof a !== "object" || typeof b !== "object" || a == null || b == null) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
const stack = [{ x: a, y: b }];
|
|
429
|
+
while (stack.length) {
|
|
430
|
+
const _stackItem = stack.pop();
|
|
431
|
+
if (!_stackItem)
|
|
432
|
+
continue;
|
|
433
|
+
const { x, y } = _stackItem;
|
|
434
|
+
if (x === y)
|
|
435
|
+
continue;
|
|
436
|
+
if (typeof x !== typeof y)
|
|
437
|
+
return false;
|
|
438
|
+
if (typeof x !== "object")
|
|
439
|
+
return false;
|
|
440
|
+
if (x == null || y == null)
|
|
441
|
+
return false;
|
|
442
|
+
const xKeys = Object.keys(x);
|
|
443
|
+
const yKeys = Object.keys(y);
|
|
444
|
+
if (xKeys.length !== yKeys.length)
|
|
445
|
+
return false;
|
|
446
|
+
for (const key2 of xKeys) {
|
|
447
|
+
if (!(key2 in y))
|
|
448
|
+
return false;
|
|
449
|
+
const xVal = x[key2];
|
|
450
|
+
const yVal = y[key2];
|
|
451
|
+
if (xVal === yVal)
|
|
452
|
+
continue;
|
|
453
|
+
if (typeof xVal === "object" && typeof yVal === "object") {
|
|
454
|
+
stack.push({ x: xVal, y: yVal });
|
|
455
|
+
} else {
|
|
456
|
+
if (xVal !== yVal)
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return true;
|
|
462
|
+
}
|
|
463
|
+
function getCustomPages(customHeader, customFooter) {
|
|
464
|
+
return [...Object.keys(customHeader), ...Object.keys(customFooter)].map(Number);
|
|
465
|
+
}
|
|
466
|
+
function getFooter(footerRightContent, footerLeftContent, onFooterClick, pageNumber) {
|
|
467
|
+
const pageFooter = document.createElement("div");
|
|
468
|
+
pageFooter.classList.add("rm-page-footer");
|
|
469
|
+
pageFooter.classList.add(`rm-page-footer-${pageNumber ? pageNumber : 0}`);
|
|
470
|
+
pageFooter.style.overflow = "visible";
|
|
471
|
+
pageFooter.style.position = "relative";
|
|
472
|
+
pageFooter.style.cursor = "pointer";
|
|
473
|
+
const pageFooterContent = document.createElement("div");
|
|
474
|
+
pageFooterContent.classList.add("rm-page-footer-content");
|
|
475
|
+
pageFooterContent.style.width = "100%";
|
|
476
|
+
pageFooterContent.style.overflow = "hidden";
|
|
477
|
+
const footerRight = footerRightContent.replace("{page}", `<span class="rm-page-number"></span>`);
|
|
478
|
+
const footerLeft = footerLeftContent.replace("{page}", `<span class="rm-page-number"></span>`);
|
|
479
|
+
const pageFooterLeft = document.createElement("div");
|
|
480
|
+
pageFooterLeft.classList.add("rm-page-footer-left");
|
|
481
|
+
pageFooterLeft.innerHTML = footerLeft;
|
|
482
|
+
const pageFooterRight = document.createElement("div");
|
|
483
|
+
pageFooterRight.classList.add("rm-page-footer-right");
|
|
484
|
+
pageFooterRight.innerHTML = footerRight;
|
|
485
|
+
pageFooterContent.append(pageFooterLeft, pageFooterRight);
|
|
486
|
+
pageFooter.append(pageFooterContent);
|
|
487
|
+
pageFooter.addEventListener("click", onFooterClick);
|
|
488
|
+
return pageFooter;
|
|
489
|
+
}
|
|
490
|
+
function getHeader(headerRightContent, headerLeftContent, onHeaderClick, pageNumber) {
|
|
491
|
+
const pageHeader = document.createElement("div");
|
|
492
|
+
pageHeader.classList.add("rm-page-header");
|
|
493
|
+
pageHeader.classList.add(`rm-page-header-${pageNumber ? pageNumber : 0}`);
|
|
494
|
+
pageHeader.style.overflow = "hidden";
|
|
495
|
+
pageHeader.style.cursor = "pointer";
|
|
496
|
+
pageHeader.style.position = "relative";
|
|
497
|
+
const pageHeaderContent = document.createElement("div");
|
|
498
|
+
pageHeaderContent.classList.add("rm-page-header-content");
|
|
499
|
+
pageHeaderContent.style.width = "100%";
|
|
500
|
+
pageHeaderContent.style.overflow = "hidden";
|
|
501
|
+
const headerLeft = headerLeftContent.replace("{page}", `<span class="rm-page-number-plus"></span>`);
|
|
502
|
+
const headerRight = headerRightContent.replace("{page}", `<span class="rm-page-number-plus"></span>`);
|
|
503
|
+
const pageHeaderLeft = document.createElement("div");
|
|
504
|
+
pageHeaderLeft.classList.add("rm-page-header-left");
|
|
505
|
+
pageHeaderLeft.innerHTML = headerLeft;
|
|
506
|
+
const pageHeaderRight = document.createElement("div");
|
|
507
|
+
pageHeaderRight.classList.add("rm-page-header-right");
|
|
508
|
+
pageHeaderRight.innerHTML = headerRight;
|
|
509
|
+
pageHeaderContent.append(pageHeaderLeft, pageHeaderRight);
|
|
510
|
+
pageHeader.append(pageHeaderContent);
|
|
511
|
+
pageHeader.addEventListener("click", onHeaderClick);
|
|
512
|
+
return pageHeader;
|
|
513
|
+
}
|
|
514
|
+
var getHeight = (pageOptions, _headerHeight, _footerHeight) => {
|
|
515
|
+
const _pageHeaderHeight = pageOptions.contentMarginTop + pageOptions.marginTop + _headerHeight;
|
|
516
|
+
const _pageFooterHeight = pageOptions.contentMarginBottom + pageOptions.marginBottom + _footerHeight;
|
|
517
|
+
const _pageHeight = pageOptions.pageHeight - _pageHeaderHeight - _pageFooterHeight;
|
|
518
|
+
return {
|
|
519
|
+
_pageHeaderHeight,
|
|
520
|
+
_pageFooterHeight,
|
|
521
|
+
_pageHeight
|
|
522
|
+
};
|
|
523
|
+
};
|
|
524
|
+
var headerClickEvent = (pageNumber, onHeaderClick) => {
|
|
525
|
+
return (event) => {
|
|
526
|
+
onHeaderClick === null || onHeaderClick === void 0 ? void 0 : onHeaderClick({
|
|
527
|
+
event,
|
|
528
|
+
pageNumber
|
|
529
|
+
});
|
|
530
|
+
};
|
|
531
|
+
};
|
|
532
|
+
var footerClickEvent = (pageNumber, onFooterClick) => {
|
|
533
|
+
return (event) => {
|
|
534
|
+
onFooterClick === null || onFooterClick === void 0 ? void 0 : onFooterClick({
|
|
535
|
+
event,
|
|
536
|
+
pageNumber
|
|
537
|
+
});
|
|
538
|
+
};
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
// ../../node_modules/.pnpm/tiptap-pagination-plus@3.1.0_@tiptap+core@2.27.2_@tiptap+pm@2.27.2__@tiptap+pm@2.27.2/node_modules/tiptap-pagination-plus/dist/PaginationPlus.js
|
|
542
|
+
var page_count_meta_key = "PAGE_COUNT_META_KEY";
|
|
543
|
+
var key = new PluginKey3("brDecoration");
|
|
544
|
+
function buildDecorations(doc) {
|
|
545
|
+
const decorations = [];
|
|
546
|
+
doc.descendants((node, pos) => {
|
|
547
|
+
if (node.type.name === "hardBreak") {
|
|
548
|
+
const afterPos = pos + 1;
|
|
549
|
+
const widget = Decoration3.widget(afterPos, () => {
|
|
550
|
+
const el = document.createElement("span");
|
|
551
|
+
el.classList.add("rm-br-decoration");
|
|
552
|
+
return el;
|
|
553
|
+
});
|
|
554
|
+
decorations.push(widget);
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
return DecorationSet3.create(doc, decorations);
|
|
558
|
+
}
|
|
559
|
+
var defaultPageConfig = {
|
|
560
|
+
enabled: true,
|
|
561
|
+
pageBreakBackground: "#ffffff",
|
|
562
|
+
pageHeight: 800,
|
|
563
|
+
pageWidth: 789,
|
|
564
|
+
marginTop: 20,
|
|
565
|
+
marginBottom: 20,
|
|
566
|
+
marginLeft: 50,
|
|
567
|
+
marginRight: 50,
|
|
568
|
+
pageGap: 50,
|
|
569
|
+
contentMarginTop: 10,
|
|
570
|
+
contentMarginBottom: 10,
|
|
571
|
+
footerRight: "{page}",
|
|
572
|
+
footerLeft: "",
|
|
573
|
+
headerRight: "",
|
|
574
|
+
headerLeft: "",
|
|
575
|
+
customHeader: {},
|
|
576
|
+
customFooter: {}
|
|
577
|
+
};
|
|
578
|
+
var defaultOptions = Object.assign({ pageGapBorderSize: 1, pageGapBorderColor: "#e5e5e5" }, defaultPageConfig);
|
|
579
|
+
var refreshPage = (targetNode, paginationEnabled = true) => {
|
|
580
|
+
var _a;
|
|
581
|
+
const paginationElement = targetNode.querySelector("[data-rm-pagination]");
|
|
582
|
+
if (paginationEnabled) {
|
|
583
|
+
targetNode.removeAttribute("rm-pagination-disabled");
|
|
584
|
+
if (paginationElement) {
|
|
585
|
+
const lastPageBreak = (_a = paginationElement.lastElementChild) === null || _a === void 0 ? void 0 : _a.querySelector(".breaker");
|
|
586
|
+
if (lastPageBreak) {
|
|
587
|
+
const minHeight = lastPageBreak.offsetTop + lastPageBreak.offsetHeight;
|
|
588
|
+
targetNode.style.minHeight = `calc(${minHeight}px + 2px)`;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
} else {
|
|
592
|
+
targetNode.setAttribute("rm-pagination-disabled", "");
|
|
593
|
+
targetNode.style.minHeight = `auto`;
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
var getPageConfig = (_storage, _currentOptions) => {
|
|
597
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
598
|
+
const pageConfig = {
|
|
599
|
+
enabled: (_a = _storage.enabled) !== null && _a !== void 0 ? _a : defaultOptions.enabled,
|
|
600
|
+
pageBreakBackground: (_b = _storage.pageBreakBackground) !== null && _b !== void 0 ? _b : defaultOptions.pageBreakBackground,
|
|
601
|
+
pageHeight: (_c = _storage.pageHeight) !== null && _c !== void 0 ? _c : defaultOptions.pageHeight,
|
|
602
|
+
pageWidth: (_d = _storage.pageWidth) !== null && _d !== void 0 ? _d : defaultPageConfig.pageWidth,
|
|
603
|
+
marginTop: (_e = _storage.marginTop) !== null && _e !== void 0 ? _e : defaultPageConfig.marginTop,
|
|
604
|
+
marginBottom: (_f = _storage.marginBottom) !== null && _f !== void 0 ? _f : defaultPageConfig.marginBottom,
|
|
605
|
+
marginLeft: (_g = _storage.marginLeft) !== null && _g !== void 0 ? _g : defaultPageConfig.marginLeft,
|
|
606
|
+
marginRight: (_h = _storage.marginRight) !== null && _h !== void 0 ? _h : defaultPageConfig.marginRight,
|
|
607
|
+
pageGap: (_j = _storage.pageGap) !== null && _j !== void 0 ? _j : defaultPageConfig.pageGap,
|
|
608
|
+
contentMarginTop: (_k = _storage.contentMarginTop) !== null && _k !== void 0 ? _k : defaultPageConfig.contentMarginTop,
|
|
609
|
+
contentMarginBottom: (_l = _storage.contentMarginBottom) !== null && _l !== void 0 ? _l : defaultPageConfig.contentMarginBottom,
|
|
610
|
+
footerRight: (_m = _storage.footerRight) !== null && _m !== void 0 ? _m : defaultPageConfig.footerRight,
|
|
611
|
+
footerLeft: (_o = _storage.footerLeft) !== null && _o !== void 0 ? _o : defaultPageConfig.footerLeft,
|
|
612
|
+
headerRight: (_p = _storage.headerRight) !== null && _p !== void 0 ? _p : defaultPageConfig.headerRight,
|
|
613
|
+
headerLeft: (_q = _storage.headerLeft) !== null && _q !== void 0 ? _q : defaultPageConfig.headerLeft,
|
|
614
|
+
customHeader: (_r = _storage.customHeader) !== null && _r !== void 0 ? _r : defaultPageConfig.customHeader,
|
|
615
|
+
customFooter: (_s = _storage.customFooter) !== null && _s !== void 0 ? _s : defaultPageConfig.customFooter
|
|
616
|
+
};
|
|
617
|
+
return {
|
|
618
|
+
config: pageConfig,
|
|
619
|
+
options: Object.assign(Object.assign({}, _currentOptions), pageConfig)
|
|
620
|
+
};
|
|
621
|
+
};
|
|
622
|
+
var getPageConfigFromOptions = (_currentOptions) => {
|
|
623
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
624
|
+
return {
|
|
625
|
+
enabled: (_a = _currentOptions.enabled) !== null && _a !== void 0 ? _a : defaultOptions.enabled,
|
|
626
|
+
pageBreakBackground: (_b = _currentOptions.pageBreakBackground) !== null && _b !== void 0 ? _b : defaultOptions.pageBreakBackground,
|
|
627
|
+
pageHeight: (_c = _currentOptions.pageHeight) !== null && _c !== void 0 ? _c : defaultOptions.pageHeight,
|
|
628
|
+
pageWidth: (_d = _currentOptions.pageWidth) !== null && _d !== void 0 ? _d : defaultPageConfig.pageWidth,
|
|
629
|
+
marginTop: (_e = _currentOptions.marginTop) !== null && _e !== void 0 ? _e : defaultPageConfig.marginTop,
|
|
630
|
+
marginBottom: (_f = _currentOptions.marginBottom) !== null && _f !== void 0 ? _f : defaultPageConfig.marginBottom,
|
|
631
|
+
marginLeft: (_g = _currentOptions.marginLeft) !== null && _g !== void 0 ? _g : defaultPageConfig.marginLeft,
|
|
632
|
+
marginRight: (_h = _currentOptions.marginRight) !== null && _h !== void 0 ? _h : defaultPageConfig.marginRight,
|
|
633
|
+
pageGap: (_j = _currentOptions.pageGap) !== null && _j !== void 0 ? _j : defaultPageConfig.pageGap,
|
|
634
|
+
contentMarginTop: (_k = _currentOptions.contentMarginTop) !== null && _k !== void 0 ? _k : defaultPageConfig.contentMarginTop,
|
|
635
|
+
contentMarginBottom: (_l = _currentOptions.contentMarginBottom) !== null && _l !== void 0 ? _l : defaultPageConfig.contentMarginBottom,
|
|
636
|
+
footerRight: (_m = _currentOptions.footerRight) !== null && _m !== void 0 ? _m : defaultPageConfig.footerRight,
|
|
637
|
+
footerLeft: (_o = _currentOptions.footerLeft) !== null && _o !== void 0 ? _o : defaultPageConfig.footerLeft,
|
|
638
|
+
headerRight: (_p = _currentOptions.headerRight) !== null && _p !== void 0 ? _p : defaultPageConfig.headerRight,
|
|
639
|
+
headerLeft: (_q = _currentOptions.headerLeft) !== null && _q !== void 0 ? _q : defaultPageConfig.headerLeft,
|
|
640
|
+
customHeader: (_r = _currentOptions.customHeader) !== null && _r !== void 0 ? _r : defaultPageConfig.customHeader,
|
|
641
|
+
customFooter: (_s = _currentOptions.customFooter) !== null && _s !== void 0 ? _s : defaultPageConfig.customFooter
|
|
642
|
+
};
|
|
643
|
+
};
|
|
644
|
+
var paginationKey = new PluginKey3("pagination");
|
|
645
|
+
var PaginationPlus = Extension4.create({
|
|
646
|
+
name: "PaginationPlus",
|
|
647
|
+
addOptions() {
|
|
648
|
+
return defaultOptions;
|
|
649
|
+
},
|
|
650
|
+
addStorage() {
|
|
651
|
+
return Object.assign(Object.assign({}, defaultOptions), { headerHeight: /* @__PURE__ */ new Map(), footerHeight: /* @__PURE__ */ new Map(), appliedConfig: defaultPageConfig });
|
|
652
|
+
},
|
|
653
|
+
onCreate() {
|
|
654
|
+
const { options: _currentOptions } = getPageConfig(this.storage, this.options);
|
|
655
|
+
const pageConfig = getPageConfigFromOptions(this.options);
|
|
656
|
+
const targetNode = this.editor.view.dom;
|
|
657
|
+
targetNode.classList.add("rm-with-pagination");
|
|
658
|
+
targetNode.style.border = `1px solid var(--rm-page-gap-border-color)`;
|
|
659
|
+
targetNode.style.paddingLeft = `var(--rm-margin-left)`;
|
|
660
|
+
targetNode.style.paddingRight = `var(--rm-margin-right)`;
|
|
661
|
+
targetNode.style.width = `var(--rm-page-width)`;
|
|
662
|
+
updateCssVariables(targetNode, Object.assign(Object.assign({}, _currentOptions), pageConfig));
|
|
663
|
+
const style = document.createElement("style");
|
|
664
|
+
style.dataset.rmPaginationStyle = "";
|
|
665
|
+
style.textContent = `
|
|
666
|
+
.rm-pagination-gap{
|
|
667
|
+
border-top: 1px solid;
|
|
668
|
+
border-bottom: 1px solid;
|
|
669
|
+
border-color: var(--rm-page-gap-border-color);
|
|
670
|
+
}
|
|
671
|
+
.rm-with-pagination,
|
|
672
|
+
.rm-with-pagination .rm-first-page-header {
|
|
673
|
+
counter-reset: page-number page-number-plus 1;
|
|
674
|
+
}
|
|
675
|
+
.rm-with-pagination .image-plus-wrapper,
|
|
676
|
+
.rm-with-pagination .table-plus td,
|
|
677
|
+
.rm-with-pagination .table-plus th {
|
|
678
|
+
max-height: var(--rm-max-content-child-height);
|
|
679
|
+
overflow-y: auto;
|
|
680
|
+
}
|
|
681
|
+
.rm-with-pagination .image-plus-wrapper {
|
|
682
|
+
overflow-y: visible;
|
|
683
|
+
}
|
|
684
|
+
.rm-with-pagination .rm-page-break {
|
|
685
|
+
counter-increment: page-number page-number-plus;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
.rm-with-pagination .rm-page-break:last-child .rm-pagination-gap {
|
|
689
|
+
display: none;
|
|
690
|
+
}
|
|
691
|
+
.rm-with-pagination .rm-page-break:last-child .rm-page-header {
|
|
692
|
+
display: none;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.rm-with-pagination table tr td,
|
|
696
|
+
.rm-with-pagination table tr th {
|
|
697
|
+
word-break: break-all;
|
|
698
|
+
}
|
|
699
|
+
.rm-with-pagination table > tr {
|
|
700
|
+
display: grid;
|
|
701
|
+
min-width: 100%;
|
|
702
|
+
}
|
|
703
|
+
.rm-with-pagination table {
|
|
704
|
+
border-collapse: collapse;
|
|
705
|
+
width: 100%;
|
|
706
|
+
display: contents;
|
|
707
|
+
}
|
|
708
|
+
.rm-with-pagination table tbody{
|
|
709
|
+
display: table;
|
|
710
|
+
max-height: 300px;
|
|
711
|
+
overflow-y: auto;
|
|
712
|
+
}
|
|
713
|
+
.rm-with-pagination table tbody > tr{
|
|
714
|
+
display: table-row !important;
|
|
715
|
+
}
|
|
716
|
+
.rm-with-pagination *:has(>br.ProseMirror-trailingBreak:only-child) {
|
|
717
|
+
display: table;
|
|
718
|
+
width: 100%;
|
|
719
|
+
}
|
|
720
|
+
.rm-with-pagination .rm-br-decoration {
|
|
721
|
+
display: table;
|
|
722
|
+
width: 100%;
|
|
723
|
+
}
|
|
724
|
+
.rm-with-pagination .table-row-group {
|
|
725
|
+
max-height: var(--rm-max-content-child-height);
|
|
726
|
+
overflow-y: auto;
|
|
727
|
+
width: 100%;
|
|
728
|
+
}
|
|
729
|
+
.rm-with-pagination .rm-page-footer-left,
|
|
730
|
+
.rm-with-pagination .rm-page-footer-right,
|
|
731
|
+
.rm-with-pagination .rm-page-header-left,
|
|
732
|
+
.rm-with-pagination .rm-page-header-right {
|
|
733
|
+
display: inline-block;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.rm-with-pagination .rm-page-header-left,
|
|
737
|
+
.rm-with-pagination .rm-page-footer-left{
|
|
738
|
+
float: left;
|
|
739
|
+
margin-left: var(--rm-margin-left);
|
|
740
|
+
}
|
|
741
|
+
.rm-with-pagination .rm-page-header-right,
|
|
742
|
+
.rm-with-pagination .rm-page-footer-right{
|
|
743
|
+
float: right;
|
|
744
|
+
margin-right: var(--rm-margin-right);
|
|
745
|
+
}
|
|
746
|
+
.rm-with-pagination .rm-first-page-header .rm-page-header-right{
|
|
747
|
+
margin-right: 0px !important;
|
|
748
|
+
}
|
|
749
|
+
.rm-with-pagination .rm-first-page-header .rm-page-header-left{
|
|
750
|
+
margin-left: 0px !important;
|
|
751
|
+
}
|
|
752
|
+
.rm-with-pagination .rm-page-number::before {
|
|
753
|
+
content: counter(page-number);
|
|
754
|
+
}
|
|
755
|
+
.rm-with-pagination .rm-page-number-plus::before {
|
|
756
|
+
content: counter(page-number-plus);
|
|
757
|
+
}
|
|
758
|
+
.rm-with-pagination .rm-page-header,
|
|
759
|
+
.rm-with-pagination .rm-page-footer{
|
|
760
|
+
width: 100%;
|
|
761
|
+
}
|
|
762
|
+
.rm-with-pagination .rm-page-header{
|
|
763
|
+
padding-bottom: var(--rm-content-margin-top) !important;
|
|
764
|
+
padding-top: var(--rm-margin-top) !important;
|
|
765
|
+
display: inline-flex;
|
|
766
|
+
justify-content: space-between;
|
|
767
|
+
max-height: calc(calc(var(--rm-page-height) * 0.45) - var(--rm-margin-top) - var(--rm-content-margin-top));
|
|
768
|
+
overflow-y: hidden;
|
|
769
|
+
}
|
|
770
|
+
.rm-with-pagination .rm-page-footer{
|
|
771
|
+
padding-top: var(--rm-content-margin-bottom) !important;
|
|
772
|
+
padding-bottom: var(--rm-margin-bottom) !important;
|
|
773
|
+
display: inline-flex;
|
|
774
|
+
justify-content: space-between;
|
|
775
|
+
max-height: calc(calc(var(--rm-page-height) * 0.45) - var(--rm-content-margin-bottom) - var(--rm-margin-bottom));
|
|
776
|
+
overflow-y: hidden;
|
|
777
|
+
}
|
|
778
|
+
.rm-with-pagination[rm-pagination-disabled] {
|
|
779
|
+
padding-top: var(--rm-margin-top) !important;
|
|
780
|
+
padding-bottom: var(--rm-margin-bottom) !important;
|
|
781
|
+
}
|
|
782
|
+
`;
|
|
783
|
+
document.head.appendChild(style);
|
|
784
|
+
refreshPage(targetNode, _currentOptions.enabled);
|
|
785
|
+
},
|
|
786
|
+
addProseMirrorPlugins() {
|
|
787
|
+
const editor = this.editor;
|
|
788
|
+
const storage = this.storage;
|
|
789
|
+
return [
|
|
790
|
+
new Plugin3({
|
|
791
|
+
key: paginationKey,
|
|
792
|
+
state: {
|
|
793
|
+
init: (_, state) => {
|
|
794
|
+
const _currentOptions = getPageConfigFromOptions(this.options);
|
|
795
|
+
const pageConfig = getPageConfigFromOptions(this.options);
|
|
796
|
+
const widgetList = createDecoration(Object.assign(Object.assign({}, this.options), _currentOptions), /* @__PURE__ */ new Map(), /* @__PURE__ */ new Map());
|
|
797
|
+
storage.pageBreakBackground = _currentOptions.pageBreakBackground;
|
|
798
|
+
storage.pageHeight = _currentOptions.pageHeight;
|
|
799
|
+
storage.pageWidth = _currentOptions.pageWidth;
|
|
800
|
+
storage.marginTop = _currentOptions.marginTop;
|
|
801
|
+
storage.marginBottom = _currentOptions.marginBottom;
|
|
802
|
+
storage.marginLeft = _currentOptions.marginLeft;
|
|
803
|
+
storage.marginRight = _currentOptions.marginRight;
|
|
804
|
+
storage.pageGap = _currentOptions.pageGap;
|
|
805
|
+
storage.contentMarginTop = _currentOptions.contentMarginTop;
|
|
806
|
+
storage.contentMarginBottom = _currentOptions.contentMarginBottom;
|
|
807
|
+
storage.footerRight = _currentOptions.footerRight;
|
|
808
|
+
storage.footerLeft = _currentOptions.footerLeft;
|
|
809
|
+
storage.headerRight = _currentOptions.headerRight;
|
|
810
|
+
storage.headerLeft = _currentOptions.headerLeft;
|
|
811
|
+
storage.customHeader = _currentOptions.customHeader;
|
|
812
|
+
storage.customFooter = _currentOptions.customFooter;
|
|
813
|
+
storage.headerHeight = /* @__PURE__ */ new Map();
|
|
814
|
+
storage.footerHeight = /* @__PURE__ */ new Map();
|
|
815
|
+
storage.appliedConfig = pageConfig;
|
|
816
|
+
return {
|
|
817
|
+
decorations: DecorationSet3.create(state.doc, widgetList)
|
|
818
|
+
};
|
|
819
|
+
},
|
|
820
|
+
apply: (tr, oldDeco, oldState, newState) => {
|
|
821
|
+
const { options: _currentOptions, config: pageConfig } = getPageConfig(storage, this.options);
|
|
822
|
+
if (storage.enabled === storage.appliedConfig.enabled && storage.enabled === false && storage.appliedConfig.enabled === false) {
|
|
823
|
+
return oldDeco;
|
|
824
|
+
}
|
|
825
|
+
const pageCount = getNewPageCount(editor.view, Object.assign(Object.assign({}, _currentOptions), pageConfig));
|
|
826
|
+
const currentPageCount = getExistingPageCount(editor.view);
|
|
827
|
+
const getNewDecoration = () => {
|
|
828
|
+
const { options: _currentOptions2, config: pageConfig2 } = getPageConfig(storage, this.options);
|
|
829
|
+
updateCssVariables(editor.view.dom, _currentOptions2);
|
|
830
|
+
let headerHeight = "headerHeight" in this.storage ? this.storage.headerHeight : /* @__PURE__ */ new Map();
|
|
831
|
+
let footerHeight = "footerHeight" in this.storage ? this.storage.footerHeight : /* @__PURE__ */ new Map();
|
|
832
|
+
const widgetList = createDecoration(Object.assign(Object.assign({}, _currentOptions2), pageConfig2), headerHeight, footerHeight);
|
|
833
|
+
storage.appliedConfig = pageConfig2;
|
|
834
|
+
storage.headerHeight = headerHeight;
|
|
835
|
+
storage.footerHeight = footerHeight;
|
|
836
|
+
return {
|
|
837
|
+
decorations: DecorationSet3.create(newState.doc, [...widgetList]),
|
|
838
|
+
footerHeight
|
|
839
|
+
};
|
|
840
|
+
};
|
|
841
|
+
if (
|
|
842
|
+
// If pagination is enabled only then check for other changes
|
|
843
|
+
(pageCount > 1 ? pageCount : 1) !== currentPageCount || storage.enabled !== storage.appliedConfig.enabled || storage.pageBreakBackground !== storage.appliedConfig.pageBreakBackground || storage.pageHeight !== storage.appliedConfig.pageHeight || storage.pageWidth !== storage.appliedConfig.pageWidth || storage.marginTop !== storage.appliedConfig.marginTop || storage.marginBottom !== storage.appliedConfig.marginBottom || storage.marginLeft !== storage.appliedConfig.marginLeft || storage.marginRight !== storage.appliedConfig.marginRight || storage.pageGap !== storage.appliedConfig.pageGap || storage.contentMarginTop !== storage.appliedConfig.contentMarginTop || storage.contentMarginBottom !== storage.appliedConfig.contentMarginBottom || storage.headerLeft !== storage.appliedConfig.headerLeft || storage.headerRight !== storage.appliedConfig.headerRight || storage.footerLeft !== storage.appliedConfig.footerLeft || storage.footerRight !== storage.appliedConfig.footerRight || !deepEqualIterative(storage.appliedConfig.customHeader, storage.customHeader) || !deepEqualIterative(storage.appliedConfig.customFooter, storage.customFooter)
|
|
844
|
+
) {
|
|
845
|
+
return getNewDecoration();
|
|
846
|
+
}
|
|
847
|
+
return oldDeco;
|
|
848
|
+
}
|
|
849
|
+
},
|
|
850
|
+
props: {
|
|
851
|
+
decorations(state) {
|
|
852
|
+
var _a;
|
|
853
|
+
return (_a = this.getState(state)) === null || _a === void 0 ? void 0 : _a.decorations;
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
view: (editorView) => {
|
|
857
|
+
return {
|
|
858
|
+
update: (view) => {
|
|
859
|
+
const { options: _currentOptions, config: pageConfig } = getPageConfig(storage, this.options);
|
|
860
|
+
if (!pageConfig.enabled && !view.dom.hasAttribute("rm-pagination-disabled")) {
|
|
861
|
+
refreshPage(view.dom, false);
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const pageCount = getNewPageCount(view, Object.assign(Object.assign({}, _currentOptions), pageConfig));
|
|
865
|
+
const currentPageCount = getExistingPageCount(view);
|
|
866
|
+
const triggerUpdate = (_footerHeight) => {
|
|
867
|
+
requestAnimationFrame(() => {
|
|
868
|
+
const tr = view.state.tr.setMeta(page_count_meta_key, { footerHeight: _footerHeight });
|
|
869
|
+
view.dispatch(tr);
|
|
870
|
+
});
|
|
871
|
+
};
|
|
872
|
+
if (currentPageCount !== pageCount) {
|
|
873
|
+
triggerUpdate();
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
const headerHeight = getHeaderHeight(view.dom, getCustomPages(_currentOptions.customHeader, {}), "content");
|
|
877
|
+
const footerHeight = getFooterHeight(view.dom, getCustomPages({}, _currentOptions.customFooter), "content");
|
|
878
|
+
const footerHeightForCurrentPages = /* @__PURE__ */ new Map();
|
|
879
|
+
for (let i = 0; i <= pageCount; i++) {
|
|
880
|
+
if (footerHeight.has(i)) {
|
|
881
|
+
footerHeightForCurrentPages.set(i, footerHeight.get(i) || 0);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
const headerHeightForCurrentPages = /* @__PURE__ */ new Map();
|
|
885
|
+
for (let i = 0; i <= pageCount; i++) {
|
|
886
|
+
if (headerHeight.has(i)) {
|
|
887
|
+
headerHeightForCurrentPages.set(i, headerHeight.get(i) || 0);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
const pagesSetToCheck = /* @__PURE__ */ new Set([1, ...footerHeightForCurrentPages.keys(), ...headerHeightForCurrentPages.keys()]);
|
|
891
|
+
let missingPageNumber = void 0;
|
|
892
|
+
for (let i = 1; i <= pageCount; i++) {
|
|
893
|
+
if (!pagesSetToCheck.has(i)) {
|
|
894
|
+
missingPageNumber = i;
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
if (missingPageNumber) {
|
|
899
|
+
pagesSetToCheck.add(missingPageNumber);
|
|
900
|
+
}
|
|
901
|
+
pagesSetToCheck.delete(0);
|
|
902
|
+
let pageContentHeightVariable = {};
|
|
903
|
+
let maxContentHeight = void 0;
|
|
904
|
+
for (const page of pagesSetToCheck) {
|
|
905
|
+
const headerHeight2 = headerHeightForCurrentPages.has(page) ? headerHeightForCurrentPages.get(page) || 0 : headerHeightForCurrentPages.get(0) || 0;
|
|
906
|
+
const footerHeight2 = footerHeightForCurrentPages.has(page) ? footerHeightForCurrentPages.get(page) || 0 : footerHeightForCurrentPages.get(0) || 0;
|
|
907
|
+
const { _pageHeaderHeight, _pageHeight } = getHeight(_currentOptions, headerHeight2, footerHeight2);
|
|
908
|
+
const contentHeight = page === 1 ? _pageHeight + _pageHeaderHeight : _pageHeight;
|
|
909
|
+
if (page === 1) {
|
|
910
|
+
pageContentHeightVariable[`rm-page-content-first`] = `${contentHeight}px`;
|
|
911
|
+
}
|
|
912
|
+
if (page === missingPageNumber) {
|
|
913
|
+
pageContentHeightVariable[`rm-page-content-general`] = `${contentHeight}px`;
|
|
914
|
+
} else {
|
|
915
|
+
pageContentHeightVariable[`rm-page-content-${page}`] = `${contentHeight}px`;
|
|
916
|
+
}
|
|
917
|
+
if (maxContentHeight === void 0 || contentHeight < maxContentHeight) {
|
|
918
|
+
maxContentHeight = contentHeight;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
if (maxContentHeight) {
|
|
922
|
+
view.dom.style.setProperty(`--rm-max-content-child-height`, `${maxContentHeight - 10}px`);
|
|
923
|
+
}
|
|
924
|
+
Object.entries(pageContentHeightVariable).forEach(([key2, value]) => {
|
|
925
|
+
view.dom.style.setProperty(`--${key2}`, value);
|
|
926
|
+
});
|
|
927
|
+
refreshPage(view.dom, _currentOptions.enabled);
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
}),
|
|
933
|
+
new Plugin3({
|
|
934
|
+
key,
|
|
935
|
+
state: {
|
|
936
|
+
init(_, state) {
|
|
937
|
+
return buildDecorations(state.doc);
|
|
938
|
+
},
|
|
939
|
+
apply(tr, old) {
|
|
940
|
+
if (tr.docChanged || tr.steps.some((step) => step instanceof ReplaceStep) || tr.steps.some((step) => step instanceof ReplaceAroundStep) || tr.steps.some((step) => step instanceof AddMarkStep) || tr.steps.some((step) => step instanceof RemoveMarkStep) || tr.steps.some((step) => step instanceof RemoveNodeMarkStep) || tr.steps.some((step) => step instanceof AttrStep)) {
|
|
941
|
+
return buildDecorations(tr.doc);
|
|
942
|
+
}
|
|
943
|
+
return old;
|
|
944
|
+
}
|
|
945
|
+
},
|
|
946
|
+
props: {
|
|
947
|
+
decorations(state) {
|
|
948
|
+
var _a;
|
|
949
|
+
return (_a = key.getState(state)) !== null && _a !== void 0 ? _a : DecorationSet3.empty;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
})
|
|
953
|
+
];
|
|
954
|
+
},
|
|
955
|
+
addCommands() {
|
|
956
|
+
return {
|
|
957
|
+
updatePageBreakBackground: (color) => () => {
|
|
958
|
+
this.storage.pageBreakBackground = color;
|
|
959
|
+
return true;
|
|
960
|
+
},
|
|
961
|
+
updatePageSize: (size) => () => {
|
|
962
|
+
this.storage.pageHeight = size.pageHeight;
|
|
963
|
+
this.storage.pageWidth = size.pageWidth;
|
|
964
|
+
this.storage.marginTop = size.marginTop;
|
|
965
|
+
this.storage.marginBottom = size.marginBottom;
|
|
966
|
+
this.storage.marginLeft = size.marginLeft;
|
|
967
|
+
this.storage.marginRight = size.marginRight;
|
|
968
|
+
return true;
|
|
969
|
+
},
|
|
970
|
+
updatePageWidth: (width) => () => {
|
|
971
|
+
this.storage.pageWidth = width;
|
|
972
|
+
return true;
|
|
973
|
+
},
|
|
974
|
+
updatePageHeight: (height) => () => {
|
|
975
|
+
this.storage.pageHeight = height;
|
|
976
|
+
return true;
|
|
977
|
+
},
|
|
978
|
+
updatePageGap: (gap) => () => {
|
|
979
|
+
this.storage.pageGap = gap;
|
|
980
|
+
return true;
|
|
981
|
+
},
|
|
982
|
+
updateMargins: (margins) => () => {
|
|
983
|
+
this.storage.marginTop = margins.top;
|
|
984
|
+
this.storage.marginBottom = margins.bottom;
|
|
985
|
+
this.storage.marginLeft = margins.left;
|
|
986
|
+
this.storage.marginRight = margins.right;
|
|
987
|
+
return true;
|
|
988
|
+
},
|
|
989
|
+
updateContentMargins: (margins) => () => {
|
|
990
|
+
this.storage.contentMarginTop = margins.top;
|
|
991
|
+
this.storage.contentMarginBottom = margins.bottom;
|
|
992
|
+
return true;
|
|
993
|
+
},
|
|
994
|
+
updateHeaderContent: (left, right, pageNumber) => () => {
|
|
995
|
+
if (pageNumber) {
|
|
996
|
+
this.storage.customHeader = Object.assign(Object.assign({}, this.storage.customHeader), { [pageNumber]: { headerLeft: left, headerRight: right } });
|
|
997
|
+
} else {
|
|
998
|
+
this.storage.headerLeft = left;
|
|
999
|
+
this.storage.headerRight = right;
|
|
1000
|
+
}
|
|
1001
|
+
return true;
|
|
1002
|
+
},
|
|
1003
|
+
updateFooterContent: (left, right, pageNumber) => () => {
|
|
1004
|
+
if (pageNumber) {
|
|
1005
|
+
this.storage.customFooter = Object.assign(Object.assign({}, this.storage.customFooter), { [pageNumber]: { footerLeft: left, footerRight: right } });
|
|
1006
|
+
} else {
|
|
1007
|
+
this.storage.footerLeft = left;
|
|
1008
|
+
this.storage.footerRight = right;
|
|
1009
|
+
}
|
|
1010
|
+
return true;
|
|
1011
|
+
},
|
|
1012
|
+
togglePagination: () => () => {
|
|
1013
|
+
this.storage.enabled = !this.storage.enabled;
|
|
1014
|
+
return true;
|
|
1015
|
+
},
|
|
1016
|
+
enablePagination: () => () => {
|
|
1017
|
+
this.storage.enabled = true;
|
|
1018
|
+
return true;
|
|
1019
|
+
},
|
|
1020
|
+
disablePagination: () => () => {
|
|
1021
|
+
this.storage.enabled = false;
|
|
1022
|
+
return true;
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
var getExistingPageCount = (view) => {
|
|
1028
|
+
const editorDom = view.dom;
|
|
1029
|
+
const paginationElement = editorDom.querySelector("[data-rm-pagination]");
|
|
1030
|
+
if (paginationElement) {
|
|
1031
|
+
return paginationElement.children.length;
|
|
1032
|
+
}
|
|
1033
|
+
return 0;
|
|
1034
|
+
};
|
|
1035
|
+
var calculatePageCount = (view, pageOptions, headerHeight = 0, footerHeight = 0) => {
|
|
1036
|
+
var _a;
|
|
1037
|
+
const editorDom = view.dom;
|
|
1038
|
+
const _pageHeaderHeight = pageOptions.contentMarginTop + pageOptions.marginTop + headerHeight;
|
|
1039
|
+
const _pageFooterHeight = pageOptions.contentMarginBottom + pageOptions.marginBottom + footerHeight;
|
|
1040
|
+
const pageContentAreaHeight = pageOptions.pageHeight - _pageHeaderHeight - _pageFooterHeight;
|
|
1041
|
+
const paginationElement = editorDom.querySelector("[data-rm-pagination]");
|
|
1042
|
+
const currentPageCount = getExistingPageCount(view);
|
|
1043
|
+
if (paginationElement) {
|
|
1044
|
+
const lastElementOfEditor = editorDom.lastElementChild;
|
|
1045
|
+
const lastPageBreak = (_a = paginationElement.lastElementChild) === null || _a === void 0 ? void 0 : _a.querySelector(".breaker");
|
|
1046
|
+
if (lastElementOfEditor && lastPageBreak) {
|
|
1047
|
+
const lastElementRect = lastElementOfEditor.getBoundingClientRect();
|
|
1048
|
+
const lastPageBreakRect = lastPageBreak.getBoundingClientRect();
|
|
1049
|
+
const lastPageGap = lastElementRect.bottom - lastPageBreakRect.bottom;
|
|
1050
|
+
if (lastPageGap > 0) {
|
|
1051
|
+
const addPage = Math.ceil(lastPageGap / pageContentAreaHeight);
|
|
1052
|
+
return currentPageCount + addPage;
|
|
1053
|
+
} else {
|
|
1054
|
+
const allBreaksAfterLastElement = Array.from(paginationElement.querySelectorAll(".breaker"));
|
|
1055
|
+
const allBreaksAfterLastElementRect = allBreaksAfterLastElement.filter((element) => element.getBoundingClientRect().top > lastElementRect.bottom);
|
|
1056
|
+
const removePage = allBreaksAfterLastElementRect.length;
|
|
1057
|
+
if (removePage > 1) {
|
|
1058
|
+
return currentPageCount - removePage;
|
|
1059
|
+
} else {
|
|
1060
|
+
return currentPageCount;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
return 1;
|
|
1065
|
+
} else {
|
|
1066
|
+
const editorHeight = editorDom.scrollHeight;
|
|
1067
|
+
let pageCount = Math.ceil(editorHeight / pageContentAreaHeight);
|
|
1068
|
+
pageCount = pageCount <= 0 ? 1 : pageCount;
|
|
1069
|
+
return pageCount;
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
var getNewPageCount = (view, pageOptions) => {
|
|
1073
|
+
if (pageOptions.enabled) {
|
|
1074
|
+
const pageCount = calculatePageCount(view, pageOptions);
|
|
1075
|
+
return pageCount <= 1 ? 1 : pageCount;
|
|
1076
|
+
} else {
|
|
1077
|
+
return 0;
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
function createDecoration(pageOptions, headerHeightMap, footerHeightMap) {
|
|
1081
|
+
if (!pageOptions.enabled) {
|
|
1082
|
+
return [];
|
|
1083
|
+
}
|
|
1084
|
+
const commonHeaderOptions = { headerLeft: pageOptions.headerLeft, headerRight: pageOptions.headerRight };
|
|
1085
|
+
const commonFooterOptions = { footerLeft: pageOptions.footerLeft, footerRight: pageOptions.footerRight };
|
|
1086
|
+
const pageWidget = Decoration3.widget(0, (view) => {
|
|
1087
|
+
const _pageGap = pageOptions.pageGap;
|
|
1088
|
+
const _pageBreakBackground = pageOptions.pageBreakBackground;
|
|
1089
|
+
const el = document.createElement("div");
|
|
1090
|
+
el.dataset.rmPagination = "true";
|
|
1091
|
+
const pageBreakDefinition = (firstPage, pageHeader, pageFooter, headerHeight, footerHeight, pageNumber) => {
|
|
1092
|
+
const { _pageHeaderHeight, _pageHeight } = getHeight(pageOptions, headerHeight, footerHeight);
|
|
1093
|
+
const pageContainer = document.createElement("div");
|
|
1094
|
+
pageContainer.classList.add("rm-page-break");
|
|
1095
|
+
const page = document.createElement("div");
|
|
1096
|
+
page.classList.add("page");
|
|
1097
|
+
page.style.position = "relative";
|
|
1098
|
+
page.style.float = "left";
|
|
1099
|
+
page.style.clear = "both";
|
|
1100
|
+
const marginTop = firstPage ? `calc(${_pageHeaderHeight}px + ${_pageHeight}px)` : _pageHeight + "px";
|
|
1101
|
+
if (pageNumber) {
|
|
1102
|
+
page.style.marginTop = `var(--rm-page-content-${pageNumber}, ${marginTop})`;
|
|
1103
|
+
} else {
|
|
1104
|
+
page.style.marginTop = firstPage ? `var(--rm-page-content-first, ${marginTop})` : `var(--rm-page-content-general, ${marginTop})`;
|
|
1105
|
+
}
|
|
1106
|
+
const pageBreak = document.createElement("div");
|
|
1107
|
+
pageBreak.classList.add("breaker");
|
|
1108
|
+
pageBreak.style.width = `calc(100% + var(--rm-margin-left) + var(--rm-margin-right))`;
|
|
1109
|
+
pageBreak.style.marginLeft = `calc(-1 * var(--rm-margin-left))`;
|
|
1110
|
+
pageBreak.style.marginRight = `calc(-1 * var(--rm-margin-right))`;
|
|
1111
|
+
pageBreak.style.position = "relative";
|
|
1112
|
+
pageBreak.style.float = "left";
|
|
1113
|
+
pageBreak.style.clear = "both";
|
|
1114
|
+
pageBreak.style.left = `0px`;
|
|
1115
|
+
pageBreak.style.right = `0px`;
|
|
1116
|
+
pageBreak.style.zIndex = "2";
|
|
1117
|
+
const pageSpace = document.createElement("div");
|
|
1118
|
+
pageSpace.classList.add("rm-pagination-gap");
|
|
1119
|
+
pageSpace.style.height = _pageGap + "px";
|
|
1120
|
+
pageSpace.style.borderLeft = "1px solid";
|
|
1121
|
+
pageSpace.style.borderRight = "1px solid";
|
|
1122
|
+
pageSpace.style.position = "relative";
|
|
1123
|
+
pageSpace.style.setProperty("width", "calc(100% + 2px)", "important");
|
|
1124
|
+
pageSpace.style.left = "-1px";
|
|
1125
|
+
pageSpace.style.backgroundColor = _pageBreakBackground;
|
|
1126
|
+
pageSpace.style.borderLeftColor = _pageBreakBackground;
|
|
1127
|
+
pageSpace.style.borderRightColor = _pageBreakBackground;
|
|
1128
|
+
pageBreak.append(pageFooter, pageSpace, pageHeader);
|
|
1129
|
+
pageContainer.append(page, pageBreak);
|
|
1130
|
+
return pageContainer;
|
|
1131
|
+
};
|
|
1132
|
+
const _headerHeight = headerHeightMap.get(0) || 0;
|
|
1133
|
+
const _footerHeight = footerHeightMap.get(0) || 0;
|
|
1134
|
+
const fragment = document.createDocumentFragment();
|
|
1135
|
+
const pageCount = getNewPageCount(view, pageOptions);
|
|
1136
|
+
for (let i = 0; i < pageCount; i++) {
|
|
1137
|
+
const pageNumber = i + 1;
|
|
1138
|
+
const headerPageNumber = i + 2;
|
|
1139
|
+
if (headerPageNumber in pageOptions.customHeader || pageNumber in pageOptions.customFooter || pageNumber in pageOptions.customHeader) {
|
|
1140
|
+
let _headerOptions = commonHeaderOptions;
|
|
1141
|
+
let _footerOptions = commonFooterOptions;
|
|
1142
|
+
let _pageHeaderHeight = _headerHeight;
|
|
1143
|
+
let _pageFooterHeight = _footerHeight;
|
|
1144
|
+
if (headerPageNumber in pageOptions.customHeader) {
|
|
1145
|
+
_headerOptions = pageOptions.customHeader[headerPageNumber] || commonHeaderOptions;
|
|
1146
|
+
_pageHeaderHeight = headerHeightMap.get(headerPageNumber) || 0;
|
|
1147
|
+
}
|
|
1148
|
+
if (pageNumber in pageOptions.customFooter) {
|
|
1149
|
+
_footerOptions = pageOptions.customFooter[pageNumber] || commonFooterOptions;
|
|
1150
|
+
_pageFooterHeight = footerHeightMap.get(pageNumber) || 0;
|
|
1151
|
+
}
|
|
1152
|
+
let _pageHeader = getHeader(_headerOptions.headerRight, _headerOptions.headerLeft, headerClickEvent(headerPageNumber, pageOptions.onHeaderClick), headerPageNumber);
|
|
1153
|
+
let _pageFooter = getFooter(_footerOptions.footerRight, _footerOptions.footerLeft, footerClickEvent(pageNumber, pageOptions.onFooterClick), pageNumber);
|
|
1154
|
+
let pageBreak = pageBreakDefinition(i === 0, _pageHeader, _pageFooter, _pageHeaderHeight, _pageFooterHeight, pageNumber);
|
|
1155
|
+
fragment.appendChild(pageBreak);
|
|
1156
|
+
} else {
|
|
1157
|
+
const __pageHeader = getHeader(commonHeaderOptions.headerRight, commonHeaderOptions.headerLeft, headerClickEvent(headerPageNumber, pageOptions.onHeaderClick));
|
|
1158
|
+
const __pageFooter = getFooter(commonFooterOptions.footerRight, commonFooterOptions.footerLeft, footerClickEvent(pageNumber, pageOptions.onFooterClick));
|
|
1159
|
+
fragment.appendChild(pageBreakDefinition(i === 0, __pageHeader, __pageFooter, _headerHeight, _footerHeight));
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
el.append(fragment);
|
|
1163
|
+
el.id = "pages";
|
|
1164
|
+
el.classList.add("rm-pages-wrapper");
|
|
1165
|
+
return el;
|
|
1166
|
+
}, { side: -1 });
|
|
1167
|
+
const firstHeaderWidget = Decoration3.widget(0, () => {
|
|
1168
|
+
const pageNumber = 1;
|
|
1169
|
+
let _headerOptions = commonHeaderOptions;
|
|
1170
|
+
if (pageNumber in pageOptions.customHeader) {
|
|
1171
|
+
_headerOptions = pageOptions.customHeader[pageNumber];
|
|
1172
|
+
}
|
|
1173
|
+
const el = getHeader(_headerOptions.headerRight, _headerOptions.headerLeft, headerClickEvent(pageNumber, pageOptions.onHeaderClick));
|
|
1174
|
+
el.classList.add("rm-first-page-header");
|
|
1175
|
+
return el;
|
|
1176
|
+
}, { side: -1 });
|
|
1177
|
+
return [pageWidget, firstHeaderWidget];
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// ../../node_modules/.pnpm/tiptap-pagination-plus@3.1.0_@tiptap+core@2.27.2_@tiptap+pm@2.27.2__@tiptap+pm@2.27.2/node_modules/tiptap-pagination-plus/dist/constants.js
|
|
1181
|
+
var A4_PAGE_SIZE = getPageSize(1123, 794, 95, 95, 76, 76);
|
|
1182
|
+
var A3_PAGE_SIZE = getPageSize(1591, 1123, 95, 95, 76, 76);
|
|
1183
|
+
var A5_PAGE_SIZE = getPageSize(794, 419, 76, 76, 57, 57);
|
|
1184
|
+
var LETTER_PAGE_SIZE = getPageSize(1060, 818, 96, 96, 96, 96);
|
|
1185
|
+
var LEGAL_PAGE_SIZE = getPageSize(1404, 818, 96, 96, 96, 96);
|
|
1186
|
+
var TABLOID_PAGE_SIZE = getPageSize(1635, 1060, 96, 96, 96, 96);
|
|
1187
|
+
var PAGE_SIZES = {
|
|
1188
|
+
A4: A4_PAGE_SIZE,
|
|
1189
|
+
A3: A3_PAGE_SIZE,
|
|
1190
|
+
A5: A5_PAGE_SIZE,
|
|
1191
|
+
LETTER: LETTER_PAGE_SIZE,
|
|
1192
|
+
LEGAL: LEGAL_PAGE_SIZE,
|
|
1193
|
+
TABLOID: TABLOID_PAGE_SIZE
|
|
1194
|
+
};
|
|
1195
|
+
|
|
192
1196
|
// src/Editor.ts
|
|
193
|
-
|
|
1197
|
+
function sanitizePastedHTML(html) {
|
|
1198
|
+
let cleaned = html.replace(/<meta[^>]*>/gi, "");
|
|
1199
|
+
cleaned = cleaned.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "");
|
|
1200
|
+
cleaned = cleaned.replace(/<!--[\s\S]*?-->/g, "");
|
|
1201
|
+
cleaned = cleaned.replace(/<link[^>]*>/gi, "");
|
|
1202
|
+
cleaned = cleaned.replace(/<base[^>]*>/gi, "");
|
|
1203
|
+
cleaned = cleaned.replace(/<title[^>]*>[\s\S]*?<\/title>/gi, "");
|
|
1204
|
+
{
|
|
1205
|
+
for (let pass = 0; pass < 10; pass++) {
|
|
1206
|
+
const before = cleaned;
|
|
1207
|
+
cleaned = cleaned.replace(
|
|
1208
|
+
/<span\s([^>]*style\s*=\s*["'][^"']*(?:background-color|background)[^"']*["'][^>]*)>([^<]*(?:<(?!\/?span)[^>]*>[^<]*)*)<\/span>/gi,
|
|
1209
|
+
(_full, attrs, content) => {
|
|
1210
|
+
if (!/background(?:-color)?\s*:/.test(attrs)) return _full;
|
|
1211
|
+
const colorMatch = attrs.match(/(?<!background-)color\s*:\s*([^;"]+)/i);
|
|
1212
|
+
const colorVal = colorMatch ? colorMatch[1].trim() : null;
|
|
1213
|
+
const markAttrs = colorVal ? attrs.replace(/(?<!background-)color\s*:\s*[^;"]+;?\s*/gi, "").trim() : attrs;
|
|
1214
|
+
if (colorVal) {
|
|
1215
|
+
return `<mark ${markAttrs}><span style="color: ${colorVal};">${content}</span></mark>`;
|
|
1216
|
+
}
|
|
1217
|
+
return `<mark ${markAttrs}>${content}</mark>`;
|
|
1218
|
+
}
|
|
1219
|
+
);
|
|
1220
|
+
if (cleaned === before) break;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
cleaned = cleaned.replace(
|
|
1224
|
+
/<b\s[^>]*style\s*=\s*["'][^"']*font-weight:\s*normal[^"']*["'][^>]*>/gi,
|
|
1225
|
+
""
|
|
1226
|
+
);
|
|
1227
|
+
cleaned = cleaned.replace(/<\/b>/gi, "");
|
|
1228
|
+
cleaned = cleaned.replace(/\sid\s*=\s*["']docs-internal[^"']*["']/gi, "");
|
|
1229
|
+
return cleaned;
|
|
1230
|
+
}
|
|
194
1231
|
function migrateContent(content) {
|
|
195
1232
|
if (!content) return content;
|
|
196
1233
|
if (typeof content === "string") {
|
|
@@ -290,20 +1327,338 @@ function createTiptapEditor(options, plugins, collaborationSetup) {
|
|
|
290
1327
|
const pluginExtensions = collectExtensions(plugins);
|
|
291
1328
|
const blockAttrs = options.getPageMap ? BlockAttributesExtension.configure({ pageMap: options.getPageMap }) : BlockAttributesExtension;
|
|
292
1329
|
const paginationExt = options.paginationOptions ? PaginationPlus.configure(options.paginationOptions) : PaginationPlus;
|
|
1330
|
+
const ManualColumnResize = Extension5.create({
|
|
1331
|
+
name: "manualColumnResize",
|
|
1332
|
+
addProseMirrorPlugins() {
|
|
1333
|
+
const key2 = new PluginKey4("manualColumnResize");
|
|
1334
|
+
return [new Plugin4({
|
|
1335
|
+
key: key2,
|
|
1336
|
+
view(view) {
|
|
1337
|
+
function pauseObserver() {
|
|
1338
|
+
try {
|
|
1339
|
+
view.domObserver?.stop?.();
|
|
1340
|
+
} catch (_) {
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
function resumeObserver() {
|
|
1344
|
+
try {
|
|
1345
|
+
view.domObserver?.start?.();
|
|
1346
|
+
} catch (_) {
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
function getMaxContainerWidth(tableEl) {
|
|
1350
|
+
let curr = tableEl.parentElement;
|
|
1351
|
+
while (curr) {
|
|
1352
|
+
const style = window.getComputedStyle(curr);
|
|
1353
|
+
const paddingLeft = parseFloat(style.paddingLeft) || 0;
|
|
1354
|
+
const paddingRight = parseFloat(style.paddingRight) || 0;
|
|
1355
|
+
const availWidth = curr.clientWidth - paddingLeft - paddingRight;
|
|
1356
|
+
if (availWidth > 100 && (curr.classList.contains("docs-editor__paper") || curr.classList.contains("docs-editor-page") || curr.classList.contains("ProseMirror") || curr.classList.contains("rm-with-pagination"))) {
|
|
1357
|
+
return availWidth;
|
|
1358
|
+
}
|
|
1359
|
+
curr = curr.parentElement;
|
|
1360
|
+
}
|
|
1361
|
+
return tableEl.parentElement?.clientWidth || 614;
|
|
1362
|
+
}
|
|
1363
|
+
const onMouseDown = function(event) {
|
|
1364
|
+
if (event.button !== 0) return;
|
|
1365
|
+
const td = event.target.closest("td, th");
|
|
1366
|
+
if (!td) return;
|
|
1367
|
+
const r = td.getBoundingClientRect();
|
|
1368
|
+
const parent = td.parentElement;
|
|
1369
|
+
if (!parent) return;
|
|
1370
|
+
const colIdx = Array.from(parent.children).indexOf(td);
|
|
1371
|
+
if (colIdx === -1) return;
|
|
1372
|
+
const table = td.closest("table");
|
|
1373
|
+
if (!table) return;
|
|
1374
|
+
const distRight = Math.abs(event.clientX - r.right);
|
|
1375
|
+
const distLeft = Math.abs(event.clientX - r.left);
|
|
1376
|
+
let targetColIdx = -1;
|
|
1377
|
+
if (distRight <= 16) {
|
|
1378
|
+
targetColIdx = colIdx;
|
|
1379
|
+
} else if (distLeft <= 16 && colIdx > 0) {
|
|
1380
|
+
targetColIdx = colIdx - 1;
|
|
1381
|
+
} else {
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
const colsList = table.querySelectorAll("colgroup col");
|
|
1385
|
+
const totalCols = colsList.length || table.querySelector("tr")?.children.length || 0;
|
|
1386
|
+
const allColWidths = [];
|
|
1387
|
+
for (let c = 0; c < totalCols; c++) {
|
|
1388
|
+
const colEl = colsList[c];
|
|
1389
|
+
const w = colEl ? parseFloat(colEl.style.width) : 0;
|
|
1390
|
+
allColWidths[c] = w || initialWidth(table, c);
|
|
1391
|
+
}
|
|
1392
|
+
const isLastCol = targetColIdx === totalCols - 1;
|
|
1393
|
+
const startX = event.clientX;
|
|
1394
|
+
const startW = allColWidths[targetColIdx] || initialWidth(table, targetColIdx);
|
|
1395
|
+
const maxContainerW = getMaxContainerWidth(table);
|
|
1396
|
+
let otherColsW = 0;
|
|
1397
|
+
allColWidths.forEach((w, idx) => {
|
|
1398
|
+
if (idx !== targetColIdx) {
|
|
1399
|
+
otherColsW += w;
|
|
1400
|
+
}
|
|
1401
|
+
});
|
|
1402
|
+
const maxNw = Math.max(20, maxContainerW - otherColsW);
|
|
1403
|
+
function updateDOMWidths(targetIdx, targetW) {
|
|
1404
|
+
let totalWidth = 0;
|
|
1405
|
+
allColWidths.forEach((_, idx) => {
|
|
1406
|
+
const w = idx === targetIdx ? targetW : allColWidths[idx];
|
|
1407
|
+
const col = table.querySelector(`colgroup col:nth-child(${idx + 1})`);
|
|
1408
|
+
if (col) col.style.setProperty("width", w + "px", "important");
|
|
1409
|
+
table.querySelectorAll("tr").forEach(function(row) {
|
|
1410
|
+
const cell = row.children[idx];
|
|
1411
|
+
if (cell) {
|
|
1412
|
+
cell.style.setProperty("width", w + "px", "important");
|
|
1413
|
+
cell.setAttribute("width", String(w));
|
|
1414
|
+
}
|
|
1415
|
+
});
|
|
1416
|
+
totalWidth += w;
|
|
1417
|
+
});
|
|
1418
|
+
if (totalWidth > 0) {
|
|
1419
|
+
table.style.setProperty("width", Math.min(totalWidth, maxContainerW) + "px", "important");
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
event.stopPropagation();
|
|
1423
|
+
let lastNw = startW;
|
|
1424
|
+
let moveCount = 0;
|
|
1425
|
+
const onMove = function(e) {
|
|
1426
|
+
moveCount++;
|
|
1427
|
+
if (!e.buttons) {
|
|
1428
|
+
onUp(e);
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
const diff = e.clientX - startX;
|
|
1432
|
+
const nw = Math.min(maxNw, Math.max(20, startW + diff));
|
|
1433
|
+
lastNw = nw;
|
|
1434
|
+
let borderPos = table.getBoundingClientRect().left;
|
|
1435
|
+
for (let i = 0; i <= targetColIdx; i++) {
|
|
1436
|
+
borderPos += i === targetColIdx ? nw : allColWidths[i];
|
|
1437
|
+
}
|
|
1438
|
+
showLine(table, borderPos);
|
|
1439
|
+
pauseObserver();
|
|
1440
|
+
updateDOMWidths(targetColIdx, nw);
|
|
1441
|
+
resumeObserver();
|
|
1442
|
+
};
|
|
1443
|
+
const onUp = function(upEvent) {
|
|
1444
|
+
document.removeEventListener("mousemove", onMove);
|
|
1445
|
+
document.removeEventListener("mouseup", onUp, true);
|
|
1446
|
+
upEvent.stopPropagation();
|
|
1447
|
+
hideLine();
|
|
1448
|
+
if (lastNw === startW) return;
|
|
1449
|
+
allColWidths[targetColIdx] = lastNw;
|
|
1450
|
+
console.log("[Resize] onUp:", { lastNw, startW, isLastCol, targetColIdx, allColWidths });
|
|
1451
|
+
try {
|
|
1452
|
+
const { state } = view;
|
|
1453
|
+
const { doc } = state;
|
|
1454
|
+
let tablePos = -1;
|
|
1455
|
+
doc.descendants((node, pos) => {
|
|
1456
|
+
if (tablePos >= 0) return false;
|
|
1457
|
+
if (node.type.name === "table") {
|
|
1458
|
+
try {
|
|
1459
|
+
const dom = view.nodeDOM(pos);
|
|
1460
|
+
if (dom === table || dom instanceof HTMLElement && dom.contains(table) || table.contains(dom)) {
|
|
1461
|
+
tablePos = pos;
|
|
1462
|
+
return false;
|
|
1463
|
+
}
|
|
1464
|
+
} catch (_) {
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
return true;
|
|
1468
|
+
});
|
|
1469
|
+
if (tablePos >= 0) {
|
|
1470
|
+
const tableNode = doc.nodeAt(tablePos);
|
|
1471
|
+
if (tableNode) {
|
|
1472
|
+
const tr = state.tr;
|
|
1473
|
+
let cellsUpdated = 0;
|
|
1474
|
+
tableNode.forEach((row, rowOffset) => {
|
|
1475
|
+
let cellColIdx = 0;
|
|
1476
|
+
row.forEach((cell, cellOffset) => {
|
|
1477
|
+
const colspan = cell.attrs.colspan || 1;
|
|
1478
|
+
const cellPos = tablePos + 1 + rowOffset + 1 + cellOffset;
|
|
1479
|
+
const cw = new Array(colspan);
|
|
1480
|
+
for (let k = 0; k < colspan; k++) {
|
|
1481
|
+
cw[k] = allColWidths[cellColIdx + k] || 100;
|
|
1482
|
+
}
|
|
1483
|
+
tr.setNodeMarkup(cellPos, null, { ...cell.attrs, colwidth: cw });
|
|
1484
|
+
cellsUpdated++;
|
|
1485
|
+
cellColIdx += colspan;
|
|
1486
|
+
});
|
|
1487
|
+
});
|
|
1488
|
+
view.dispatch(tr);
|
|
1489
|
+
pauseObserver();
|
|
1490
|
+
updateDOMWidths(targetColIdx, lastNw);
|
|
1491
|
+
resumeObserver();
|
|
1492
|
+
}
|
|
1493
|
+
} else {
|
|
1494
|
+
console.warn("[Resize] could not find table position in doc");
|
|
1495
|
+
}
|
|
1496
|
+
} catch (err) {
|
|
1497
|
+
console.warn("[Resize] transaction failed, falling back to DOM:", err);
|
|
1498
|
+
pauseObserver();
|
|
1499
|
+
updateDOMWidths(targetColIdx, lastNw);
|
|
1500
|
+
resumeObserver();
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
document.addEventListener("mousemove", onMove);
|
|
1504
|
+
document.addEventListener("mouseup", onUp, true);
|
|
1505
|
+
};
|
|
1506
|
+
function initialWidth(table, colIdx) {
|
|
1507
|
+
const firstRow = table.querySelector("tr");
|
|
1508
|
+
if (!firstRow) return 100;
|
|
1509
|
+
const cell = firstRow.children[colIdx];
|
|
1510
|
+
if (!cell) return 100;
|
|
1511
|
+
return Math.round(cell.getBoundingClientRect().width) || cell.offsetWidth || 100;
|
|
1512
|
+
}
|
|
1513
|
+
let lineEl = null;
|
|
1514
|
+
let isDragging = false;
|
|
1515
|
+
function getOrCreateLine() {
|
|
1516
|
+
if (!lineEl) {
|
|
1517
|
+
lineEl = document.createElement("div");
|
|
1518
|
+
lineEl.className = "docflow-active-border-line";
|
|
1519
|
+
Object.assign(lineEl.style, {
|
|
1520
|
+
position: "fixed",
|
|
1521
|
+
width: "3px",
|
|
1522
|
+
background: "#06b6d4",
|
|
1523
|
+
boxShadow: "0 0 8px rgba(6, 182, 212, 0.9)",
|
|
1524
|
+
pointerEvents: "none",
|
|
1525
|
+
zIndex: "999999",
|
|
1526
|
+
display: "none",
|
|
1527
|
+
borderRadius: "1.5px"
|
|
1528
|
+
});
|
|
1529
|
+
const dotTop = document.createElement("div");
|
|
1530
|
+
Object.assign(dotTop.style, {
|
|
1531
|
+
position: "absolute",
|
|
1532
|
+
top: "-4px",
|
|
1533
|
+
left: "-3.5px",
|
|
1534
|
+
width: "10px",
|
|
1535
|
+
height: "10px",
|
|
1536
|
+
borderRadius: "50%",
|
|
1537
|
+
background: "#ffffff",
|
|
1538
|
+
border: "2px solid #06b6d4"
|
|
1539
|
+
});
|
|
1540
|
+
const dotBottom = document.createElement("div");
|
|
1541
|
+
Object.assign(dotBottom.style, {
|
|
1542
|
+
position: "absolute",
|
|
1543
|
+
bottom: "-4px",
|
|
1544
|
+
left: "-3.5px",
|
|
1545
|
+
width: "10px",
|
|
1546
|
+
height: "10px",
|
|
1547
|
+
borderRadius: "50%",
|
|
1548
|
+
background: "#ffffff",
|
|
1549
|
+
border: "2px solid #06b6d4"
|
|
1550
|
+
});
|
|
1551
|
+
lineEl.appendChild(dotTop);
|
|
1552
|
+
lineEl.appendChild(dotBottom);
|
|
1553
|
+
document.body.appendChild(lineEl);
|
|
1554
|
+
}
|
|
1555
|
+
return lineEl;
|
|
1556
|
+
}
|
|
1557
|
+
function showLine(table, borderX) {
|
|
1558
|
+
const line = getOrCreateLine();
|
|
1559
|
+
const tableRect = table.getBoundingClientRect();
|
|
1560
|
+
line.style.left = `${borderX - 1.5}px`;
|
|
1561
|
+
line.style.top = `${tableRect.top}px`;
|
|
1562
|
+
line.style.height = `${tableRect.height}px`;
|
|
1563
|
+
line.style.display = "block";
|
|
1564
|
+
document.body.style.cursor = "col-resize";
|
|
1565
|
+
view.dom.style.cursor = "col-resize";
|
|
1566
|
+
}
|
|
1567
|
+
function hideLine() {
|
|
1568
|
+
if (lineEl) {
|
|
1569
|
+
lineEl.style.display = "none";
|
|
1570
|
+
}
|
|
1571
|
+
document.body.style.cursor = "";
|
|
1572
|
+
view.dom.style.cursor = "";
|
|
1573
|
+
}
|
|
1574
|
+
const onMouseMoveHover = function(event) {
|
|
1575
|
+
if (isDragging) return;
|
|
1576
|
+
const target = event.target;
|
|
1577
|
+
const td = target.closest("td, th");
|
|
1578
|
+
if (!td) {
|
|
1579
|
+
hideLine();
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1582
|
+
const r = td.getBoundingClientRect();
|
|
1583
|
+
const distRight = Math.abs(event.clientX - r.right);
|
|
1584
|
+
const distLeft = Math.abs(event.clientX - r.left);
|
|
1585
|
+
const parent = td.parentElement;
|
|
1586
|
+
if (!parent) {
|
|
1587
|
+
hideLine();
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
const colIdx = Array.from(parent.children).indexOf(td);
|
|
1591
|
+
let borderX = -1;
|
|
1592
|
+
if (distRight <= 16) {
|
|
1593
|
+
borderX = r.right;
|
|
1594
|
+
} else if (distLeft <= 16 && colIdx > 0) {
|
|
1595
|
+
borderX = r.left;
|
|
1596
|
+
}
|
|
1597
|
+
if (borderX >= 0) {
|
|
1598
|
+
const table = td.closest("table");
|
|
1599
|
+
if (table) {
|
|
1600
|
+
showLine(table, borderX);
|
|
1601
|
+
}
|
|
1602
|
+
} else {
|
|
1603
|
+
hideLine();
|
|
1604
|
+
}
|
|
1605
|
+
};
|
|
1606
|
+
document.addEventListener("mousemove", onMouseMoveHover, true);
|
|
1607
|
+
view.dom.addEventListener("mousedown", function handleMouseDown(event) {
|
|
1608
|
+
onMouseDown(event);
|
|
1609
|
+
const td = event.target.closest("td, th");
|
|
1610
|
+
if (!td) return;
|
|
1611
|
+
const r = td.getBoundingClientRect();
|
|
1612
|
+
const distRight = Math.abs(event.clientX - r.right);
|
|
1613
|
+
const distLeft = Math.abs(event.clientX - r.left);
|
|
1614
|
+
const parent = td.parentElement;
|
|
1615
|
+
if (!parent) return;
|
|
1616
|
+
const colIdx = Array.from(parent.children).indexOf(td);
|
|
1617
|
+
if (distRight <= 16 || distLeft <= 16 && colIdx > 0) {
|
|
1618
|
+
isDragging = true;
|
|
1619
|
+
hideLine();
|
|
1620
|
+
const onDragEnd = function() {
|
|
1621
|
+
isDragging = false;
|
|
1622
|
+
hideLine();
|
|
1623
|
+
document.removeEventListener("mouseup", onDragEnd, true);
|
|
1624
|
+
};
|
|
1625
|
+
document.addEventListener("mouseup", onDragEnd, true);
|
|
1626
|
+
}
|
|
1627
|
+
}, true);
|
|
1628
|
+
return {
|
|
1629
|
+
destroy: function() {
|
|
1630
|
+
document.removeEventListener("mousemove", onMouseMoveHover, true);
|
|
1631
|
+
if (lineEl && lineEl.parentElement) {
|
|
1632
|
+
lineEl.parentElement.removeChild(lineEl);
|
|
1633
|
+
}
|
|
1634
|
+
lineEl = null;
|
|
1635
|
+
hideLine();
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
})];
|
|
1640
|
+
}
|
|
1641
|
+
});
|
|
293
1642
|
let extensions = [
|
|
1643
|
+
ManualColumnResize,
|
|
294
1644
|
baseStarterKit,
|
|
295
1645
|
TextStyle,
|
|
296
1646
|
blockAttrs,
|
|
297
1647
|
paginationExt,
|
|
1648
|
+
// Always present — carries host-injected ports (onImageUpload, citation, …)
|
|
1649
|
+
// in storage so plugin commands can reach them through the editor instance.
|
|
1650
|
+
EditorContextExtension.configure({
|
|
1651
|
+
onImageUpload: options.onImageUpload,
|
|
1652
|
+
citation: options.citation,
|
|
1653
|
+
aiStream: options.aiStream,
|
|
1654
|
+
aiDraft: options.aiDraft
|
|
1655
|
+
}),
|
|
1656
|
+
// Always present — find & replace decorations + state (core editing infra).
|
|
1657
|
+
SearchAndReplaceExtension,
|
|
298
1658
|
...pluginExtensions
|
|
299
1659
|
];
|
|
300
1660
|
const content = options.collaboration ? void 0 : options.content;
|
|
301
1661
|
if (options.collaboration && collaborationSetup) {
|
|
302
|
-
const fragment = collaborationSetup.ydoc.getXmlFragment("default");
|
|
303
|
-
if (fragment.length === 0 && options.content && typeof options.content === "object") {
|
|
304
|
-
const schema = getSchema([baseStarterKit, TextStyle, blockAttrs, paginationExt, ...pluginExtensions]);
|
|
305
|
-
prosemirrorJSONToYXmlFragment(schema, options.content, fragment);
|
|
306
|
-
}
|
|
307
1662
|
extensions = [...extensions, ...collaborationExtensions(collaborationSetup)];
|
|
308
1663
|
}
|
|
309
1664
|
return new TiptapEditor({
|
|
@@ -313,12 +1668,18 @@ function createTiptapEditor(options, plugins, collaborationSetup) {
|
|
|
313
1668
|
editable: options.editable ?? true,
|
|
314
1669
|
onUpdate: ({ editor }) => {
|
|
315
1670
|
options.onUpdate?.(editor.getJSON());
|
|
1671
|
+
},
|
|
1672
|
+
editorProps: {
|
|
1673
|
+
// Sanitize pasted HTML (strips <meta>, <style>, comments, etc.)
|
|
1674
|
+
// before ProseMirror parsing. Prevents crashes from non-content
|
|
1675
|
+
// tags commonly produced by Google Docs clipboard data.
|
|
1676
|
+
transformPastedHTML: sanitizePastedHTML
|
|
316
1677
|
}
|
|
317
1678
|
});
|
|
318
1679
|
}
|
|
319
1680
|
|
|
320
1681
|
// src/FontSize.ts
|
|
321
|
-
import { Extension as
|
|
1682
|
+
import { Extension as Extension6 } from "@tiptap/core";
|
|
322
1683
|
function mergeFontSize(textStyleType, existing, fontSize) {
|
|
323
1684
|
if (fontSize === null) {
|
|
324
1685
|
const { fontSize: _removed, ...rest } = existing?.attrs ?? {};
|
|
@@ -329,7 +1690,7 @@ function mergeFontSize(textStyleType, existing, fontSize) {
|
|
|
329
1690
|
function hasAttrs(mark) {
|
|
330
1691
|
return Object.values(mark.attrs).some((v) => v != null);
|
|
331
1692
|
}
|
|
332
|
-
var FontSizeExtension =
|
|
1693
|
+
var FontSizeExtension = Extension6.create({
|
|
333
1694
|
name: "fontSize",
|
|
334
1695
|
addGlobalAttributes() {
|
|
335
1696
|
return [
|
|
@@ -427,18 +1788,135 @@ var FontSizeExtension = Extension2.create({
|
|
|
427
1788
|
}
|
|
428
1789
|
});
|
|
429
1790
|
|
|
430
|
-
// src/
|
|
431
|
-
import {
|
|
1791
|
+
// src/SubdocumentProvider.ts
|
|
1792
|
+
import { Awareness as AwarenessClass } from "y-protocols/awareness";
|
|
1793
|
+
import { WebsocketProvider as WebsocketProvider2 } from "y-websocket";
|
|
1794
|
+
import * as Y2 from "yjs";
|
|
1795
|
+
var SubdocumentProvider = class {
|
|
1796
|
+
parentDoc;
|
|
1797
|
+
subdocs;
|
|
1798
|
+
awareness;
|
|
1799
|
+
options;
|
|
1800
|
+
states = /* @__PURE__ */ new Map();
|
|
1801
|
+
activeQueue = [];
|
|
1802
|
+
parentProvider = null;
|
|
1803
|
+
constructor(options) {
|
|
1804
|
+
this.options = {
|
|
1805
|
+
maxActive: options.maxActive ?? 5,
|
|
1806
|
+
onStateChange: options.onStateChange ?? (() => {
|
|
1807
|
+
}),
|
|
1808
|
+
...options
|
|
1809
|
+
};
|
|
1810
|
+
this.parentDoc = new Y2.Doc();
|
|
1811
|
+
this.subdocs = this.parentDoc.getMap("subdocs");
|
|
1812
|
+
this.awareness = new AwarenessClass(this.parentDoc);
|
|
1813
|
+
this.awareness.setLocalStateField("user", this.options.user);
|
|
1814
|
+
this.parentProvider = new WebsocketProvider2(
|
|
1815
|
+
this.options.websocketUrl,
|
|
1816
|
+
`${this.options.roomPrefix}/_parent`,
|
|
1817
|
+
this.parentDoc
|
|
1818
|
+
);
|
|
1819
|
+
}
|
|
1820
|
+
/** Create a new subdocument. Does NOT activate it. */
|
|
1821
|
+
createSubdoc(id, initialState) {
|
|
1822
|
+
if (this.states.has(id)) return this.states.get(id).doc;
|
|
1823
|
+
const doc = new Y2.Doc();
|
|
1824
|
+
if (initialState) Y2.applyUpdate(doc, initialState);
|
|
1825
|
+
doc.getXmlFragment("default");
|
|
1826
|
+
this.subdocs.set(id, doc);
|
|
1827
|
+
this.states.set(id, {
|
|
1828
|
+
id,
|
|
1829
|
+
doc,
|
|
1830
|
+
provider: null,
|
|
1831
|
+
active: false
|
|
1832
|
+
});
|
|
1833
|
+
this.options.onStateChange(this.getAllStates());
|
|
1834
|
+
return doc;
|
|
1835
|
+
}
|
|
1836
|
+
/** Activate a subdocument — connects it to the network for live sync. */
|
|
1837
|
+
activate(id) {
|
|
1838
|
+
const state = this.states.get(id);
|
|
1839
|
+
if (!state || state.active) return;
|
|
1840
|
+
if (this.activeQueue.length >= this.options.maxActive) {
|
|
1841
|
+
const oldest = this.activeQueue.shift();
|
|
1842
|
+
if (oldest) this.deactivate(oldest);
|
|
1843
|
+
}
|
|
1844
|
+
const doc = state.doc;
|
|
1845
|
+
const roomName = `${this.options.roomPrefix}/${id}`;
|
|
1846
|
+
const provider = new WebsocketProvider2(
|
|
1847
|
+
this.options.websocketUrl,
|
|
1848
|
+
roomName,
|
|
1849
|
+
doc
|
|
1850
|
+
);
|
|
1851
|
+
provider.awareness.setLocalStateField("user", this.options.user);
|
|
1852
|
+
state.provider = provider;
|
|
1853
|
+
state.active = true;
|
|
1854
|
+
this.activeQueue.push(id);
|
|
1855
|
+
this.options.onStateChange(this.getAllStates());
|
|
1856
|
+
}
|
|
1857
|
+
/** Deactivate a subdocument — disconnects it from the network. */
|
|
1858
|
+
deactivate(id) {
|
|
1859
|
+
const state = this.states.get(id);
|
|
1860
|
+
if (!state || !state.active) return;
|
|
1861
|
+
state.provider?.destroy();
|
|
1862
|
+
state.provider = null;
|
|
1863
|
+
state.active = false;
|
|
1864
|
+
const idx = this.activeQueue.indexOf(id);
|
|
1865
|
+
if (idx >= 0) this.activeQueue.splice(idx, 1);
|
|
1866
|
+
this.options.onStateChange(this.getAllStates());
|
|
1867
|
+
}
|
|
1868
|
+
/** Get the Y.XmlFragment for a subdocument. */
|
|
1869
|
+
getFragment(id) {
|
|
1870
|
+
const doc = this.states.get(id)?.doc ?? this.subdocs.get(id);
|
|
1871
|
+
if (!doc) return null;
|
|
1872
|
+
return doc.getXmlFragment("default");
|
|
1873
|
+
}
|
|
1874
|
+
/** Check if a subdocument is currently active (syncing). */
|
|
1875
|
+
isActive(id) {
|
|
1876
|
+
return this.states.get(id)?.active ?? false;
|
|
1877
|
+
}
|
|
1878
|
+
/** Get all subdocument states. */
|
|
1879
|
+
getAllStates() {
|
|
1880
|
+
return Array.from(this.states.values());
|
|
1881
|
+
}
|
|
1882
|
+
/** Get IDs of all active subdocuments. */
|
|
1883
|
+
getActiveIds() {
|
|
1884
|
+
return [...this.activeQueue];
|
|
1885
|
+
}
|
|
1886
|
+
/** Destroy all subdocuments and providers. */
|
|
1887
|
+
destroy() {
|
|
1888
|
+
for (const [id] of this.states) {
|
|
1889
|
+
this.deactivate(id);
|
|
1890
|
+
}
|
|
1891
|
+
this.parentProvider?.destroy();
|
|
1892
|
+
this.parentDoc.destroy();
|
|
1893
|
+
this.states.clear();
|
|
1894
|
+
this.activeQueue.length = 0;
|
|
1895
|
+
}
|
|
1896
|
+
};
|
|
432
1897
|
export {
|
|
433
1898
|
BlockAttributesExtension,
|
|
1899
|
+
EditorContextExtension,
|
|
434
1900
|
FontSizeExtension,
|
|
435
1901
|
PAGE_SIZES,
|
|
436
|
-
|
|
1902
|
+
PaginationPlus,
|
|
1903
|
+
SearchAndReplaceExtension,
|
|
1904
|
+
SubdocumentProvider,
|
|
1905
|
+
clearSearch,
|
|
437
1906
|
collaborationExtensions,
|
|
438
1907
|
collectExtensions,
|
|
439
1908
|
createActionMap,
|
|
440
1909
|
createCollaboration,
|
|
441
1910
|
createEditor,
|
|
442
1911
|
definePlugin,
|
|
443
|
-
|
|
1912
|
+
findMatches,
|
|
1913
|
+
getSearchState,
|
|
1914
|
+
replaceAll,
|
|
1915
|
+
replaceCurrent,
|
|
1916
|
+
resolveAction,
|
|
1917
|
+
sanitizePastedHTML,
|
|
1918
|
+
searchAndReplaceKey,
|
|
1919
|
+
searchNext,
|
|
1920
|
+
searchPrev,
|
|
1921
|
+
setSearchQuery
|
|
444
1922
|
};
|