@harbour-enterprises/superdoc 1.5.0-next.7 → 1.5.0-next.9
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 +2 -2
- package/dist/chunks/{PdfViewer-Cli6IR-X.cjs → PdfViewer-CJrP6IEy.cjs} +2 -2
- package/dist/chunks/{PdfViewer-ClST5VR6.es.js → PdfViewer-CYai_OkL.es.js} +2 -2
- package/dist/chunks/{SuperConverter-CIjArITT.cjs → SuperConverter-Ck9J4dUw.cjs} +589 -450
- package/dist/chunks/{SuperConverter-S5AfMnkn.es.js → SuperConverter-meS8FJqm.es.js} +589 -450
- package/dist/chunks/{index-LpMObyDy.cjs → index-3B3UnhZ-.cjs} +402 -29
- package/dist/chunks/{index-7ebfCUN0.es.js → index-CfwhHibT.es.js} +402 -29
- package/dist/chunks/{index-bw_yQ0EP.es.js → index-CmNzR_QC.es.js} +4 -4
- package/dist/chunks/{index-CbbEjpJ0.cjs → index-DFGKRDVF.cjs} +4 -4
- package/dist/style.css +7 -0
- package/dist/super-editor/converter.cjs +1 -1
- package/dist/super-editor/converter.es.js +1 -1
- package/dist/super-editor.cjs +2 -2
- package/dist/super-editor.es.js +3 -3
- package/dist/superdoc.cjs +3 -3
- package/dist/superdoc.es.js +3 -3
- package/dist/superdoc.umd.js +991 -479
- package/dist/superdoc.umd.js.map +1 -1
- package/package.json +5 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const jszip = require("./jszip-C8_CqJxM.cjs");
|
|
3
3
|
const helpers$1 = require("./helpers-nOdwpmwb.cjs");
|
|
4
|
-
const superEditor_converter = require("./SuperConverter-
|
|
4
|
+
const superEditor_converter = require("./SuperConverter-Ck9J4dUw.cjs");
|
|
5
5
|
const vue = require("./vue-De9wkgLl.cjs");
|
|
6
6
|
require("./jszip.min-BPh2MMAa.cjs");
|
|
7
7
|
const eventemitter3 = require("./eventemitter3-BQuRcMPI.cjs");
|
|
@@ -15524,7 +15524,7 @@ const canUseDOM = () => {
|
|
|
15524
15524
|
return false;
|
|
15525
15525
|
}
|
|
15526
15526
|
};
|
|
15527
|
-
const summaryVersion = "1.5.0-next.
|
|
15527
|
+
const summaryVersion = "1.5.0-next.9";
|
|
15528
15528
|
const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
|
|
15529
15529
|
const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
|
|
15530
15530
|
function mapAttributes(attrs) {
|
|
@@ -18181,7 +18181,7 @@ class Editor extends EventEmitter {
|
|
|
18181
18181
|
* Process collaboration migrations
|
|
18182
18182
|
*/
|
|
18183
18183
|
processCollaborationMigrations() {
|
|
18184
|
-
console.debug("[checkVersionMigrations] Current editor version", "1.5.0-next.
|
|
18184
|
+
console.debug("[checkVersionMigrations] Current editor version", "1.5.0-next.9");
|
|
18185
18185
|
if (!this.options.ydoc) return;
|
|
18186
18186
|
const metaMap = this.options.ydoc.getMap("meta");
|
|
18187
18187
|
let docVersion = metaMap.get("version");
|
|
@@ -23469,7 +23469,8 @@ const lineStyles = (lineHeight2) => ({
|
|
|
23469
23469
|
// The primary fix uses accurate font metrics from Canvas API, but this
|
|
23470
23470
|
// provides defense-in-depth against any remaining sub-pixel rendering
|
|
23471
23471
|
// differences between measurement and display.
|
|
23472
|
-
overflow: "visible"
|
|
23472
|
+
overflow: "visible",
|
|
23473
|
+
zIndex: "10"
|
|
23473
23474
|
});
|
|
23474
23475
|
const PRINT_STYLES = `
|
|
23475
23476
|
@media print {
|
|
@@ -23775,6 +23776,7 @@ const SDT_CONTAINER_STYLES = `
|
|
|
23775
23776
|
border: 1px solid #629be7;
|
|
23776
23777
|
position: relative;
|
|
23777
23778
|
display: inline;
|
|
23779
|
+
z-index: 10;
|
|
23778
23780
|
}
|
|
23779
23781
|
|
|
23780
23782
|
/* Hover effect for inline structured content */
|
|
@@ -28962,11 +28964,6 @@ class DomPainter {
|
|
|
28962
28964
|
} else {
|
|
28963
28965
|
delete el.dataset.pmEnd;
|
|
28964
28966
|
}
|
|
28965
|
-
if (fragment.pmStart != null && fragment.pmEnd != null) {
|
|
28966
|
-
el.title = `PM ${fragment.pmStart}–${fragment.pmEnd}`;
|
|
28967
|
-
} else {
|
|
28968
|
-
el.removeAttribute("title");
|
|
28969
|
-
}
|
|
28970
28967
|
if (fragment.continuesFromPrev) {
|
|
28971
28968
|
el.dataset.continuesFromPrev = "true";
|
|
28972
28969
|
} else {
|
|
@@ -49108,8 +49105,6 @@ class EditorOverlayManager {
|
|
|
49108
49105
|
#activeRegion = null;
|
|
49109
49106
|
/** Full-width border line element (MS Word style) */
|
|
49110
49107
|
#borderLine = null;
|
|
49111
|
-
/** Dimming overlay element (for dimming body content during editing) */
|
|
49112
|
-
#dimmingOverlay = null;
|
|
49113
49108
|
/**
|
|
49114
49109
|
* Creates a new EditorOverlayManager instance.
|
|
49115
49110
|
*
|
|
@@ -49403,17 +49398,6 @@ class EditorOverlayManager {
|
|
|
49403
49398
|
}
|
|
49404
49399
|
}
|
|
49405
49400
|
}
|
|
49406
|
-
/**
|
|
49407
|
-
* Hides and removes the dimming overlay.
|
|
49408
|
-
* @internal Reserved for future implementation of body dimming during header/footer editing.
|
|
49409
|
-
*/
|
|
49410
|
-
// eslint-disable-next-line no-unused-private-class-members
|
|
49411
|
-
#hideDimmingOverlay() {
|
|
49412
|
-
if (this.#dimmingOverlay) {
|
|
49413
|
-
this.#dimmingOverlay.remove();
|
|
49414
|
-
this.#dimmingOverlay = null;
|
|
49415
|
-
}
|
|
49416
|
-
}
|
|
49417
49401
|
/**
|
|
49418
49402
|
* Shows a full-width border line at the bottom of the header or top of the footer.
|
|
49419
49403
|
* This creates the MS Word style visual indicator spanning edge-to-edge of the page.
|
|
@@ -51586,6 +51570,7 @@ class PresentationEditor extends EventEmitter {
|
|
|
51586
51570
|
#viewportHost;
|
|
51587
51571
|
#painterHost;
|
|
51588
51572
|
#selectionOverlay;
|
|
51573
|
+
#permissionOverlay = null;
|
|
51589
51574
|
#hiddenHost;
|
|
51590
51575
|
#layoutOptions;
|
|
51591
51576
|
#layoutState = { blocks: [], measures: [], layout: null, bookmarks: /* @__PURE__ */ new Map() };
|
|
@@ -51745,6 +51730,16 @@ class PresentationEditor extends EventEmitter {
|
|
|
51745
51730
|
});
|
|
51746
51731
|
this.#domIndexObserverManager.setup();
|
|
51747
51732
|
this.#selectionSync.on("render", () => this.#updateSelection());
|
|
51733
|
+
this.#selectionSync.on("render", () => this.#updatePermissionOverlay());
|
|
51734
|
+
this.#permissionOverlay = doc2.createElement("div");
|
|
51735
|
+
this.#permissionOverlay.className = "presentation-editor__permission-overlay";
|
|
51736
|
+
Object.assign(this.#permissionOverlay.style, {
|
|
51737
|
+
position: "absolute",
|
|
51738
|
+
inset: "0",
|
|
51739
|
+
pointerEvents: "none",
|
|
51740
|
+
zIndex: "5"
|
|
51741
|
+
});
|
|
51742
|
+
this.#viewportHost.appendChild(this.#permissionOverlay);
|
|
51748
51743
|
this.#selectionOverlay = doc2.createElement("div");
|
|
51749
51744
|
this.#selectionOverlay.className = "presentation-editor__selection-overlay";
|
|
51750
51745
|
this.#selectionOverlay.id = `presentation-overlay-${options.documentId || "default"}`;
|
|
@@ -51830,7 +51825,7 @@ class PresentationEditor extends EventEmitter {
|
|
|
51830
51825
|
const normalizedEditorProps = {
|
|
51831
51826
|
...editorOptions.editorProps ?? {},
|
|
51832
51827
|
editable: () => {
|
|
51833
|
-
return this.#
|
|
51828
|
+
return !this.#isViewLocked();
|
|
51834
51829
|
}
|
|
51835
51830
|
};
|
|
51836
51831
|
try {
|
|
@@ -52272,6 +52267,7 @@ class PresentationEditor extends EventEmitter {
|
|
|
52272
52267
|
this.#pendingDocChange = true;
|
|
52273
52268
|
this.#scheduleRerender();
|
|
52274
52269
|
}
|
|
52270
|
+
this.#updatePermissionOverlay();
|
|
52275
52271
|
}
|
|
52276
52272
|
#syncDocumentModeClass() {
|
|
52277
52273
|
if (!this.#visibleHost) return;
|
|
@@ -53661,7 +53657,7 @@ class PresentationEditor extends EventEmitter {
|
|
|
53661
53657
|
win,
|
|
53662
53658
|
this.#visibleHost,
|
|
53663
53659
|
() => this.#getActiveDomTarget(),
|
|
53664
|
-
() => this.#
|
|
53660
|
+
() => !this.#isViewLocked()
|
|
53665
53661
|
);
|
|
53666
53662
|
this.#inputBridge.bind();
|
|
53667
53663
|
}
|
|
@@ -54586,7 +54582,7 @@ class PresentationEditor extends EventEmitter {
|
|
|
54586
54582
|
this.#dragUsedPageNotMountedFallback = false;
|
|
54587
54583
|
return;
|
|
54588
54584
|
}
|
|
54589
|
-
if (this.#session.mode !== "body" || this.#
|
|
54585
|
+
if (this.#session.mode !== "body" || this.#isViewLocked()) {
|
|
54590
54586
|
this.#dragLastPointer = null;
|
|
54591
54587
|
this.#dragLastRawHit = null;
|
|
54592
54588
|
this.#dragUsedPageNotMountedFallback = false;
|
|
@@ -54936,6 +54932,7 @@ class PresentationEditor extends EventEmitter {
|
|
|
54936
54932
|
this.#epochMapper.onLayoutComplete(layoutEpoch);
|
|
54937
54933
|
this.#selectionSync.onLayoutComplete(layoutEpoch);
|
|
54938
54934
|
layoutCompleted = true;
|
|
54935
|
+
this.#updatePermissionOverlay();
|
|
54939
54936
|
this.#layoutError = null;
|
|
54940
54937
|
this.#layoutErrorState = "healthy";
|
|
54941
54938
|
this.#dismissErrorBanner();
|
|
@@ -55024,7 +55021,7 @@ class PresentationEditor extends EventEmitter {
|
|
|
55024
55021
|
if (!this.#localSelectionLayer) {
|
|
55025
55022
|
return;
|
|
55026
55023
|
}
|
|
55027
|
-
if (this.#
|
|
55024
|
+
if (this.#isViewLocked()) {
|
|
55028
55025
|
try {
|
|
55029
55026
|
this.#localSelectionLayer.innerHTML = "";
|
|
55030
55027
|
} catch (error) {
|
|
@@ -55106,6 +55103,76 @@ class PresentationEditor extends EventEmitter {
|
|
|
55106
55103
|
}
|
|
55107
55104
|
}
|
|
55108
55105
|
}
|
|
55106
|
+
/**
|
|
55107
|
+
* Updates the permission overlay (w:permStart/w:permEnd) to match the current editor permission ranges.
|
|
55108
|
+
*
|
|
55109
|
+
* This method is called after layout completes to ensure permission overlay
|
|
55110
|
+
* is based on stable permission ranges data.
|
|
55111
|
+
*/
|
|
55112
|
+
#updatePermissionOverlay() {
|
|
55113
|
+
const overlay2 = this.#permissionOverlay;
|
|
55114
|
+
if (!overlay2) {
|
|
55115
|
+
return;
|
|
55116
|
+
}
|
|
55117
|
+
if (this.#session.mode !== "body") {
|
|
55118
|
+
overlay2.innerHTML = "";
|
|
55119
|
+
return;
|
|
55120
|
+
}
|
|
55121
|
+
const permissionStorage = this.#editor?.storage?.permissionRanges;
|
|
55122
|
+
const ranges = permissionStorage?.ranges ?? [];
|
|
55123
|
+
const shouldRender = ranges.length > 0;
|
|
55124
|
+
if (!shouldRender) {
|
|
55125
|
+
overlay2.innerHTML = "";
|
|
55126
|
+
return;
|
|
55127
|
+
}
|
|
55128
|
+
const layout = this.#layoutState.layout;
|
|
55129
|
+
if (!layout) {
|
|
55130
|
+
overlay2.innerHTML = "";
|
|
55131
|
+
return;
|
|
55132
|
+
}
|
|
55133
|
+
const docEpoch = this.#epochMapper.getCurrentEpoch();
|
|
55134
|
+
if (this.#layoutEpoch < docEpoch) {
|
|
55135
|
+
return;
|
|
55136
|
+
}
|
|
55137
|
+
const pageHeight = this.#getBodyPageHeight();
|
|
55138
|
+
const pageGap = layout.pageGap ?? this.#getEffectivePageGap();
|
|
55139
|
+
const fragment = overlay2.ownerDocument?.createDocumentFragment();
|
|
55140
|
+
if (!fragment) {
|
|
55141
|
+
overlay2.innerHTML = "";
|
|
55142
|
+
return;
|
|
55143
|
+
}
|
|
55144
|
+
ranges.forEach(({ from: from3, to }) => {
|
|
55145
|
+
const rects = this.#computeSelectionRectsFromDom(from3, to);
|
|
55146
|
+
if (!rects?.length) {
|
|
55147
|
+
return;
|
|
55148
|
+
}
|
|
55149
|
+
rects.forEach((rect) => {
|
|
55150
|
+
const pageLocalY = rect.y - rect.pageIndex * (pageHeight + pageGap);
|
|
55151
|
+
const coords = this.#convertPageLocalToOverlayCoords(rect.pageIndex, rect.x, pageLocalY);
|
|
55152
|
+
if (!coords) {
|
|
55153
|
+
return;
|
|
55154
|
+
}
|
|
55155
|
+
const highlight = overlay2.ownerDocument?.createElement("div");
|
|
55156
|
+
if (!highlight) {
|
|
55157
|
+
return;
|
|
55158
|
+
}
|
|
55159
|
+
highlight.className = "presentation-editor__permission-highlight";
|
|
55160
|
+
Object.assign(highlight.style, {
|
|
55161
|
+
position: "absolute",
|
|
55162
|
+
left: `${coords.x}px`,
|
|
55163
|
+
top: `${coords.y}px`,
|
|
55164
|
+
width: `${Math.max(1, rect.width)}px`,
|
|
55165
|
+
height: `${Math.max(1, rect.height)}px`,
|
|
55166
|
+
borderRadius: "2px",
|
|
55167
|
+
pointerEvents: "none",
|
|
55168
|
+
zIndex: 1
|
|
55169
|
+
});
|
|
55170
|
+
fragment.appendChild(highlight);
|
|
55171
|
+
});
|
|
55172
|
+
});
|
|
55173
|
+
overlay2.innerHTML = "";
|
|
55174
|
+
overlay2.appendChild(fragment);
|
|
55175
|
+
}
|
|
55109
55176
|
#resolveLayoutOptions(blocks, sectionMetadata) {
|
|
55110
55177
|
const defaults = this.#computeDefaultLayoutDefaults();
|
|
55111
55178
|
const firstSection = blocks?.find(
|
|
@@ -55851,7 +55918,7 @@ class PresentationEditor extends EventEmitter {
|
|
|
55851
55918
|
this.#announce(announcement.message);
|
|
55852
55919
|
}
|
|
55853
55920
|
#validateHeaderFooterEditPermission() {
|
|
55854
|
-
if (this.#
|
|
55921
|
+
if (this.#isViewLocked()) {
|
|
55855
55922
|
return { allowed: false, reason: "documentMode" };
|
|
55856
55923
|
}
|
|
55857
55924
|
if (!this.#editor.isEditable) {
|
|
@@ -56714,6 +56781,17 @@ class PresentationEditor extends EventEmitter {
|
|
|
56714
56781
|
this.#errorBanner = null;
|
|
56715
56782
|
this.#errorBannerMessage = null;
|
|
56716
56783
|
}
|
|
56784
|
+
/**
|
|
56785
|
+
* Determines whether the current viewing mode should block edits.
|
|
56786
|
+
* When documentMode is viewing but the active editor has been toggled
|
|
56787
|
+
* back to editable (e.g. permission ranges), we treat the view as editable.
|
|
56788
|
+
*/
|
|
56789
|
+
#isViewLocked() {
|
|
56790
|
+
if (this.#documentMode !== "viewing") return false;
|
|
56791
|
+
const hasPermissionOverride = !!this.#editor?.storage?.permissionRanges?.hasAllowedRanges;
|
|
56792
|
+
if (hasPermissionOverride) return false;
|
|
56793
|
+
return this.#documentMode === "viewing";
|
|
56794
|
+
}
|
|
56717
56795
|
/**
|
|
56718
56796
|
* Applies vertical alignment and font scaling to layout DOM elements for subscript/superscript rendering.
|
|
56719
56797
|
*
|
|
@@ -58593,6 +58671,11 @@ const structuredContentHelpers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ O
|
|
|
58593
58671
|
parseTagObject
|
|
58594
58672
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
58595
58673
|
const STRUCTURED_CONTENT_NAMES = ["structuredContent", "structuredContentBlock"];
|
|
58674
|
+
function isValidIntegerId(id) {
|
|
58675
|
+
if (id === null || id === void 0) return true;
|
|
58676
|
+
const str = String(id);
|
|
58677
|
+
return /^-?\d+$/.test(str);
|
|
58678
|
+
}
|
|
58596
58679
|
const findFirstTextNode = (node) => {
|
|
58597
58680
|
let firstTextNode = null;
|
|
58598
58681
|
node.descendants((child) => {
|
|
@@ -58634,6 +58717,9 @@ const StructuredContentCommands = Extension.create({
|
|
|
58634
58717
|
* });
|
|
58635
58718
|
*/
|
|
58636
58719
|
insertStructuredContentInline: (options = {}) => ({ editor, dispatch, state, tr }) => {
|
|
58720
|
+
if (options.attrs?.id !== void 0 && !isValidIntegerId(options.attrs.id)) {
|
|
58721
|
+
throw new Error("Invalid structured content id - must be an integer, got: " + options.attrs.id);
|
|
58722
|
+
}
|
|
58637
58723
|
const { schema } = editor;
|
|
58638
58724
|
let { from: from3, to } = state.selection;
|
|
58639
58725
|
if (dispatch) {
|
|
@@ -58696,6 +58782,9 @@ const StructuredContentCommands = Extension.create({
|
|
|
58696
58782
|
* });
|
|
58697
58783
|
*/
|
|
58698
58784
|
insertStructuredContentBlock: (options = {}) => ({ editor, dispatch, state, tr }) => {
|
|
58785
|
+
if (options.attrs?.id !== void 0 && !isValidIntegerId(options.attrs.id)) {
|
|
58786
|
+
throw new Error("Invalid structured content id - must be an integer, got: " + options.attrs.id);
|
|
58787
|
+
}
|
|
58699
58788
|
const { schema } = editor;
|
|
58700
58789
|
let { from: from3, to } = state.selection;
|
|
58701
58790
|
if (dispatch) {
|
|
@@ -58753,6 +58842,9 @@ const StructuredContentCommands = Extension.create({
|
|
|
58753
58842
|
* });
|
|
58754
58843
|
*/
|
|
58755
58844
|
updateStructuredContentById: (id, options = {}) => ({ editor, dispatch, state, tr }) => {
|
|
58845
|
+
if (options.attrs?.id !== void 0 && !isValidIntegerId(options.attrs.id)) {
|
|
58846
|
+
throw new Error("Invalid structured content id - must be an integer, got: " + options.attrs.id);
|
|
58847
|
+
}
|
|
58756
58848
|
const structuredContentTags = getStructuredContentTagsById(id, state);
|
|
58757
58849
|
if (!structuredContentTags.length) {
|
|
58758
58850
|
return true;
|
|
@@ -58880,6 +58972,9 @@ const StructuredContentCommands = Extension.create({
|
|
|
58880
58972
|
* });
|
|
58881
58973
|
*/
|
|
58882
58974
|
updateStructuredContentByGroup: (group, options = {}) => ({ editor, dispatch, state, tr }) => {
|
|
58975
|
+
if (options.attrs?.id !== void 0 && !isValidIntegerId(options.attrs.id)) {
|
|
58976
|
+
throw new Error("Invalid structured content id - must be an integer, got: " + options.attrs.id);
|
|
58977
|
+
}
|
|
58883
58978
|
const structuredContentTags = getStructuredContentByGroup(group, state);
|
|
58884
58979
|
if (!structuredContentTags.length) {
|
|
58885
58980
|
return true;
|
|
@@ -59557,7 +59652,7 @@ const mergeRanges$2 = (ranges, docSize) => {
|
|
|
59557
59652
|
}
|
|
59558
59653
|
return merged;
|
|
59559
59654
|
};
|
|
59560
|
-
const collectChangedRanges = (trs, docSize) => {
|
|
59655
|
+
const collectChangedRanges$1 = (trs, docSize) => {
|
|
59561
59656
|
const ranges = [];
|
|
59562
59657
|
trs.forEach((tr) => {
|
|
59563
59658
|
if (!tr.docChanged) return;
|
|
@@ -59760,7 +59855,7 @@ const wrapTextInRunsPlugin = (editor) => {
|
|
|
59760
59855
|
const runType = newState.schema.nodes.run;
|
|
59761
59856
|
if (!runType) return null;
|
|
59762
59857
|
pendingRanges = mapRangesThroughTransactions(pendingRanges, transactions, docSize);
|
|
59763
|
-
const changedRanges = collectChangedRanges(transactions, docSize);
|
|
59858
|
+
const changedRanges = collectChangedRanges$1(transactions, docSize);
|
|
59764
59859
|
pendingRanges = mergeRanges$2([...pendingRanges, ...changedRanges], docSize);
|
|
59765
59860
|
if (view?.composing) {
|
|
59766
59861
|
return null;
|
|
@@ -74635,6 +74730,283 @@ const NodeResizer = Extension.create({
|
|
|
74635
74730
|
return [nodeResizer(["image"], this.editor)];
|
|
74636
74731
|
}
|
|
74637
74732
|
});
|
|
74733
|
+
const PERMISSION_PLUGIN_KEY = new superEditor_converter.PluginKey("permissionRanges");
|
|
74734
|
+
const EVERYONE_GROUP = "everyone";
|
|
74735
|
+
const EMPTY_IDENTIFIER_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
74736
|
+
const normalizeIdentifier = (value) => typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
74737
|
+
const buildAllowedIdentifierSet = (editor) => {
|
|
74738
|
+
const email = normalizeIdentifier(editor?.options?.user?.email);
|
|
74739
|
+
if (!email) {
|
|
74740
|
+
return EMPTY_IDENTIFIER_SET;
|
|
74741
|
+
}
|
|
74742
|
+
const [localPart, domain] = email.split("@");
|
|
74743
|
+
if (!localPart || !domain) {
|
|
74744
|
+
return EMPTY_IDENTIFIER_SET;
|
|
74745
|
+
}
|
|
74746
|
+
const formatted = `${domain}\\${localPart}`;
|
|
74747
|
+
return formatted ? /* @__PURE__ */ new Set([formatted]) : EMPTY_IDENTIFIER_SET;
|
|
74748
|
+
};
|
|
74749
|
+
const isEveryoneGroup = (value) => normalizeIdentifier(value) === EVERYONE_GROUP;
|
|
74750
|
+
const isRangeAllowedForUser = (attrs, allowedIdentifiers) => {
|
|
74751
|
+
if (!attrs) return false;
|
|
74752
|
+
if (isEveryoneGroup(attrs.edGrp)) {
|
|
74753
|
+
return true;
|
|
74754
|
+
}
|
|
74755
|
+
if (!allowedIdentifiers?.size) {
|
|
74756
|
+
return false;
|
|
74757
|
+
}
|
|
74758
|
+
const normalizedEd = normalizeIdentifier(attrs.ed);
|
|
74759
|
+
return normalizedEd && allowedIdentifiers.has(normalizedEd);
|
|
74760
|
+
};
|
|
74761
|
+
const getPermissionNodeId = (node, pos, fallbackPrefix) => String(node.attrs?.id ?? `${fallbackPrefix}-${pos}`);
|
|
74762
|
+
const buildPermissionState = (doc2, allowedIdentifiers = EMPTY_IDENTIFIER_SET) => {
|
|
74763
|
+
const ranges = [];
|
|
74764
|
+
const openRanges = /* @__PURE__ */ new Map();
|
|
74765
|
+
doc2.descendants((node, pos) => {
|
|
74766
|
+
if (node.type?.name === "permStart") {
|
|
74767
|
+
const id = getPermissionNodeId(node, pos, "permStart");
|
|
74768
|
+
openRanges.set(id, {
|
|
74769
|
+
from: pos + node.nodeSize,
|
|
74770
|
+
attrs: node.attrs ?? {}
|
|
74771
|
+
});
|
|
74772
|
+
return false;
|
|
74773
|
+
}
|
|
74774
|
+
if (node.type?.name === "permEnd") {
|
|
74775
|
+
const id = getPermissionNodeId(node, pos, "permEnd");
|
|
74776
|
+
const start2 = openRanges.get(id);
|
|
74777
|
+
if (start2 && isRangeAllowedForUser(start2.attrs, allowedIdentifiers)) {
|
|
74778
|
+
const to = Math.max(pos, start2.from);
|
|
74779
|
+
if (to > start2.from) {
|
|
74780
|
+
ranges.push({
|
|
74781
|
+
id,
|
|
74782
|
+
from: start2.from,
|
|
74783
|
+
to
|
|
74784
|
+
});
|
|
74785
|
+
}
|
|
74786
|
+
}
|
|
74787
|
+
if (start2) {
|
|
74788
|
+
openRanges.delete(id);
|
|
74789
|
+
}
|
|
74790
|
+
return false;
|
|
74791
|
+
}
|
|
74792
|
+
});
|
|
74793
|
+
return {
|
|
74794
|
+
ranges,
|
|
74795
|
+
hasAllowedRanges: ranges.length > 0
|
|
74796
|
+
};
|
|
74797
|
+
};
|
|
74798
|
+
const collectPermissionTags = (doc2, permStartType, permEndType) => {
|
|
74799
|
+
const tags = /* @__PURE__ */ new Map();
|
|
74800
|
+
doc2.descendants((node, pos) => {
|
|
74801
|
+
if (node.type !== permStartType && node.type !== permEndType) {
|
|
74802
|
+
return;
|
|
74803
|
+
}
|
|
74804
|
+
const id = node.attrs?.id;
|
|
74805
|
+
if (!id) {
|
|
74806
|
+
return;
|
|
74807
|
+
}
|
|
74808
|
+
const entry = tags.get(id) ?? {};
|
|
74809
|
+
if (node.type === permStartType) {
|
|
74810
|
+
entry.start = { pos, attrs: node.attrs ?? {} };
|
|
74811
|
+
} else if (node.type === permEndType) {
|
|
74812
|
+
entry.end = { pos, attrs: node.attrs ?? {} };
|
|
74813
|
+
}
|
|
74814
|
+
tags.set(id, entry);
|
|
74815
|
+
});
|
|
74816
|
+
return tags;
|
|
74817
|
+
};
|
|
74818
|
+
const clampPosition = (pos, size2) => {
|
|
74819
|
+
if (Number.isNaN(pos) || !Number.isFinite(pos)) {
|
|
74820
|
+
return 0;
|
|
74821
|
+
}
|
|
74822
|
+
return Math.max(0, Math.min(pos, size2));
|
|
74823
|
+
};
|
|
74824
|
+
const trimPermissionTagsFromRange = (doc2, range, permStartType, permEndType) => {
|
|
74825
|
+
let from3 = range.from;
|
|
74826
|
+
let to = range.to;
|
|
74827
|
+
while (from3 < to) {
|
|
74828
|
+
const node = doc2.nodeAt(from3);
|
|
74829
|
+
if (!node || node.type !== permStartType && node.type !== permEndType) {
|
|
74830
|
+
break;
|
|
74831
|
+
}
|
|
74832
|
+
from3 += node.nodeSize;
|
|
74833
|
+
}
|
|
74834
|
+
while (to > from3) {
|
|
74835
|
+
const $pos = doc2.resolve(to);
|
|
74836
|
+
const nodeBefore = $pos.nodeBefore;
|
|
74837
|
+
if (!nodeBefore || nodeBefore.type !== permStartType && nodeBefore.type !== permEndType) {
|
|
74838
|
+
break;
|
|
74839
|
+
}
|
|
74840
|
+
to -= nodeBefore.nodeSize;
|
|
74841
|
+
}
|
|
74842
|
+
return { from: from3, to };
|
|
74843
|
+
};
|
|
74844
|
+
const collectChangedRanges = (tr) => {
|
|
74845
|
+
const ranges = [];
|
|
74846
|
+
tr.mapping.maps.forEach((map3) => {
|
|
74847
|
+
map3.forEach((oldStart, oldEnd) => {
|
|
74848
|
+
const from3 = Math.min(oldStart, oldEnd);
|
|
74849
|
+
const to = Math.max(oldStart, oldEnd);
|
|
74850
|
+
ranges.push({ from: from3, to });
|
|
74851
|
+
});
|
|
74852
|
+
});
|
|
74853
|
+
return ranges;
|
|
74854
|
+
};
|
|
74855
|
+
const isRangeAllowed = (range, allowedRanges) => {
|
|
74856
|
+
if (!allowedRanges?.length) return false;
|
|
74857
|
+
return allowedRanges.some((allowed) => range.from >= allowed.from && range.to <= allowed.to);
|
|
74858
|
+
};
|
|
74859
|
+
const PermissionRanges = Extension.create({
|
|
74860
|
+
name: "permissionRanges",
|
|
74861
|
+
addStorage() {
|
|
74862
|
+
return {
|
|
74863
|
+
ranges: [],
|
|
74864
|
+
hasAllowedRanges: false
|
|
74865
|
+
};
|
|
74866
|
+
},
|
|
74867
|
+
addPmPlugins() {
|
|
74868
|
+
const editor = this.editor;
|
|
74869
|
+
const storage = this.storage;
|
|
74870
|
+
let originalSetDocumentMode = null;
|
|
74871
|
+
const getAllowedIdentifiers = () => buildAllowedIdentifierSet(editor);
|
|
74872
|
+
const toggleEditableIfAllowed = (hasAllowedRanges) => {
|
|
74873
|
+
if (!editor || editor.isDestroyed) return;
|
|
74874
|
+
if (editor.options.documentMode !== "viewing") return;
|
|
74875
|
+
if (hasAllowedRanges && !editor.isEditable) {
|
|
74876
|
+
editor.setEditable(true, false);
|
|
74877
|
+
} else if (!hasAllowedRanges && editor.isEditable) {
|
|
74878
|
+
editor.setEditable(false, false);
|
|
74879
|
+
}
|
|
74880
|
+
};
|
|
74881
|
+
const updateEditableState = (hasAllowedRanges) => {
|
|
74882
|
+
const nextValue = Boolean(hasAllowedRanges);
|
|
74883
|
+
const previousValue = storage.hasAllowedRanges;
|
|
74884
|
+
storage.hasAllowedRanges = nextValue;
|
|
74885
|
+
if (previousValue === nextValue) {
|
|
74886
|
+
return;
|
|
74887
|
+
}
|
|
74888
|
+
toggleEditableIfAllowed(nextValue);
|
|
74889
|
+
};
|
|
74890
|
+
if (editor && typeof editor.setDocumentMode === "function") {
|
|
74891
|
+
originalSetDocumentMode = editor.setDocumentMode.bind(editor);
|
|
74892
|
+
editor.setDocumentMode = (mode, caller) => {
|
|
74893
|
+
originalSetDocumentMode(mode, caller);
|
|
74894
|
+
const state = editor.state;
|
|
74895
|
+
if (!state) return;
|
|
74896
|
+
const pluginState = PERMISSION_PLUGIN_KEY.getState(state);
|
|
74897
|
+
if (pluginState) {
|
|
74898
|
+
toggleEditableIfAllowed(pluginState.hasAllowedRanges);
|
|
74899
|
+
}
|
|
74900
|
+
};
|
|
74901
|
+
}
|
|
74902
|
+
return [
|
|
74903
|
+
new superEditor_converter.Plugin({
|
|
74904
|
+
key: PERMISSION_PLUGIN_KEY,
|
|
74905
|
+
state: {
|
|
74906
|
+
init(_2, state) {
|
|
74907
|
+
const permissionState = buildPermissionState(state.doc, getAllowedIdentifiers());
|
|
74908
|
+
storage.ranges = permissionState.ranges;
|
|
74909
|
+
updateEditableState(permissionState.hasAllowedRanges);
|
|
74910
|
+
return permissionState;
|
|
74911
|
+
},
|
|
74912
|
+
apply(tr, value, _oldState, newState) {
|
|
74913
|
+
let permissionState = value;
|
|
74914
|
+
if (tr.docChanged) {
|
|
74915
|
+
permissionState = buildPermissionState(newState.doc, getAllowedIdentifiers());
|
|
74916
|
+
storage.ranges = permissionState.ranges;
|
|
74917
|
+
updateEditableState(permissionState.hasAllowedRanges);
|
|
74918
|
+
}
|
|
74919
|
+
return permissionState;
|
|
74920
|
+
}
|
|
74921
|
+
},
|
|
74922
|
+
view() {
|
|
74923
|
+
return {
|
|
74924
|
+
destroy() {
|
|
74925
|
+
if (editor && originalSetDocumentMode) {
|
|
74926
|
+
editor.setDocumentMode = originalSetDocumentMode;
|
|
74927
|
+
}
|
|
74928
|
+
}
|
|
74929
|
+
};
|
|
74930
|
+
},
|
|
74931
|
+
// Appends transactions to the document to ensure permission ranges are updated.
|
|
74932
|
+
appendTransaction(transactions, oldState, newState) {
|
|
74933
|
+
if (!transactions.some((tr2) => tr2.docChanged)) return null;
|
|
74934
|
+
const permStartType = newState.schema.nodes["permStart"];
|
|
74935
|
+
const permEndType = newState.schema.nodes["permEnd"];
|
|
74936
|
+
if (!permStartType || !permEndType) return null;
|
|
74937
|
+
const oldTags = collectPermissionTags(oldState.doc, permStartType, permEndType);
|
|
74938
|
+
if (!oldTags.size) {
|
|
74939
|
+
return null;
|
|
74940
|
+
}
|
|
74941
|
+
const newTags = collectPermissionTags(newState.doc, permStartType, permEndType);
|
|
74942
|
+
const mappingToNew = new superEditor_converter.Mapping();
|
|
74943
|
+
transactions.forEach((tr2) => {
|
|
74944
|
+
mappingToNew.appendMapping(tr2.mapping);
|
|
74945
|
+
});
|
|
74946
|
+
const pendingInsertions = [];
|
|
74947
|
+
oldTags.forEach((tag, id) => {
|
|
74948
|
+
const current = newTags.get(id);
|
|
74949
|
+
if (tag.start && !current?.start) {
|
|
74950
|
+
const mapped = mappingToNew.mapResult(tag.start.pos, -1);
|
|
74951
|
+
pendingInsertions.push({
|
|
74952
|
+
pos: mapped.pos,
|
|
74953
|
+
nodeType: permStartType,
|
|
74954
|
+
attrs: tag.start.attrs,
|
|
74955
|
+
priority: 0
|
|
74956
|
+
});
|
|
74957
|
+
}
|
|
74958
|
+
if (tag.end && !current?.end) {
|
|
74959
|
+
const mapped = mappingToNew.mapResult(tag.end.pos, 1);
|
|
74960
|
+
pendingInsertions.push({
|
|
74961
|
+
pos: mapped.pos,
|
|
74962
|
+
nodeType: permEndType,
|
|
74963
|
+
attrs: tag.end.attrs,
|
|
74964
|
+
priority: 1
|
|
74965
|
+
});
|
|
74966
|
+
}
|
|
74967
|
+
});
|
|
74968
|
+
if (!pendingInsertions.length) {
|
|
74969
|
+
return null;
|
|
74970
|
+
}
|
|
74971
|
+
pendingInsertions.sort((a, b2) => {
|
|
74972
|
+
if (a.pos === b2.pos) {
|
|
74973
|
+
return a.priority - b2.priority;
|
|
74974
|
+
}
|
|
74975
|
+
return a.pos - b2.pos;
|
|
74976
|
+
});
|
|
74977
|
+
const tr = newState.tr;
|
|
74978
|
+
let offset2 = 0;
|
|
74979
|
+
pendingInsertions.forEach((item) => {
|
|
74980
|
+
const node = item.nodeType.create(item.attrs);
|
|
74981
|
+
const insertPos = clampPosition(item.pos + offset2, tr.doc.content.size);
|
|
74982
|
+
tr.insert(insertPos, node);
|
|
74983
|
+
offset2 += node.nodeSize;
|
|
74984
|
+
});
|
|
74985
|
+
return tr.docChanged ? tr : null;
|
|
74986
|
+
},
|
|
74987
|
+
// Filters transactions to ensure only allowed edits are applied.
|
|
74988
|
+
filterTransaction(tr, state) {
|
|
74989
|
+
if (!tr.docChanged) return true;
|
|
74990
|
+
if (!editor || editor.options.documentMode !== "viewing") return true;
|
|
74991
|
+
const pluginState = PERMISSION_PLUGIN_KEY.getState(state);
|
|
74992
|
+
if (!pluginState?.hasAllowedRanges) {
|
|
74993
|
+
return true;
|
|
74994
|
+
}
|
|
74995
|
+
const changedRanges = collectChangedRanges(tr);
|
|
74996
|
+
if (!changedRanges.length) return true;
|
|
74997
|
+
const permStartType = state.schema.nodes["permStart"];
|
|
74998
|
+
const permEndType = state.schema.nodes["permEnd"];
|
|
74999
|
+
if (!permStartType || !permEndType) return true;
|
|
75000
|
+
const allRangesAllowed = changedRanges.every((range) => {
|
|
75001
|
+
const trimmed = trimPermissionTagsFromRange(state.doc, range, permStartType, permEndType);
|
|
75002
|
+
return isRangeAllowed(trimmed, pluginState.ranges);
|
|
75003
|
+
});
|
|
75004
|
+
return allRangesAllowed;
|
|
75005
|
+
}
|
|
75006
|
+
})
|
|
75007
|
+
];
|
|
75008
|
+
}
|
|
75009
|
+
});
|
|
74638
75010
|
const PermStart = Node$1.create({
|
|
74639
75011
|
name: "permStart",
|
|
74640
75012
|
group: "inline",
|
|
@@ -74794,6 +75166,7 @@ const getStarterExtensions = () => {
|
|
|
74794
75166
|
ShapeGroup,
|
|
74795
75167
|
PermStart,
|
|
74796
75168
|
PermEnd,
|
|
75169
|
+
PermissionRanges,
|
|
74797
75170
|
PassthroughInline,
|
|
74798
75171
|
PassthroughBlock
|
|
74799
75172
|
];
|