superdoc 1.12.0-next.11 → 1.12.0-next.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{PdfViewer-1H_e-blH.cjs → PdfViewer-BM8GbrHb.cjs} +2 -2
- package/dist/chunks/{PdfViewer-2GmHPcuP.es.js → PdfViewer-D9duMPBd.es.js} +2 -2
- package/dist/chunks/{SuperConverter-DKC3eAnw.cjs → SuperConverter-BMjvGr5r.cjs} +14 -3
- package/dist/chunks/{SuperConverter-Cyd0kGmJ.es.js → SuperConverter-Dx95dNlr.es.js} +14 -3
- package/dist/chunks/{index-BKXPlsQF.cjs → index-BF7DfWLs.cjs} +756 -390
- package/dist/chunks/{index-BlzZBR33.es.js → index-BTrpAvox.es.js} +4 -4
- package/dist/chunks/{index-C22k0MUW.es.js → index-C-t9SDCr.es.js} +756 -390
- package/dist/chunks/{index-CpgpR-lf.cjs → index-DcUDN9u9.cjs} +4 -4
- package/dist/style.css +39 -29
- package/dist/super-editor/converter.cjs +1 -1
- package/dist/super-editor/converter.es.js +1 -1
- package/dist/super-editor/core/Editor.d.ts.map +1 -1
- package/dist/super-editor/core/presentation-editor/PresentationEditor.d.ts.map +1 -1
- package/dist/super-editor/core/super-converter/v3/handlers/w/sdt/helpers/handle-structured-content-node.d.ts.map +1 -1
- package/dist/super-editor/extensions/structured-content/StructuredContentBlockView.d.ts.map +1 -1
- package/dist/super-editor/extensions/structured-content/StructuredContentInlineView.d.ts.map +1 -1
- package/dist/super-editor/extensions/structured-content/StructuredContentViewBase.d.ts +3 -0
- package/dist/super-editor/extensions/structured-content/StructuredContentViewBase.d.ts.map +1 -1
- package/dist/super-editor/extensions/structured-content/structured-content-block.d.ts.map +1 -1
- package/dist/super-editor/extensions/structured-content/structured-content-lock-plugin.d.ts +5 -0
- package/dist/super-editor/extensions/structured-content/structured-content-lock-plugin.d.ts.map +1 -0
- package/dist/super-editor/extensions/structured-content/structured-content-select-plugin.d.ts +14 -0
- package/dist/super-editor/extensions/structured-content/structured-content-select-plugin.d.ts.map +1 -0
- package/dist/super-editor/extensions/structured-content/structured-content.d.ts.map +1 -1
- package/dist/super-editor/extensions/types/node-attributes.d.ts +4 -0
- package/dist/super-editor/extensions/types/node-attributes.d.ts.map +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 +770 -393
- package/dist/superdoc.umd.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as generateDocxRandomId, T as TextSelection$1, o as objectIncludes, w as wrapTextsInRuns, D as DOMParser$1, c as createDocFromMarkdown, a as createDocFromHTML, F as Fragment, b as chainableEditorState, d as convertMarkdownToHTML, f as findParentNode, e as findParentNodeClosestToPos, h as generateRandom32BitHex, i as generateRandomSigned32BitIntStrId, P as Plugin, j as PluginKey, M as Mapping, N as NodeSelection, k as Selection, l as Slice, m as DOMSerializer, n as Mark$1, p as dropPoint, A as AllSelection, q as Schema$2, s as canSplit, t as resolveRunProperties, u as encodeMarksFromRPr, v as liftTarget, x as replaceStep$1, y as canJoin, z as joinPoint, R as ReplaceAroundStep$1, B as htmlHandler, C as ReplaceStep, E as getResolvedParagraphProperties, G as changeListLevel, H as isList$1, I as updateNumberingProperties, L as ListHelpers, J as inputRulesPlugin, K as TrackDeleteMarkName, O as TrackInsertMarkName, Q as TrackFormatMarkName, U as AddMarkStep, V as RemoveMarkStep, W as CommandService, S as SuperConverter, X as EditorState, Y as unflattenListsInHtml, Z as SelectionRange, _ as Transform, $ as resolveParagraphProperties, a0 as resolveDocxFontFamily, a1 as _getReferencedTableStyles, a2 as resolveTableCellProperties, a3 as decodeRPrFromMarks, a4 as carbonCopy, a5 as calculateResolvedParagraphProperties, a6 as encodeCSSFromPPr, a7 as encodeCSSFromRPr, a8 as generateOrderedListIndex, a9 as docxNumberingHelpers, aa as InputRule, ab as insertNewRelationship, ac as kebabCase$1, ad as getUnderlineCssString, ae as handleClipboardPaste } from "./SuperConverter-
|
|
1
|
+
import { g as generateDocxRandomId, T as TextSelection$1, o as objectIncludes, w as wrapTextsInRuns, D as DOMParser$1, c as createDocFromMarkdown, a as createDocFromHTML, F as Fragment, b as chainableEditorState, d as convertMarkdownToHTML, f as findParentNode, e as findParentNodeClosestToPos, h as generateRandom32BitHex, i as generateRandomSigned32BitIntStrId, P as Plugin, j as PluginKey, M as Mapping, N as NodeSelection, k as Selection, l as Slice, m as DOMSerializer, n as Mark$1, p as dropPoint, A as AllSelection, q as Schema$2, s as canSplit, t as resolveRunProperties, u as encodeMarksFromRPr, v as liftTarget, x as replaceStep$1, y as canJoin, z as joinPoint, R as ReplaceAroundStep$1, B as htmlHandler, C as ReplaceStep, E as getResolvedParagraphProperties, G as changeListLevel, H as isList$1, I as updateNumberingProperties, L as ListHelpers, J as inputRulesPlugin, K as TrackDeleteMarkName, O as TrackInsertMarkName, Q as TrackFormatMarkName, U as AddMarkStep, V as RemoveMarkStep, W as CommandService, S as SuperConverter, X as EditorState, Y as unflattenListsInHtml, Z as SelectionRange, _ as Transform, $ as resolveParagraphProperties, a0 as resolveDocxFontFamily, a1 as _getReferencedTableStyles, a2 as resolveTableCellProperties, a3 as decodeRPrFromMarks, a4 as carbonCopy, a5 as calculateResolvedParagraphProperties, a6 as encodeCSSFromPPr, a7 as encodeCSSFromRPr, a8 as generateOrderedListIndex, a9 as docxNumberingHelpers, aa as InputRule, ab as insertNewRelationship, ac as kebabCase$1, ad as getUnderlineCssString, ae as handleClipboardPaste } from "./SuperConverter-Dx95dNlr.es.js";
|
|
2
2
|
import { j as twipsToInches, m as inchesToTwips, p as ptToTwips, d as linesToTwips, f as twipsToLines, k as pixelsToTwips, z as resolveOpcTargetPath, B as Buffer$3, D as getArrayBufferFromUrl, h as halfPointToPoints, c as twipsToPixels$2, E as convertSizeToCSS, F as inchesToPixels } from "./helpers-BqdwtJE0.es.js";
|
|
3
3
|
import { p as process$1$2, r as ref, b as computed, c as createElementBlock, F as Fragment$1, U as renderList, O as withModifiers, o as openBlock, Q as normalizeClass, M as toDisplayString, i as createCommentVNode, a as createBaseVNode, V as createApp, e as onMounted, f as onUnmounted, u as unref, S as withDirectives, Y as vModelText, D as nextTick, N as normalizeStyle, B as watch, Z as withKeys, _ as createTextVNode, g as createVNode, h as h$1, $ as readonly, E as getCurrentInstance, l as onBeforeUnmount, s as reactive, m as onBeforeMount, j as inject, a0 as onActivated, a1 as onDeactivated, a2 as Comment, d as defineComponent, k as provide, q as Teleport, t as toRef, a3 as renderSlot, a4 as isVNode, K as shallowRef, w as watchEffect, J as global$2, T as Transition, a5 as mergeProps, a6 as vShow, a7 as cloneVNode, a8 as Text$2, x as markRaw, P as createBlock, L as withCtx, a9 as useCssVars, W as resolveDynamicComponent, aa as normalizeProps, ab as guardReactiveProps } from "./vue-DiPLN5sT.es.js";
|
|
4
4
|
import "./jszip.min-BCZQ7Wq2.es.js";
|
|
@@ -976,7 +976,7 @@ const DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
|
|
|
976
976
|
const COMMUNITY_LICENSE_KEY = "community-and-eval-agplv3";
|
|
977
977
|
function getSuperdocVersion() {
|
|
978
978
|
try {
|
|
979
|
-
return true ? "1.12.0-next.
|
|
979
|
+
return true ? "1.12.0-next.13" : "unknown";
|
|
980
980
|
} catch {
|
|
981
981
|
return "unknown";
|
|
982
982
|
}
|
|
@@ -17051,7 +17051,7 @@ const canUseDOM = () => {
|
|
|
17051
17051
|
return false;
|
|
17052
17052
|
}
|
|
17053
17053
|
};
|
|
17054
|
-
const summaryVersion = "1.12.0-next.
|
|
17054
|
+
const summaryVersion = "1.12.0-next.13";
|
|
17055
17055
|
const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
|
|
17056
17056
|
const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
|
|
17057
17057
|
function mapAttributes(attrs) {
|
|
@@ -19465,8 +19465,7 @@ class Editor extends EventEmitter {
|
|
|
19465
19465
|
"docProps/custom.xml": String(customXml),
|
|
19466
19466
|
"word/_rels/document.xml.rels": String(rels),
|
|
19467
19467
|
"word/numbering.xml": String(numbering),
|
|
19468
|
-
|
|
19469
|
-
"word/styles.xml": String(styles).replace(/&/gi, "&"),
|
|
19468
|
+
"word/styles.xml": String(styles),
|
|
19470
19469
|
...updatedHeadersFooters,
|
|
19471
19470
|
...coreXml ? { "docProps/core.xml": String(coreXml) } : {}
|
|
19472
19471
|
};
|
|
@@ -19856,7 +19855,7 @@ class Editor extends EventEmitter {
|
|
|
19856
19855
|
* Process collaboration migrations
|
|
19857
19856
|
*/
|
|
19858
19857
|
processCollaborationMigrations() {
|
|
19859
|
-
console.debug("[checkVersionMigrations] Current editor version", "1.12.0-next.
|
|
19858
|
+
console.debug("[checkVersionMigrations] Current editor version", "1.12.0-next.13");
|
|
19860
19859
|
if (!this.options.ydoc) return;
|
|
19861
19860
|
const metaMap = this.options.ydoc.getMap("meta");
|
|
19862
19861
|
let docVersion = metaMap.get("version");
|
|
@@ -20034,6 +20033,300 @@ class Editor extends EventEmitter {
|
|
|
20034
20033
|
this.#renderer?.initDevTools?.(this);
|
|
20035
20034
|
}
|
|
20036
20035
|
}
|
|
20036
|
+
function getEditorSurfaceElement(editor) {
|
|
20037
|
+
if (!editor) return null;
|
|
20038
|
+
if (typeof editor.hitTest === "function" && editor.element instanceof HTMLElement) {
|
|
20039
|
+
return editor.element;
|
|
20040
|
+
}
|
|
20041
|
+
return editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element ?? null;
|
|
20042
|
+
}
|
|
20043
|
+
function getSurfaceRelativePoint(editor, eventLocation = {}) {
|
|
20044
|
+
const surface = getEditorSurfaceElement(editor);
|
|
20045
|
+
if (!surface) return null;
|
|
20046
|
+
const rect = surface.getBoundingClientRect();
|
|
20047
|
+
let left2;
|
|
20048
|
+
let top2;
|
|
20049
|
+
if (typeof eventLocation.clientX === "number" && typeof eventLocation.clientY === "number") {
|
|
20050
|
+
left2 = eventLocation.clientX - rect.left;
|
|
20051
|
+
top2 = eventLocation.clientY - rect.top;
|
|
20052
|
+
} else if (editor?.state?.selection) {
|
|
20053
|
+
const selectionFrom = editor.state.selection.from;
|
|
20054
|
+
const coords = editor.coordsAtPos?.(selectionFrom);
|
|
20055
|
+
if (coords) {
|
|
20056
|
+
left2 = coords.left - rect.left;
|
|
20057
|
+
top2 = coords.top - rect.top;
|
|
20058
|
+
}
|
|
20059
|
+
}
|
|
20060
|
+
if (!Number.isFinite(left2) || !Number.isFinite(top2)) {
|
|
20061
|
+
return null;
|
|
20062
|
+
}
|
|
20063
|
+
return { left: left2, top: top2 };
|
|
20064
|
+
}
|
|
20065
|
+
function findContainingBlockAncestor(element) {
|
|
20066
|
+
if (!element) return null;
|
|
20067
|
+
let current = element.parentElement;
|
|
20068
|
+
while (current && current !== document.body && current !== document.documentElement) {
|
|
20069
|
+
try {
|
|
20070
|
+
const style2 = window.getComputedStyle(current);
|
|
20071
|
+
const transform = style2.transform;
|
|
20072
|
+
const filter = style2.filter;
|
|
20073
|
+
const backdropFilter = style2.backdropFilter || style2.webkitBackdropFilter;
|
|
20074
|
+
const perspective = style2.perspective;
|
|
20075
|
+
const willChange = style2.willChange;
|
|
20076
|
+
const contain = style2.contain;
|
|
20077
|
+
if (transform && transform !== "none") {
|
|
20078
|
+
return current;
|
|
20079
|
+
}
|
|
20080
|
+
if (filter && filter !== "none") {
|
|
20081
|
+
return current;
|
|
20082
|
+
}
|
|
20083
|
+
if (backdropFilter && backdropFilter !== "none") {
|
|
20084
|
+
return current;
|
|
20085
|
+
}
|
|
20086
|
+
if (perspective && perspective !== "none") {
|
|
20087
|
+
return current;
|
|
20088
|
+
}
|
|
20089
|
+
if (willChange && willChange !== "auto") {
|
|
20090
|
+
const values = willChange.split(",").map((v) => v.trim());
|
|
20091
|
+
if (values.includes("transform") || values.includes("perspective")) {
|
|
20092
|
+
return current;
|
|
20093
|
+
}
|
|
20094
|
+
}
|
|
20095
|
+
if (contain && /paint|layout|strict|content/.test(contain)) {
|
|
20096
|
+
return current;
|
|
20097
|
+
}
|
|
20098
|
+
} catch (error) {
|
|
20099
|
+
console.warn("SlashMenu: Failed to get computed style for element", current, error);
|
|
20100
|
+
}
|
|
20101
|
+
current = current.parentElement;
|
|
20102
|
+
}
|
|
20103
|
+
return null;
|
|
20104
|
+
}
|
|
20105
|
+
const SlashMenuPluginKey = new PluginKey("slashMenu");
|
|
20106
|
+
const MENU_OFFSET_X = 100;
|
|
20107
|
+
const MENU_OFFSET_Y = 28;
|
|
20108
|
+
const CONTEXT_MENU_OFFSET_X = 10;
|
|
20109
|
+
const CONTEXT_MENU_OFFSET_Y = 10;
|
|
20110
|
+
const SLASH_COOLDOWN_MS = 5e3;
|
|
20111
|
+
const SlashMenu = Extension.create({
|
|
20112
|
+
name: "slashMenu",
|
|
20113
|
+
/**
|
|
20114
|
+
* Initialize default options for the SlashMenu extension
|
|
20115
|
+
* @returns {SlashMenuOptions} Empty options object (configuration is inherited from editor options)
|
|
20116
|
+
*/
|
|
20117
|
+
addOptions() {
|
|
20118
|
+
return {};
|
|
20119
|
+
},
|
|
20120
|
+
addPmPlugins() {
|
|
20121
|
+
const editor = this.editor;
|
|
20122
|
+
if (editor.options?.isHeadless) {
|
|
20123
|
+
return [];
|
|
20124
|
+
}
|
|
20125
|
+
let slashCooldown = false;
|
|
20126
|
+
let slashCooldownTimeout = null;
|
|
20127
|
+
const isMenuDisabled = () => Boolean(editor.options?.disableContextMenu);
|
|
20128
|
+
const ensureStateShape = (value = {}) => ({
|
|
20129
|
+
open: false,
|
|
20130
|
+
selected: null,
|
|
20131
|
+
anchorPos: null,
|
|
20132
|
+
menuPosition: null,
|
|
20133
|
+
disabled: isMenuDisabled(),
|
|
20134
|
+
...value
|
|
20135
|
+
});
|
|
20136
|
+
const slashMenuPlugin = new Plugin({
|
|
20137
|
+
key: SlashMenuPluginKey,
|
|
20138
|
+
state: {
|
|
20139
|
+
init: () => ensureStateShape(),
|
|
20140
|
+
/**
|
|
20141
|
+
* Apply transaction to update plugin state
|
|
20142
|
+
* Handles state transitions based on transaction metadata:
|
|
20143
|
+
* - 'open': Opens menu at specified position or cursor location
|
|
20144
|
+
* - 'select': Updates the selected menu item
|
|
20145
|
+
* - 'close': Closes the menu and clears anchor position
|
|
20146
|
+
* - 'updatePosition': Triggers menu position recalculation (no-op in apply)
|
|
20147
|
+
*
|
|
20148
|
+
* @param {import('prosemirror-state').Transaction} tr - The transaction
|
|
20149
|
+
* @param {SlashMenuState} value - Previous plugin state
|
|
20150
|
+
* @returns {SlashMenuState} New plugin state
|
|
20151
|
+
*/
|
|
20152
|
+
apply(tr, value) {
|
|
20153
|
+
const meta = tr.getMeta(SlashMenuPluginKey);
|
|
20154
|
+
const disabled = isMenuDisabled();
|
|
20155
|
+
if (disabled) {
|
|
20156
|
+
if (value.open) {
|
|
20157
|
+
editor.emit("slashMenu:close");
|
|
20158
|
+
}
|
|
20159
|
+
return ensureStateShape({ disabled: true });
|
|
20160
|
+
}
|
|
20161
|
+
if (!meta) {
|
|
20162
|
+
if (value.disabled !== disabled) {
|
|
20163
|
+
return ensureStateShape({ ...value, disabled });
|
|
20164
|
+
}
|
|
20165
|
+
return value;
|
|
20166
|
+
}
|
|
20167
|
+
switch (meta.type) {
|
|
20168
|
+
case "open": {
|
|
20169
|
+
if (typeof meta.pos !== "number" || meta.pos < 0 || meta.pos > tr.doc.content.size) {
|
|
20170
|
+
console.warn("SlashMenu: Invalid position", meta.pos);
|
|
20171
|
+
return ensureStateShape(value);
|
|
20172
|
+
}
|
|
20173
|
+
let left2 = 0;
|
|
20174
|
+
let top2 = 0;
|
|
20175
|
+
let isContextMenu = false;
|
|
20176
|
+
if (typeof meta.clientX === "number" && typeof meta.clientY === "number") {
|
|
20177
|
+
left2 = meta.clientX;
|
|
20178
|
+
top2 = meta.clientY;
|
|
20179
|
+
isContextMenu = true;
|
|
20180
|
+
} else {
|
|
20181
|
+
const relativePoint = getSurfaceRelativePoint(editor, meta);
|
|
20182
|
+
if (relativePoint) {
|
|
20183
|
+
const surface = editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element;
|
|
20184
|
+
if (surface) {
|
|
20185
|
+
try {
|
|
20186
|
+
const rect = surface.getBoundingClientRect();
|
|
20187
|
+
left2 = rect.left + relativePoint.left;
|
|
20188
|
+
top2 = rect.top + relativePoint.top;
|
|
20189
|
+
} catch (error) {
|
|
20190
|
+
console.warn("SlashMenu: Failed to get surface bounds", error);
|
|
20191
|
+
return ensureStateShape(value);
|
|
20192
|
+
}
|
|
20193
|
+
}
|
|
20194
|
+
}
|
|
20195
|
+
}
|
|
20196
|
+
const menuSurface = editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element;
|
|
20197
|
+
const containingBlock = findContainingBlockAncestor(menuSurface);
|
|
20198
|
+
if (containingBlock) {
|
|
20199
|
+
try {
|
|
20200
|
+
const cbRect = containingBlock.getBoundingClientRect();
|
|
20201
|
+
left2 -= cbRect.left;
|
|
20202
|
+
top2 -= cbRect.top;
|
|
20203
|
+
left2 += containingBlock.scrollLeft || 0;
|
|
20204
|
+
top2 += containingBlock.scrollTop || 0;
|
|
20205
|
+
} catch (error) {
|
|
20206
|
+
console.warn("SlashMenu: Failed to adjust for containing block", error);
|
|
20207
|
+
}
|
|
20208
|
+
}
|
|
20209
|
+
const offsetX = isContextMenu ? CONTEXT_MENU_OFFSET_X : MENU_OFFSET_X;
|
|
20210
|
+
const offsetY = isContextMenu ? CONTEXT_MENU_OFFSET_Y : MENU_OFFSET_Y;
|
|
20211
|
+
const menuPosition = {
|
|
20212
|
+
left: `${left2 + offsetX}px`,
|
|
20213
|
+
top: `${top2 + offsetY}px`
|
|
20214
|
+
};
|
|
20215
|
+
const newState = {
|
|
20216
|
+
...value,
|
|
20217
|
+
open: true,
|
|
20218
|
+
anchorPos: meta.pos,
|
|
20219
|
+
menuPosition
|
|
20220
|
+
};
|
|
20221
|
+
editor.emit("slashMenu:open", { menuPosition });
|
|
20222
|
+
return ensureStateShape(newState);
|
|
20223
|
+
}
|
|
20224
|
+
case "select": {
|
|
20225
|
+
return ensureStateShape({ ...value, selected: meta.id });
|
|
20226
|
+
}
|
|
20227
|
+
case "close": {
|
|
20228
|
+
editor.emit("slashMenu:close");
|
|
20229
|
+
return ensureStateShape({ ...value, open: false, anchorPos: null });
|
|
20230
|
+
}
|
|
20231
|
+
default:
|
|
20232
|
+
return ensureStateShape({ ...value, disabled });
|
|
20233
|
+
}
|
|
20234
|
+
}
|
|
20235
|
+
},
|
|
20236
|
+
/**
|
|
20237
|
+
* Create view plugin to handle window event listeners
|
|
20238
|
+
* @param {import('prosemirror-view').EditorView} editorView - The ProseMirror editor view
|
|
20239
|
+
* @returns {Object} View plugin with destroy method
|
|
20240
|
+
*/
|
|
20241
|
+
view(editorView) {
|
|
20242
|
+
const updatePosition2 = () => {
|
|
20243
|
+
if (isMenuDisabled()) return;
|
|
20244
|
+
const state = SlashMenuPluginKey.getState(editorView.state);
|
|
20245
|
+
if (state.open) {
|
|
20246
|
+
editorView.dispatch(
|
|
20247
|
+
editorView.state.tr.setMeta(SlashMenuPluginKey, {
|
|
20248
|
+
type: "updatePosition"
|
|
20249
|
+
})
|
|
20250
|
+
);
|
|
20251
|
+
}
|
|
20252
|
+
};
|
|
20253
|
+
window.addEventListener("scroll", updatePosition2, true);
|
|
20254
|
+
window.addEventListener("resize", updatePosition2);
|
|
20255
|
+
return {
|
|
20256
|
+
destroy() {
|
|
20257
|
+
window.removeEventListener("scroll", updatePosition2, true);
|
|
20258
|
+
window.removeEventListener("resize", updatePosition2);
|
|
20259
|
+
if (slashCooldownTimeout) {
|
|
20260
|
+
clearTimeout(slashCooldownTimeout);
|
|
20261
|
+
slashCooldownTimeout = null;
|
|
20262
|
+
}
|
|
20263
|
+
}
|
|
20264
|
+
};
|
|
20265
|
+
},
|
|
20266
|
+
props: {
|
|
20267
|
+
/**
|
|
20268
|
+
* Handle keyboard events to open/close the slash menu
|
|
20269
|
+
* - '/': Opens menu at cursor if conditions are met (in paragraph, after space/start)
|
|
20270
|
+
* - 'Escape' or 'ArrowLeft': Closes menu and restores cursor position
|
|
20271
|
+
*
|
|
20272
|
+
* @param {import('prosemirror-view').EditorView} view - The ProseMirror editor view
|
|
20273
|
+
* @param {KeyboardEvent} event - The keyboard event
|
|
20274
|
+
* @returns {boolean} True if the event was handled, false otherwise
|
|
20275
|
+
*/
|
|
20276
|
+
handleKeyDown(view, event) {
|
|
20277
|
+
if (isMenuDisabled()) {
|
|
20278
|
+
return false;
|
|
20279
|
+
}
|
|
20280
|
+
const pluginState = this.getState(view.state);
|
|
20281
|
+
if (event.key === "/" && slashCooldown) {
|
|
20282
|
+
return false;
|
|
20283
|
+
}
|
|
20284
|
+
if (event.key === "/" && !pluginState.open) {
|
|
20285
|
+
const { $cursor } = view.state.selection;
|
|
20286
|
+
if (!$cursor) return false;
|
|
20287
|
+
const isParagraph = $cursor.parent.type.name === "paragraph";
|
|
20288
|
+
if (!isParagraph) return false;
|
|
20289
|
+
const textBefore = $cursor.parent.textContent.slice(0, $cursor.parentOffset);
|
|
20290
|
+
const isEmptyOrAfterSpace = !textBefore || textBefore.endsWith(" ");
|
|
20291
|
+
if (!isEmptyOrAfterSpace) return false;
|
|
20292
|
+
event.preventDefault();
|
|
20293
|
+
slashCooldown = true;
|
|
20294
|
+
if (slashCooldownTimeout) clearTimeout(slashCooldownTimeout);
|
|
20295
|
+
slashCooldownTimeout = setTimeout(() => {
|
|
20296
|
+
slashCooldown = false;
|
|
20297
|
+
slashCooldownTimeout = null;
|
|
20298
|
+
}, SLASH_COOLDOWN_MS);
|
|
20299
|
+
view.dispatch(
|
|
20300
|
+
view.state.tr.setMeta(SlashMenuPluginKey, {
|
|
20301
|
+
type: "open",
|
|
20302
|
+
pos: $cursor.pos
|
|
20303
|
+
})
|
|
20304
|
+
);
|
|
20305
|
+
return true;
|
|
20306
|
+
}
|
|
20307
|
+
if (pluginState.open && (event.key === "Escape" || event.key === "ArrowLeft")) {
|
|
20308
|
+
const { anchorPos } = pluginState;
|
|
20309
|
+
view.dispatch(
|
|
20310
|
+
view.state.tr.setMeta(SlashMenuPluginKey, {
|
|
20311
|
+
type: "close"
|
|
20312
|
+
})
|
|
20313
|
+
);
|
|
20314
|
+
if (anchorPos !== null) {
|
|
20315
|
+
const tr = view.state.tr.setSelection(
|
|
20316
|
+
view.state.selection.constructor.near(view.state.doc.resolve(anchorPos))
|
|
20317
|
+
);
|
|
20318
|
+
view.dispatch(tr);
|
|
20319
|
+
view.focus();
|
|
20320
|
+
}
|
|
20321
|
+
return true;
|
|
20322
|
+
}
|
|
20323
|
+
return false;
|
|
20324
|
+
}
|
|
20325
|
+
}
|
|
20326
|
+
});
|
|
20327
|
+
return [slashMenuPlugin];
|
|
20328
|
+
}
|
|
20329
|
+
});
|
|
20037
20330
|
let readFromCache;
|
|
20038
20331
|
let addToCache;
|
|
20039
20332
|
if (typeof WeakMap != "undefined") {
|
|
@@ -25067,21 +25360,21 @@ const SDT_CONTAINER_STYLES = `
|
|
|
25067
25360
|
|
|
25068
25361
|
/* Structured content drag handle/label - positioned above */
|
|
25069
25362
|
.superdoc-structured-content__label {
|
|
25070
|
-
font-size:
|
|
25363
|
+
font-size: 11px;
|
|
25071
25364
|
align-items: center;
|
|
25072
25365
|
justify-content: center;
|
|
25073
25366
|
position: absolute;
|
|
25074
25367
|
left: 2px;
|
|
25075
25368
|
top: -19px;
|
|
25076
25369
|
width: calc(100% - 4px);
|
|
25077
|
-
max-width:
|
|
25370
|
+
max-width: 130px;
|
|
25078
25371
|
min-width: 0;
|
|
25079
25372
|
height: 18px;
|
|
25080
25373
|
padding: 0 4px;
|
|
25081
25374
|
border: 1px solid #629be7;
|
|
25082
25375
|
border-bottom: none;
|
|
25083
25376
|
border-radius: 6px 6px 0 0;
|
|
25084
|
-
background-color: #
|
|
25377
|
+
background-color: #629be7ee;
|
|
25085
25378
|
box-sizing: border-box;
|
|
25086
25379
|
z-index: 10;
|
|
25087
25380
|
display: none;
|
|
@@ -25095,7 +25388,9 @@ const SDT_CONTAINER_STYLES = `
|
|
|
25095
25388
|
text-overflow: ellipsis;
|
|
25096
25389
|
}
|
|
25097
25390
|
|
|
25098
|
-
|
|
25391
|
+
/* Hover effect for block structured content (via event delegation class).
|
|
25392
|
+
* Shows label on hover — border reveal is handled by the lock-mode hover rule below. */
|
|
25393
|
+
.superdoc-structured-content-block.sdt-hover .superdoc-structured-content__label {
|
|
25099
25394
|
display: inline-flex;
|
|
25100
25395
|
}
|
|
25101
25396
|
|
|
@@ -25124,6 +25419,13 @@ const SDT_CONTAINER_STYLES = `
|
|
|
25124
25419
|
border-bottom: none;
|
|
25125
25420
|
}
|
|
25126
25421
|
|
|
25422
|
+
/* Collapse double borders between adjacent SDT blocks */
|
|
25423
|
+
.superdoc-structured-content-block + .superdoc-structured-content-block {
|
|
25424
|
+
border-top: none;
|
|
25425
|
+
border-top-left-radius: 0;
|
|
25426
|
+
border-top-right-radius: 0;
|
|
25427
|
+
}
|
|
25428
|
+
|
|
25127
25429
|
/* Structured Content Inline - Inline wrapper with blue border */
|
|
25128
25430
|
.superdoc-structured-content-inline {
|
|
25129
25431
|
padding: 1px;
|
|
@@ -25135,21 +25437,15 @@ const SDT_CONTAINER_STYLES = `
|
|
|
25135
25437
|
z-index: 10;
|
|
25136
25438
|
}
|
|
25137
25439
|
|
|
25138
|
-
/* Hover effect for inline structured content */
|
|
25139
|
-
.superdoc-structured-content-inline:hover {
|
|
25140
|
-
background-color: rgba(98, 155, 231, 0.15);
|
|
25141
|
-
border-color: #4a8ad9;
|
|
25142
|
-
}
|
|
25143
|
-
|
|
25144
25440
|
/* Inline structured content label - shown on hover */
|
|
25145
25441
|
.superdoc-structured-content-inline__label {
|
|
25146
25442
|
position: absolute;
|
|
25147
25443
|
bottom: calc(100% + 2px);
|
|
25148
25444
|
left: 50%;
|
|
25149
25445
|
transform: translateX(-50%);
|
|
25150
|
-
font-size:
|
|
25151
|
-
padding:
|
|
25152
|
-
background-color: #
|
|
25446
|
+
font-size: 11px;
|
|
25447
|
+
padding: 0 4px;
|
|
25448
|
+
background-color: #629be7ee;
|
|
25153
25449
|
color: white;
|
|
25154
25450
|
border-radius: 4px;
|
|
25155
25451
|
white-space: nowrap;
|
|
@@ -25162,6 +25458,17 @@ const SDT_CONTAINER_STYLES = `
|
|
|
25162
25458
|
display: block;
|
|
25163
25459
|
}
|
|
25164
25460
|
|
|
25461
|
+
/* Hover highlight for SDT containers.
|
|
25462
|
+
* Blue border is always visible (set in base rules above).
|
|
25463
|
+
* Hover adds background highlight and z-index boost.
|
|
25464
|
+
* Block SDTs use .sdt-hover class (event delegation for multi-fragment coordination).
|
|
25465
|
+
* Inline SDTs use :hover (single element, no coordination needed). */
|
|
25466
|
+
.superdoc-structured-content-block[data-lock-mode].sdt-hover,
|
|
25467
|
+
.superdoc-structured-content-inline[data-lock-mode]:hover {
|
|
25468
|
+
background-color: rgba(98, 155, 231, 0.08);
|
|
25469
|
+
z-index: 9999999;
|
|
25470
|
+
}
|
|
25471
|
+
|
|
25165
25472
|
/* Viewing mode: remove structured content affordances */
|
|
25166
25473
|
.presentation-editor--viewing .superdoc-structured-content-block,
|
|
25167
25474
|
.presentation-editor--viewing .superdoc-structured-content-inline {
|
|
@@ -25207,7 +25514,7 @@ const FIELD_ANNOTATION_STYLES = `
|
|
|
25207
25514
|
.superdoc-layout .annotation *::selection {
|
|
25208
25515
|
background: transparent;
|
|
25209
25516
|
}
|
|
25210
|
-
|
|
25517
|
+
|
|
25211
25518
|
.superdoc-layout .annotation::-moz-selection,
|
|
25212
25519
|
.superdoc-layout .annotation *::-moz-selection {
|
|
25213
25520
|
background: transparent;
|
|
@@ -25359,7 +25666,16 @@ const DOM_CLASS_NAMES = {
|
|
|
25359
25666
|
* within this wrapper should be used for character-level positioning, not the
|
|
25360
25667
|
* wrapper itself.
|
|
25361
25668
|
*/
|
|
25362
|
-
INLINE_SDT_WRAPPER: "superdoc-structured-content-inline"
|
|
25669
|
+
INLINE_SDT_WRAPPER: "superdoc-structured-content-inline",
|
|
25670
|
+
/**
|
|
25671
|
+
* Class name for block-level structured content containers.
|
|
25672
|
+
*/
|
|
25673
|
+
BLOCK_SDT: "superdoc-structured-content-block",
|
|
25674
|
+
/**
|
|
25675
|
+
* Class name added to block SDT fragments on hover via event delegation.
|
|
25676
|
+
* Applied/removed by SdtGroupedHover to highlight all fragments of the same SDT.
|
|
25677
|
+
*/
|
|
25678
|
+
SDT_HOVER: "sdt-hover"
|
|
25363
25679
|
};
|
|
25364
25680
|
const DEFAULT_ALLOWED_PROTOCOLS = ["http", "https", "mailto", "tel", "sms"];
|
|
25365
25681
|
const OPTIONAL_PROTOCOLS = ["ftp", "sftp", "irc"];
|
|
@@ -25764,6 +26080,11 @@ function applySdtContainerStyling(doc2, container, sdt, containerSdt, boundaryOp
|
|
|
25764
26080
|
container.dataset.sdtContainerStart = String(isStart);
|
|
25765
26081
|
container.dataset.sdtContainerEnd = String(isEnd);
|
|
25766
26082
|
container.style.overflow = "visible";
|
|
26083
|
+
if (isStructuredContentMetadata(sdt)) {
|
|
26084
|
+
container.dataset.lockMode = sdt.lockMode || "unlocked";
|
|
26085
|
+
} else if (isStructuredContentMetadata(containerSdt)) {
|
|
26086
|
+
container.dataset.lockMode = containerSdt.lockMode || "unlocked";
|
|
26087
|
+
}
|
|
25767
26088
|
if (boundaryOptions?.widthOverride != null) {
|
|
25768
26089
|
container.style.width = `${boundaryOptions.widthOverride}px`;
|
|
25769
26090
|
}
|
|
@@ -25776,6 +26097,19 @@ function applySdtContainerStyling(doc2, container, sdt, containerSdt, boundaryOp
|
|
|
25776
26097
|
container.appendChild(labelEl);
|
|
25777
26098
|
}
|
|
25778
26099
|
}
|
|
26100
|
+
function shouldRebuildForSdtBoundary(element, boundary) {
|
|
26101
|
+
if (!boundary) {
|
|
26102
|
+
return element.dataset.sdtContainerStart !== void 0;
|
|
26103
|
+
}
|
|
26104
|
+
const startAttr = element.dataset.sdtContainerStart;
|
|
26105
|
+
const endAttr = element.dataset.sdtContainerEnd;
|
|
26106
|
+
const expectedStart = String(boundary.isStart ?? true);
|
|
26107
|
+
const expectedEnd = String(boundary.isEnd ?? true);
|
|
26108
|
+
if (startAttr === void 0 || endAttr === void 0) {
|
|
26109
|
+
return true;
|
|
26110
|
+
}
|
|
26111
|
+
return startAttr !== expectedStart || endAttr !== expectedEnd;
|
|
26112
|
+
}
|
|
25779
26113
|
const TWIPS_PER_INCH$4 = 1440;
|
|
25780
26114
|
const PX_PER_INCH$3 = 96;
|
|
25781
26115
|
const PX_PER_PT = 96 / 72;
|
|
@@ -27254,6 +27588,65 @@ function assertFragmentPmPositions(fragment, _context) {
|
|
|
27254
27588
|
const hasPmEnd = fragment.pmEnd != null;
|
|
27255
27589
|
globalValidationStats.record(hasPmStart, hasPmEnd);
|
|
27256
27590
|
}
|
|
27591
|
+
const SDT_BLOCK_SELECTOR = `.${DOM_CLASS_NAMES.BLOCK_SDT}[data-sdt-id]`;
|
|
27592
|
+
const HOVER_CLASS = DOM_CLASS_NAMES.SDT_HOVER;
|
|
27593
|
+
function sdtElementsById(root2, sdtId) {
|
|
27594
|
+
return root2.querySelectorAll(`.${DOM_CLASS_NAMES.BLOCK_SDT}[data-sdt-id="${sdtId}"]`);
|
|
27595
|
+
}
|
|
27596
|
+
class SdtGroupedHover {
|
|
27597
|
+
constructor() {
|
|
27598
|
+
this.hoveredSdtId = null;
|
|
27599
|
+
this.mount = null;
|
|
27600
|
+
this.onMouseOver = null;
|
|
27601
|
+
this.onMouseLeave = null;
|
|
27602
|
+
}
|
|
27603
|
+
/** Attach hover listeners to the mount element. Safe to call again on remount. */
|
|
27604
|
+
bind(mount2) {
|
|
27605
|
+
this.destroy();
|
|
27606
|
+
this.mount = mount2;
|
|
27607
|
+
this.onMouseOver = (e) => {
|
|
27608
|
+
const target = e.target.closest?.(SDT_BLOCK_SELECTOR);
|
|
27609
|
+
const sdtId = target?.dataset.sdtId ?? null;
|
|
27610
|
+
if (sdtId === this.hoveredSdtId) return;
|
|
27611
|
+
if (this.hoveredSdtId) {
|
|
27612
|
+
sdtElementsById(mount2, this.hoveredSdtId).forEach((el) => el.classList.remove(HOVER_CLASS));
|
|
27613
|
+
}
|
|
27614
|
+
this.hoveredSdtId = sdtId;
|
|
27615
|
+
if (sdtId) {
|
|
27616
|
+
sdtElementsById(mount2, sdtId).forEach((el) => el.classList.add(HOVER_CLASS));
|
|
27617
|
+
}
|
|
27618
|
+
};
|
|
27619
|
+
this.onMouseLeave = () => {
|
|
27620
|
+
if (this.hoveredSdtId) {
|
|
27621
|
+
sdtElementsById(mount2, this.hoveredSdtId).forEach((el) => el.classList.remove(HOVER_CLASS));
|
|
27622
|
+
this.hoveredSdtId = null;
|
|
27623
|
+
}
|
|
27624
|
+
};
|
|
27625
|
+
mount2.addEventListener("mouseover", this.onMouseOver);
|
|
27626
|
+
mount2.addEventListener("mouseleave", this.onMouseLeave);
|
|
27627
|
+
}
|
|
27628
|
+
/** Re-apply hover class after render. New/rebuilt elements lose the class. */
|
|
27629
|
+
reapply() {
|
|
27630
|
+
if (this.hoveredSdtId && this.mount) {
|
|
27631
|
+
sdtElementsById(this.mount, this.hoveredSdtId).forEach((el) => el.classList.add(HOVER_CLASS));
|
|
27632
|
+
}
|
|
27633
|
+
}
|
|
27634
|
+
/** Remove listeners and reset state. */
|
|
27635
|
+
destroy() {
|
|
27636
|
+
if (this.mount) {
|
|
27637
|
+
if (this.onMouseOver) {
|
|
27638
|
+
this.mount.removeEventListener("mouseover", this.onMouseOver);
|
|
27639
|
+
}
|
|
27640
|
+
if (this.onMouseLeave) {
|
|
27641
|
+
this.mount.removeEventListener("mouseleave", this.onMouseLeave);
|
|
27642
|
+
}
|
|
27643
|
+
}
|
|
27644
|
+
this.mount = null;
|
|
27645
|
+
this.onMouseOver = null;
|
|
27646
|
+
this.onMouseLeave = null;
|
|
27647
|
+
this.hoveredSdtId = null;
|
|
27648
|
+
}
|
|
27649
|
+
}
|
|
27257
27650
|
const DEFAULT_PPI = 96;
|
|
27258
27651
|
const DEFAULT_RULER_HEIGHT = 25;
|
|
27259
27652
|
const TICK_SPACING_PX = DEFAULT_PPI / 8;
|
|
@@ -27962,6 +28355,7 @@ class DomPainter {
|
|
|
27962
28355
|
this.onScrollHandler = null;
|
|
27963
28356
|
this.onWindowScrollHandler = null;
|
|
27964
28357
|
this.onResizeHandler = null;
|
|
28358
|
+
this.sdtHover = new SdtGroupedHover();
|
|
27965
28359
|
this.activeCommentId = null;
|
|
27966
28360
|
this.options = options;
|
|
27967
28361
|
this.layoutMode = options.layoutMode ?? "vertical";
|
|
@@ -28227,6 +28621,7 @@ class DomPainter {
|
|
|
28227
28621
|
};
|
|
28228
28622
|
win.addEventListener("resize", this.onResizeHandler);
|
|
28229
28623
|
}
|
|
28624
|
+
this.sdtHover.bind(mount2);
|
|
28230
28625
|
}
|
|
28231
28626
|
computeVirtualMetrics() {
|
|
28232
28627
|
if (!this.currentLayout) return;
|
|
@@ -28369,6 +28764,7 @@ class DomPainter {
|
|
|
28369
28764
|
}
|
|
28370
28765
|
this.changedBlocks.clear();
|
|
28371
28766
|
this.processedLayoutVersion = this.layoutVersion;
|
|
28767
|
+
this.sdtHover.reapply();
|
|
28372
28768
|
}
|
|
28373
28769
|
updateSpacers(start2, end2) {
|
|
28374
28770
|
if (!this.topSpacerEl || !this.bottomSpacerEl) return;
|
|
@@ -28653,6 +29049,7 @@ class DomPainter {
|
|
|
28653
29049
|
this.onScrollHandler = null;
|
|
28654
29050
|
this.onWindowScrollHandler = null;
|
|
28655
29051
|
this.onResizeHandler = null;
|
|
29052
|
+
this.sdtHover.destroy();
|
|
28656
29053
|
this.layoutVersion = 0;
|
|
28657
29054
|
this.processedLayoutVersion = -1;
|
|
28658
29055
|
}
|
|
@@ -28714,7 +29111,9 @@ class DomPainter {
|
|
|
28714
29111
|
if (current) {
|
|
28715
29112
|
existing.delete(key2);
|
|
28716
29113
|
const sdtBoundaryMismatch = shouldRebuildForSdtBoundary(current.element, sdtBoundary);
|
|
28717
|
-
const
|
|
29114
|
+
const newPmStart = fragment.pmStart;
|
|
29115
|
+
const mappingUnreliable = this.currentMapping != null && newPmStart != null && current.element.dataset.pmStart != null && this.currentMapping.map(Number(current.element.dataset.pmStart)) !== newPmStart;
|
|
29116
|
+
const needsRebuild = this.changedBlocks.has(fragment.blockId) || current.signature !== fragmentSignature(fragment, this.blockLookup) || sdtBoundaryMismatch || mappingUnreliable;
|
|
28718
29117
|
if (needsRebuild) {
|
|
28719
29118
|
const replacement = this.renderFragment(fragment, contextBase, sdtBoundary);
|
|
28720
29119
|
pageEl.replaceChild(replacement, current.element);
|
|
@@ -30800,6 +31199,43 @@ class DomPainter {
|
|
|
30800
31199
|
}
|
|
30801
31200
|
return void 0;
|
|
30802
31201
|
};
|
|
31202
|
+
let geoSdtWrapper = null;
|
|
31203
|
+
let geoSdtId = null;
|
|
31204
|
+
let geoSdtWrapperLeft = 0;
|
|
31205
|
+
let geoSdtMaxRight = 0;
|
|
31206
|
+
const closeGeoSdtWrapper = () => {
|
|
31207
|
+
if (geoSdtWrapper) {
|
|
31208
|
+
geoSdtWrapper.style.width = `${geoSdtMaxRight - geoSdtWrapperLeft}px`;
|
|
31209
|
+
el.appendChild(geoSdtWrapper);
|
|
31210
|
+
geoSdtWrapper = null;
|
|
31211
|
+
geoSdtId = null;
|
|
31212
|
+
}
|
|
31213
|
+
};
|
|
31214
|
+
const appendToLineGeo = (elem, runForSdt, elemLeftPx, elemWidthPx) => {
|
|
31215
|
+
const resolved = this.resolveRunSdtId(runForSdt);
|
|
31216
|
+
const thisRunSdtId = resolved?.sdtId ?? null;
|
|
31217
|
+
if (thisRunSdtId !== geoSdtId) {
|
|
31218
|
+
closeGeoSdtWrapper();
|
|
31219
|
+
}
|
|
31220
|
+
if (resolved && this.doc) {
|
|
31221
|
+
if (!geoSdtWrapper) {
|
|
31222
|
+
geoSdtWrapper = this.createInlineSdtWrapper(resolved.sdt);
|
|
31223
|
+
geoSdtId = thisRunSdtId;
|
|
31224
|
+
geoSdtWrapperLeft = elemLeftPx;
|
|
31225
|
+
geoSdtMaxRight = elemLeftPx;
|
|
31226
|
+
geoSdtWrapper.style.position = "absolute";
|
|
31227
|
+
geoSdtWrapper.style.left = `${elemLeftPx}px`;
|
|
31228
|
+
geoSdtWrapper.style.top = "0px";
|
|
31229
|
+
geoSdtWrapper.style.height = `${line.lineHeight}px`;
|
|
31230
|
+
}
|
|
31231
|
+
elem.style.left = `${elemLeftPx - geoSdtWrapperLeft}px`;
|
|
31232
|
+
geoSdtMaxRight = Math.max(geoSdtMaxRight, elemLeftPx + elemWidthPx);
|
|
31233
|
+
this.expandSdtWrapperPmRange(geoSdtWrapper, runForSdt.pmStart, runForSdt.pmEnd);
|
|
31234
|
+
geoSdtWrapper.appendChild(elem);
|
|
31235
|
+
} else {
|
|
31236
|
+
el.appendChild(elem);
|
|
31237
|
+
}
|
|
31238
|
+
};
|
|
30803
31239
|
for (let runIndex = line.fromRun; runIndex <= line.toRun; runIndex += 1) {
|
|
30804
31240
|
const baseRun = block.runs[runIndex];
|
|
30805
31241
|
if (!baseRun) continue;
|
|
@@ -30831,7 +31267,7 @@ class DomPainter {
|
|
|
30831
31267
|
if (baseRun.pmStart != null) tabEl.dataset.pmStart = String(baseRun.pmStart);
|
|
30832
31268
|
if (baseRun.pmEnd != null) tabEl.dataset.pmEnd = String(baseRun.pmEnd);
|
|
30833
31269
|
tabEl.dataset.layoutEpoch = String(this.layoutEpoch);
|
|
30834
|
-
|
|
31270
|
+
appendToLineGeo(tabEl, baseRun, tabStartX + indentOffset, actualTabWidth);
|
|
30835
31271
|
cumulativeX = tabEndX;
|
|
30836
31272
|
continue;
|
|
30837
31273
|
}
|
|
@@ -30847,7 +31283,7 @@ class DomPainter {
|
|
|
30847
31283
|
const segWidth = (runSegments2 && runSegments2[0]?.width !== void 0 ? runSegments2[0].width : elem.offsetWidth) ?? 0;
|
|
30848
31284
|
elem.style.position = "absolute";
|
|
30849
31285
|
elem.style.left = `${segX}px`;
|
|
30850
|
-
|
|
31286
|
+
appendToLineGeo(elem, baseRun, segX, segWidth);
|
|
30851
31287
|
cumulativeX = baseSegX + segWidth;
|
|
30852
31288
|
}
|
|
30853
31289
|
continue;
|
|
@@ -30870,7 +31306,7 @@ class DomPainter {
|
|
|
30870
31306
|
const segWidth = (runSegments2 && runSegments2[0]?.width !== void 0 ? runSegments2[0].width : 0) ?? 0;
|
|
30871
31307
|
elem.style.position = "absolute";
|
|
30872
31308
|
elem.style.left = `${segX}px`;
|
|
30873
|
-
|
|
31309
|
+
appendToLineGeo(elem, baseRun, segX, segWidth);
|
|
30874
31310
|
cumulativeX = baseSegX + segWidth;
|
|
30875
31311
|
}
|
|
30876
31312
|
continue;
|
|
@@ -30905,7 +31341,7 @@ class DomPainter {
|
|
|
30905
31341
|
const xPos = baseX + indentOffset;
|
|
30906
31342
|
elem.style.position = "absolute";
|
|
30907
31343
|
elem.style.left = `${xPos}px`;
|
|
30908
|
-
|
|
31344
|
+
appendToLineGeo(elem, segmentRun, xPos, segment.width ?? 0);
|
|
30909
31345
|
let width = segment.width ?? 0;
|
|
30910
31346
|
if (width <= 0 && this.doc) {
|
|
30911
31347
|
const measureEl = elem.cloneNode(true);
|
|
@@ -30917,9 +31353,13 @@ class DomPainter {
|
|
|
30917
31353
|
this.doc.body.removeChild(measureEl);
|
|
30918
31354
|
}
|
|
30919
31355
|
cumulativeX = baseX + width;
|
|
31356
|
+
if (geoSdtWrapper) {
|
|
31357
|
+
geoSdtMaxRight = Math.max(geoSdtMaxRight, xPos + width);
|
|
31358
|
+
}
|
|
30920
31359
|
}
|
|
30921
31360
|
});
|
|
30922
31361
|
}
|
|
31362
|
+
closeGeoSdtWrapper();
|
|
30923
31363
|
} else {
|
|
30924
31364
|
let currentInlineSdtWrapper = null;
|
|
30925
31365
|
let currentInlineSdtId = null;
|
|
@@ -30931,12 +31371,12 @@ class DomPainter {
|
|
|
30931
31371
|
}
|
|
30932
31372
|
};
|
|
30933
31373
|
runsForLine.forEach((run) => {
|
|
30934
|
-
const
|
|
30935
|
-
const
|
|
30936
|
-
const runSdtId = isInlineSdt && runSdt?.id ? String(runSdt.id) : null;
|
|
31374
|
+
const resolved = this.resolveRunSdtId(run);
|
|
31375
|
+
const runSdtId = resolved?.sdtId ?? null;
|
|
30937
31376
|
if (runSdtId !== currentInlineSdtId) {
|
|
30938
31377
|
closeCurrentWrapper();
|
|
30939
31378
|
}
|
|
31379
|
+
let elem = null;
|
|
30940
31380
|
if (run.kind === "tab") {
|
|
30941
31381
|
const tabEl = this.doc.createElement("span");
|
|
30942
31382
|
tabEl.classList.add("superdoc-tab");
|
|
@@ -30957,39 +31397,20 @@ class DomPainter {
|
|
|
30957
31397
|
if (run.pmStart != null) tabEl.dataset.pmStart = String(run.pmStart);
|
|
30958
31398
|
if (run.pmEnd != null) tabEl.dataset.pmEnd = String(run.pmEnd);
|
|
30959
31399
|
tabEl.dataset.layoutEpoch = String(this.layoutEpoch);
|
|
30960
|
-
|
|
30961
|
-
|
|
31400
|
+
elem = tabEl;
|
|
31401
|
+
} else {
|
|
31402
|
+
elem = this.renderRun(run, context, trackedConfig);
|
|
30962
31403
|
}
|
|
30963
|
-
const elem = this.renderRun(run, context, trackedConfig);
|
|
30964
31404
|
if (elem) {
|
|
30965
31405
|
if (styleId) {
|
|
30966
31406
|
elem.setAttribute("styleid", styleId);
|
|
30967
31407
|
}
|
|
30968
|
-
if (
|
|
31408
|
+
if (resolved && this.doc) {
|
|
30969
31409
|
if (!currentInlineSdtWrapper) {
|
|
30970
|
-
currentInlineSdtWrapper = this.
|
|
30971
|
-
currentInlineSdtWrapper.className = DOM_CLASS_NAMES.INLINE_SDT_WRAPPER;
|
|
30972
|
-
currentInlineSdtWrapper.dataset.layoutEpoch = String(this.layoutEpoch);
|
|
31410
|
+
currentInlineSdtWrapper = this.createInlineSdtWrapper(resolved.sdt);
|
|
30973
31411
|
currentInlineSdtId = runSdtId;
|
|
30974
|
-
this.applySdtDataset(currentInlineSdtWrapper, runSdt);
|
|
30975
|
-
const alias = runSdt?.alias || "Inline content";
|
|
30976
|
-
const labelEl = this.doc.createElement("span");
|
|
30977
|
-
labelEl.className = `${DOM_CLASS_NAMES.INLINE_SDT_WRAPPER}__label`;
|
|
30978
|
-
labelEl.textContent = alias;
|
|
30979
|
-
currentInlineSdtWrapper.appendChild(labelEl);
|
|
30980
|
-
}
|
|
30981
|
-
const wrapperPmStart = currentInlineSdtWrapper.dataset.pmStart;
|
|
30982
|
-
const wrapperPmEnd = currentInlineSdtWrapper.dataset.pmEnd;
|
|
30983
|
-
if (run.pmStart != null) {
|
|
30984
|
-
if (!wrapperPmStart || run.pmStart < parseInt(wrapperPmStart, 10)) {
|
|
30985
|
-
currentInlineSdtWrapper.dataset.pmStart = String(run.pmStart);
|
|
30986
|
-
}
|
|
30987
|
-
}
|
|
30988
|
-
if (run.pmEnd != null) {
|
|
30989
|
-
if (!wrapperPmEnd || run.pmEnd > parseInt(wrapperPmEnd, 10)) {
|
|
30990
|
-
currentInlineSdtWrapper.dataset.pmEnd = String(run.pmEnd);
|
|
30991
|
-
}
|
|
30992
31412
|
}
|
|
31413
|
+
this.expandSdtWrapperPmRange(currentInlineSdtWrapper, run.pmStart, run.pmEnd);
|
|
30993
31414
|
currentInlineSdtWrapper.appendChild(elem);
|
|
30994
31415
|
} else {
|
|
30995
31416
|
el.appendChild(elem);
|
|
@@ -31166,6 +31587,7 @@ class DomPainter {
|
|
|
31166
31587
|
"sdtScope",
|
|
31167
31588
|
"sdtTag",
|
|
31168
31589
|
"sdtAlias",
|
|
31590
|
+
"lockMode",
|
|
31169
31591
|
"sdtSectionTitle",
|
|
31170
31592
|
"sdtSectionType",
|
|
31171
31593
|
"sdtSectionLocked",
|
|
@@ -31190,6 +31612,49 @@ class DomPainter {
|
|
|
31190
31612
|
el.dataset[key2] = String(value);
|
|
31191
31613
|
}
|
|
31192
31614
|
}
|
|
31615
|
+
/**
|
|
31616
|
+
* Resolve the inline SDT id from a run, or null if the run is not inside an inline SDT.
|
|
31617
|
+
*/
|
|
31618
|
+
resolveRunSdtId(run) {
|
|
31619
|
+
const sdt = run.sdt;
|
|
31620
|
+
if (sdt?.type === "structuredContent" && sdt?.scope === "inline" && sdt?.id) {
|
|
31621
|
+
return { sdtId: String(sdt.id), sdt };
|
|
31622
|
+
}
|
|
31623
|
+
return null;
|
|
31624
|
+
}
|
|
31625
|
+
/**
|
|
31626
|
+
* Create an inline SDT wrapper `<span>` with className, layoutEpoch, dataset, and label.
|
|
31627
|
+
* Shared by both the geometry and run-based rendering paths.
|
|
31628
|
+
*/
|
|
31629
|
+
createInlineSdtWrapper(sdt) {
|
|
31630
|
+
const wrapper = this.doc.createElement("span");
|
|
31631
|
+
wrapper.className = DOM_CLASS_NAMES.INLINE_SDT_WRAPPER;
|
|
31632
|
+
wrapper.dataset.layoutEpoch = String(this.layoutEpoch);
|
|
31633
|
+
this.applySdtDataset(wrapper, sdt);
|
|
31634
|
+
const alias = sdt?.alias || "Inline content";
|
|
31635
|
+
const labelEl = this.doc.createElement("span");
|
|
31636
|
+
labelEl.className = `${DOM_CLASS_NAMES.INLINE_SDT_WRAPPER}__label`;
|
|
31637
|
+
labelEl.textContent = alias;
|
|
31638
|
+
wrapper.appendChild(labelEl);
|
|
31639
|
+
return wrapper;
|
|
31640
|
+
}
|
|
31641
|
+
/**
|
|
31642
|
+
* Expand the PM position range tracked on an SDT wrapper to include a new run's range.
|
|
31643
|
+
*/
|
|
31644
|
+
expandSdtWrapperPmRange(wrapper, pmStart, pmEnd) {
|
|
31645
|
+
if (pmStart != null) {
|
|
31646
|
+
const cur = wrapper.dataset.pmStart;
|
|
31647
|
+
if (!cur || pmStart < parseInt(cur, 10)) {
|
|
31648
|
+
wrapper.dataset.pmStart = String(pmStart);
|
|
31649
|
+
}
|
|
31650
|
+
}
|
|
31651
|
+
if (pmEnd != null) {
|
|
31652
|
+
const cur = wrapper.dataset.pmEnd;
|
|
31653
|
+
if (!cur || pmEnd > parseInt(cur, 10)) {
|
|
31654
|
+
wrapper.dataset.pmEnd = String(pmEnd);
|
|
31655
|
+
}
|
|
31656
|
+
}
|
|
31657
|
+
}
|
|
31193
31658
|
/**
|
|
31194
31659
|
* Applies SDT (Structured Document Tag) metadata to an element's dataset as data-sdt-* attributes.
|
|
31195
31660
|
* Supports field annotations, structured content, document sections, and doc parts.
|
|
@@ -31217,6 +31682,7 @@ class DomPainter {
|
|
|
31217
31682
|
this.setDatasetString(el, "sdtScope", metadata.scope);
|
|
31218
31683
|
this.setDatasetString(el, "sdtTag", metadata.tag);
|
|
31219
31684
|
this.setDatasetString(el, "sdtAlias", metadata.alias);
|
|
31685
|
+
this.setDatasetString(el, "lockMode", metadata.lockMode || "unlocked");
|
|
31220
31686
|
} else if (metadata.type === "documentSection") {
|
|
31221
31687
|
this.setDatasetString(el, "sdtSectionTitle", metadata.title);
|
|
31222
31688
|
this.setDatasetString(el, "sdtSectionType", metadata.sectionType);
|
|
@@ -31305,17 +31771,6 @@ const computeSdtBoundaries = (fragments, blockLookup) => {
|
|
|
31305
31771
|
}
|
|
31306
31772
|
return boundaries;
|
|
31307
31773
|
};
|
|
31308
|
-
const shouldRebuildForSdtBoundary = (element, boundary) => {
|
|
31309
|
-
if (!boundary) return false;
|
|
31310
|
-
const startAttr = element.dataset.sdtContainerStart;
|
|
31311
|
-
const endAttr = element.dataset.sdtContainerEnd;
|
|
31312
|
-
const expectedStart = String(boundary.isStart ?? true);
|
|
31313
|
-
const expectedEnd = String(boundary.isEnd ?? true);
|
|
31314
|
-
if (startAttr === void 0 || endAttr === void 0) {
|
|
31315
|
-
return true;
|
|
31316
|
-
}
|
|
31317
|
-
return startAttr !== expectedStart || endAttr !== expectedEnd;
|
|
31318
|
-
};
|
|
31319
31774
|
const fragmentKey = (fragment) => {
|
|
31320
31775
|
if (fragment.kind === "para") {
|
|
31321
31776
|
return `para:${fragment.blockId}:${fragment.fromLine}:${fragment.toLine}`;
|
|
@@ -40760,6 +41215,7 @@ function normalizeStructuredContentMetadata(nodeType, attrs) {
|
|
|
40760
41215
|
id: toNullableString(attrs.id),
|
|
40761
41216
|
tag: toOptionalString(attrs.tag),
|
|
40762
41217
|
alias: toOptionalString(attrs.alias),
|
|
41218
|
+
lockMode: attrs.lockMode,
|
|
40763
41219
|
sdtPr: attrs.sdtPr
|
|
40764
41220
|
};
|
|
40765
41221
|
}
|
|
@@ -41584,7 +42040,8 @@ function tabNodeToRun({
|
|
|
41584
42040
|
positions,
|
|
41585
42041
|
tabOrdinal,
|
|
41586
42042
|
paragraphAttrs,
|
|
41587
|
-
inheritedMarks
|
|
42043
|
+
inheritedMarks,
|
|
42044
|
+
sdtMetadata
|
|
41588
42045
|
}) {
|
|
41589
42046
|
const pos = positions.get(node);
|
|
41590
42047
|
if (!pos) return null;
|
|
@@ -41600,6 +42057,9 @@ function tabNodeToRun({
|
|
|
41600
42057
|
indent,
|
|
41601
42058
|
leader: node.attrs?.leader ?? null
|
|
41602
42059
|
};
|
|
42060
|
+
if (sdtMetadata) {
|
|
42061
|
+
run.sdt = sdtMetadata;
|
|
42062
|
+
}
|
|
41603
42063
|
const marks = [...node.marks ?? [], ...inheritedMarks ?? []];
|
|
41604
42064
|
if (marks.length > 0) {
|
|
41605
42065
|
applyMarksToRun(run, marks);
|
|
@@ -64184,7 +64644,8 @@ class PresentationEditor extends EventEmitter {
|
|
|
64184
64644
|
}
|
|
64185
64645
|
const activeEditor = this.getActiveEditor();
|
|
64186
64646
|
const hasFocus = activeEditor?.view?.hasFocus?.() ?? false;
|
|
64187
|
-
|
|
64647
|
+
const slashMenuOpen = activeEditor?.state ? !!SlashMenuPluginKey.getState(activeEditor.state)?.open : false;
|
|
64648
|
+
if (!hasFocus && !slashMenuOpen) {
|
|
64188
64649
|
try {
|
|
64189
64650
|
this.#clearSelectedFieldAnnotationClass();
|
|
64190
64651
|
this.#localSelectionLayer.innerHTML = "";
|
|
@@ -66421,300 +66882,6 @@ const processAiHighlights = (editor, doc2, highlightColor, customClass = null) =
|
|
|
66421
66882
|
});
|
|
66422
66883
|
return { decorations };
|
|
66423
66884
|
};
|
|
66424
|
-
function getEditorSurfaceElement(editor) {
|
|
66425
|
-
if (!editor) return null;
|
|
66426
|
-
if (typeof editor.hitTest === "function" && editor.element instanceof HTMLElement) {
|
|
66427
|
-
return editor.element;
|
|
66428
|
-
}
|
|
66429
|
-
return editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element ?? null;
|
|
66430
|
-
}
|
|
66431
|
-
function getSurfaceRelativePoint(editor, eventLocation = {}) {
|
|
66432
|
-
const surface = getEditorSurfaceElement(editor);
|
|
66433
|
-
if (!surface) return null;
|
|
66434
|
-
const rect = surface.getBoundingClientRect();
|
|
66435
|
-
let left2;
|
|
66436
|
-
let top2;
|
|
66437
|
-
if (typeof eventLocation.clientX === "number" && typeof eventLocation.clientY === "number") {
|
|
66438
|
-
left2 = eventLocation.clientX - rect.left;
|
|
66439
|
-
top2 = eventLocation.clientY - rect.top;
|
|
66440
|
-
} else if (editor?.state?.selection) {
|
|
66441
|
-
const selectionFrom = editor.state.selection.from;
|
|
66442
|
-
const coords = editor.coordsAtPos?.(selectionFrom);
|
|
66443
|
-
if (coords) {
|
|
66444
|
-
left2 = coords.left - rect.left;
|
|
66445
|
-
top2 = coords.top - rect.top;
|
|
66446
|
-
}
|
|
66447
|
-
}
|
|
66448
|
-
if (!Number.isFinite(left2) || !Number.isFinite(top2)) {
|
|
66449
|
-
return null;
|
|
66450
|
-
}
|
|
66451
|
-
return { left: left2, top: top2 };
|
|
66452
|
-
}
|
|
66453
|
-
function findContainingBlockAncestor(element) {
|
|
66454
|
-
if (!element) return null;
|
|
66455
|
-
let current = element.parentElement;
|
|
66456
|
-
while (current && current !== document.body && current !== document.documentElement) {
|
|
66457
|
-
try {
|
|
66458
|
-
const style2 = window.getComputedStyle(current);
|
|
66459
|
-
const transform = style2.transform;
|
|
66460
|
-
const filter = style2.filter;
|
|
66461
|
-
const backdropFilter = style2.backdropFilter || style2.webkitBackdropFilter;
|
|
66462
|
-
const perspective = style2.perspective;
|
|
66463
|
-
const willChange = style2.willChange;
|
|
66464
|
-
const contain = style2.contain;
|
|
66465
|
-
if (transform && transform !== "none") {
|
|
66466
|
-
return current;
|
|
66467
|
-
}
|
|
66468
|
-
if (filter && filter !== "none") {
|
|
66469
|
-
return current;
|
|
66470
|
-
}
|
|
66471
|
-
if (backdropFilter && backdropFilter !== "none") {
|
|
66472
|
-
return current;
|
|
66473
|
-
}
|
|
66474
|
-
if (perspective && perspective !== "none") {
|
|
66475
|
-
return current;
|
|
66476
|
-
}
|
|
66477
|
-
if (willChange && willChange !== "auto") {
|
|
66478
|
-
const values = willChange.split(",").map((v) => v.trim());
|
|
66479
|
-
if (values.includes("transform") || values.includes("perspective")) {
|
|
66480
|
-
return current;
|
|
66481
|
-
}
|
|
66482
|
-
}
|
|
66483
|
-
if (contain && /paint|layout|strict|content/.test(contain)) {
|
|
66484
|
-
return current;
|
|
66485
|
-
}
|
|
66486
|
-
} catch (error) {
|
|
66487
|
-
console.warn("SlashMenu: Failed to get computed style for element", current, error);
|
|
66488
|
-
}
|
|
66489
|
-
current = current.parentElement;
|
|
66490
|
-
}
|
|
66491
|
-
return null;
|
|
66492
|
-
}
|
|
66493
|
-
const SlashMenuPluginKey = new PluginKey("slashMenu");
|
|
66494
|
-
const MENU_OFFSET_X = 100;
|
|
66495
|
-
const MENU_OFFSET_Y = 28;
|
|
66496
|
-
const CONTEXT_MENU_OFFSET_X = 10;
|
|
66497
|
-
const CONTEXT_MENU_OFFSET_Y = 10;
|
|
66498
|
-
const SLASH_COOLDOWN_MS = 5e3;
|
|
66499
|
-
const SlashMenu = Extension.create({
|
|
66500
|
-
name: "slashMenu",
|
|
66501
|
-
/**
|
|
66502
|
-
* Initialize default options for the SlashMenu extension
|
|
66503
|
-
* @returns {SlashMenuOptions} Empty options object (configuration is inherited from editor options)
|
|
66504
|
-
*/
|
|
66505
|
-
addOptions() {
|
|
66506
|
-
return {};
|
|
66507
|
-
},
|
|
66508
|
-
addPmPlugins() {
|
|
66509
|
-
const editor = this.editor;
|
|
66510
|
-
if (editor.options?.isHeadless) {
|
|
66511
|
-
return [];
|
|
66512
|
-
}
|
|
66513
|
-
let slashCooldown = false;
|
|
66514
|
-
let slashCooldownTimeout = null;
|
|
66515
|
-
const isMenuDisabled = () => Boolean(editor.options?.disableContextMenu);
|
|
66516
|
-
const ensureStateShape = (value = {}) => ({
|
|
66517
|
-
open: false,
|
|
66518
|
-
selected: null,
|
|
66519
|
-
anchorPos: null,
|
|
66520
|
-
menuPosition: null,
|
|
66521
|
-
disabled: isMenuDisabled(),
|
|
66522
|
-
...value
|
|
66523
|
-
});
|
|
66524
|
-
const slashMenuPlugin = new Plugin({
|
|
66525
|
-
key: SlashMenuPluginKey,
|
|
66526
|
-
state: {
|
|
66527
|
-
init: () => ensureStateShape(),
|
|
66528
|
-
/**
|
|
66529
|
-
* Apply transaction to update plugin state
|
|
66530
|
-
* Handles state transitions based on transaction metadata:
|
|
66531
|
-
* - 'open': Opens menu at specified position or cursor location
|
|
66532
|
-
* - 'select': Updates the selected menu item
|
|
66533
|
-
* - 'close': Closes the menu and clears anchor position
|
|
66534
|
-
* - 'updatePosition': Triggers menu position recalculation (no-op in apply)
|
|
66535
|
-
*
|
|
66536
|
-
* @param {import('prosemirror-state').Transaction} tr - The transaction
|
|
66537
|
-
* @param {SlashMenuState} value - Previous plugin state
|
|
66538
|
-
* @returns {SlashMenuState} New plugin state
|
|
66539
|
-
*/
|
|
66540
|
-
apply(tr, value) {
|
|
66541
|
-
const meta = tr.getMeta(SlashMenuPluginKey);
|
|
66542
|
-
const disabled = isMenuDisabled();
|
|
66543
|
-
if (disabled) {
|
|
66544
|
-
if (value.open) {
|
|
66545
|
-
editor.emit("slashMenu:close");
|
|
66546
|
-
}
|
|
66547
|
-
return ensureStateShape({ disabled: true });
|
|
66548
|
-
}
|
|
66549
|
-
if (!meta) {
|
|
66550
|
-
if (value.disabled !== disabled) {
|
|
66551
|
-
return ensureStateShape({ ...value, disabled });
|
|
66552
|
-
}
|
|
66553
|
-
return value;
|
|
66554
|
-
}
|
|
66555
|
-
switch (meta.type) {
|
|
66556
|
-
case "open": {
|
|
66557
|
-
if (typeof meta.pos !== "number" || meta.pos < 0 || meta.pos > tr.doc.content.size) {
|
|
66558
|
-
console.warn("SlashMenu: Invalid position", meta.pos);
|
|
66559
|
-
return ensureStateShape(value);
|
|
66560
|
-
}
|
|
66561
|
-
let left2 = 0;
|
|
66562
|
-
let top2 = 0;
|
|
66563
|
-
let isContextMenu = false;
|
|
66564
|
-
if (typeof meta.clientX === "number" && typeof meta.clientY === "number") {
|
|
66565
|
-
left2 = meta.clientX;
|
|
66566
|
-
top2 = meta.clientY;
|
|
66567
|
-
isContextMenu = true;
|
|
66568
|
-
} else {
|
|
66569
|
-
const relativePoint = getSurfaceRelativePoint(editor, meta);
|
|
66570
|
-
if (relativePoint) {
|
|
66571
|
-
const surface = editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element;
|
|
66572
|
-
if (surface) {
|
|
66573
|
-
try {
|
|
66574
|
-
const rect = surface.getBoundingClientRect();
|
|
66575
|
-
left2 = rect.left + relativePoint.left;
|
|
66576
|
-
top2 = rect.top + relativePoint.top;
|
|
66577
|
-
} catch (error) {
|
|
66578
|
-
console.warn("SlashMenu: Failed to get surface bounds", error);
|
|
66579
|
-
return ensureStateShape(value);
|
|
66580
|
-
}
|
|
66581
|
-
}
|
|
66582
|
-
}
|
|
66583
|
-
}
|
|
66584
|
-
const menuSurface = editor.presentationEditor?.element ?? editor.view?.dom ?? editor.options?.element;
|
|
66585
|
-
const containingBlock = findContainingBlockAncestor(menuSurface);
|
|
66586
|
-
if (containingBlock) {
|
|
66587
|
-
try {
|
|
66588
|
-
const cbRect = containingBlock.getBoundingClientRect();
|
|
66589
|
-
left2 -= cbRect.left;
|
|
66590
|
-
top2 -= cbRect.top;
|
|
66591
|
-
left2 += containingBlock.scrollLeft || 0;
|
|
66592
|
-
top2 += containingBlock.scrollTop || 0;
|
|
66593
|
-
} catch (error) {
|
|
66594
|
-
console.warn("SlashMenu: Failed to adjust for containing block", error);
|
|
66595
|
-
}
|
|
66596
|
-
}
|
|
66597
|
-
const offsetX = isContextMenu ? CONTEXT_MENU_OFFSET_X : MENU_OFFSET_X;
|
|
66598
|
-
const offsetY = isContextMenu ? CONTEXT_MENU_OFFSET_Y : MENU_OFFSET_Y;
|
|
66599
|
-
const menuPosition = {
|
|
66600
|
-
left: `${left2 + offsetX}px`,
|
|
66601
|
-
top: `${top2 + offsetY}px`
|
|
66602
|
-
};
|
|
66603
|
-
const newState = {
|
|
66604
|
-
...value,
|
|
66605
|
-
open: true,
|
|
66606
|
-
anchorPos: meta.pos,
|
|
66607
|
-
menuPosition
|
|
66608
|
-
};
|
|
66609
|
-
editor.emit("slashMenu:open", { menuPosition });
|
|
66610
|
-
return ensureStateShape(newState);
|
|
66611
|
-
}
|
|
66612
|
-
case "select": {
|
|
66613
|
-
return ensureStateShape({ ...value, selected: meta.id });
|
|
66614
|
-
}
|
|
66615
|
-
case "close": {
|
|
66616
|
-
editor.emit("slashMenu:close");
|
|
66617
|
-
return ensureStateShape({ ...value, open: false, anchorPos: null });
|
|
66618
|
-
}
|
|
66619
|
-
default:
|
|
66620
|
-
return ensureStateShape({ ...value, disabled });
|
|
66621
|
-
}
|
|
66622
|
-
}
|
|
66623
|
-
},
|
|
66624
|
-
/**
|
|
66625
|
-
* Create view plugin to handle window event listeners
|
|
66626
|
-
* @param {import('prosemirror-view').EditorView} editorView - The ProseMirror editor view
|
|
66627
|
-
* @returns {Object} View plugin with destroy method
|
|
66628
|
-
*/
|
|
66629
|
-
view(editorView) {
|
|
66630
|
-
const updatePosition2 = () => {
|
|
66631
|
-
if (isMenuDisabled()) return;
|
|
66632
|
-
const state = SlashMenuPluginKey.getState(editorView.state);
|
|
66633
|
-
if (state.open) {
|
|
66634
|
-
editorView.dispatch(
|
|
66635
|
-
editorView.state.tr.setMeta(SlashMenuPluginKey, {
|
|
66636
|
-
type: "updatePosition"
|
|
66637
|
-
})
|
|
66638
|
-
);
|
|
66639
|
-
}
|
|
66640
|
-
};
|
|
66641
|
-
window.addEventListener("scroll", updatePosition2, true);
|
|
66642
|
-
window.addEventListener("resize", updatePosition2);
|
|
66643
|
-
return {
|
|
66644
|
-
destroy() {
|
|
66645
|
-
window.removeEventListener("scroll", updatePosition2, true);
|
|
66646
|
-
window.removeEventListener("resize", updatePosition2);
|
|
66647
|
-
if (slashCooldownTimeout) {
|
|
66648
|
-
clearTimeout(slashCooldownTimeout);
|
|
66649
|
-
slashCooldownTimeout = null;
|
|
66650
|
-
}
|
|
66651
|
-
}
|
|
66652
|
-
};
|
|
66653
|
-
},
|
|
66654
|
-
props: {
|
|
66655
|
-
/**
|
|
66656
|
-
* Handle keyboard events to open/close the slash menu
|
|
66657
|
-
* - '/': Opens menu at cursor if conditions are met (in paragraph, after space/start)
|
|
66658
|
-
* - 'Escape' or 'ArrowLeft': Closes menu and restores cursor position
|
|
66659
|
-
*
|
|
66660
|
-
* @param {import('prosemirror-view').EditorView} view - The ProseMirror editor view
|
|
66661
|
-
* @param {KeyboardEvent} event - The keyboard event
|
|
66662
|
-
* @returns {boolean} True if the event was handled, false otherwise
|
|
66663
|
-
*/
|
|
66664
|
-
handleKeyDown(view, event) {
|
|
66665
|
-
if (isMenuDisabled()) {
|
|
66666
|
-
return false;
|
|
66667
|
-
}
|
|
66668
|
-
const pluginState = this.getState(view.state);
|
|
66669
|
-
if (event.key === "/" && slashCooldown) {
|
|
66670
|
-
return false;
|
|
66671
|
-
}
|
|
66672
|
-
if (event.key === "/" && !pluginState.open) {
|
|
66673
|
-
const { $cursor } = view.state.selection;
|
|
66674
|
-
if (!$cursor) return false;
|
|
66675
|
-
const isParagraph = $cursor.parent.type.name === "paragraph";
|
|
66676
|
-
if (!isParagraph) return false;
|
|
66677
|
-
const textBefore = $cursor.parent.textContent.slice(0, $cursor.parentOffset);
|
|
66678
|
-
const isEmptyOrAfterSpace = !textBefore || textBefore.endsWith(" ");
|
|
66679
|
-
if (!isEmptyOrAfterSpace) return false;
|
|
66680
|
-
event.preventDefault();
|
|
66681
|
-
slashCooldown = true;
|
|
66682
|
-
if (slashCooldownTimeout) clearTimeout(slashCooldownTimeout);
|
|
66683
|
-
slashCooldownTimeout = setTimeout(() => {
|
|
66684
|
-
slashCooldown = false;
|
|
66685
|
-
slashCooldownTimeout = null;
|
|
66686
|
-
}, SLASH_COOLDOWN_MS);
|
|
66687
|
-
view.dispatch(
|
|
66688
|
-
view.state.tr.setMeta(SlashMenuPluginKey, {
|
|
66689
|
-
type: "open",
|
|
66690
|
-
pos: $cursor.pos
|
|
66691
|
-
})
|
|
66692
|
-
);
|
|
66693
|
-
return true;
|
|
66694
|
-
}
|
|
66695
|
-
if (pluginState.open && (event.key === "Escape" || event.key === "ArrowLeft")) {
|
|
66696
|
-
const { anchorPos } = pluginState;
|
|
66697
|
-
view.dispatch(
|
|
66698
|
-
view.state.tr.setMeta(SlashMenuPluginKey, {
|
|
66699
|
-
type: "close"
|
|
66700
|
-
})
|
|
66701
|
-
);
|
|
66702
|
-
if (anchorPos !== null) {
|
|
66703
|
-
const tr = view.state.tr.setSelection(
|
|
66704
|
-
view.state.selection.constructor.near(view.state.doc.resolve(anchorPos))
|
|
66705
|
-
);
|
|
66706
|
-
view.dispatch(tr);
|
|
66707
|
-
view.focus();
|
|
66708
|
-
}
|
|
66709
|
-
return true;
|
|
66710
|
-
}
|
|
66711
|
-
return false;
|
|
66712
|
-
}
|
|
66713
|
-
}
|
|
66714
|
-
});
|
|
66715
|
-
return [slashMenuPlugin];
|
|
66716
|
-
}
|
|
66717
|
-
});
|
|
66718
66885
|
class StructuredContentViewBase {
|
|
66719
66886
|
node;
|
|
66720
66887
|
view;
|
|
@@ -66854,6 +67021,20 @@ class StructuredContentViewBase {
|
|
|
66854
67021
|
dragHandle.append(textElement);
|
|
66855
67022
|
return dragHandle;
|
|
66856
67023
|
}
|
|
67024
|
+
isContentLocked() {
|
|
67025
|
+
const lockMode = this.node.attrs.lockMode;
|
|
67026
|
+
return lockMode === "contentLocked" || lockMode === "sdtContentLocked";
|
|
67027
|
+
}
|
|
67028
|
+
isSdtLocked() {
|
|
67029
|
+
const lockMode = this.node.attrs.lockMode;
|
|
67030
|
+
return lockMode === "sdtLocked" || lockMode === "sdtContentLocked";
|
|
67031
|
+
}
|
|
67032
|
+
updateContentEditability() {
|
|
67033
|
+
if (this.dom) {
|
|
67034
|
+
this.dom.classList.toggle("sd-structured-content--content-locked", this.isContentLocked());
|
|
67035
|
+
this.dom.classList.toggle("sd-structured-content--sdt-locked", this.isSdtLocked());
|
|
67036
|
+
}
|
|
67037
|
+
}
|
|
66857
67038
|
onDragStart(event) {
|
|
66858
67039
|
const { view } = this.editor;
|
|
66859
67040
|
const target = event.target;
|
|
@@ -66909,10 +67090,12 @@ class StructuredContentInlineView extends StructuredContentViewBase {
|
|
|
66909
67090
|
element.prepend(dragHandle);
|
|
66910
67091
|
element.addEventListener("dragstart", (e) => this.onDragStart(e));
|
|
66911
67092
|
this.root = element;
|
|
67093
|
+
this.updateContentEditability();
|
|
66912
67094
|
}
|
|
66913
67095
|
updateView() {
|
|
66914
67096
|
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
66915
67097
|
updateDOMAttributes(this.dom, { ...domAttrs });
|
|
67098
|
+
this.updateContentEditability();
|
|
66916
67099
|
}
|
|
66917
67100
|
update(node, decorations, innerDecorations) {
|
|
66918
67101
|
const result = super.update(node, decorations, innerDecorations);
|
|
@@ -66921,6 +67104,157 @@ class StructuredContentInlineView extends StructuredContentViewBase {
|
|
|
66921
67104
|
return true;
|
|
66922
67105
|
}
|
|
66923
67106
|
}
|
|
67107
|
+
const STRUCTURED_CONTENT_LOCK_KEY = new PluginKey("structuredContentLock");
|
|
67108
|
+
function collectSDTNodes(doc2) {
|
|
67109
|
+
const sdtNodes = [];
|
|
67110
|
+
doc2.descendants((node, pos) => {
|
|
67111
|
+
if (node.type.name === "structuredContent" || node.type.name === "structuredContentBlock") {
|
|
67112
|
+
sdtNodes.push({
|
|
67113
|
+
type: node.type.name,
|
|
67114
|
+
lockMode: node.attrs.lockMode,
|
|
67115
|
+
pos,
|
|
67116
|
+
end: pos + node.nodeSize
|
|
67117
|
+
});
|
|
67118
|
+
}
|
|
67119
|
+
});
|
|
67120
|
+
return sdtNodes;
|
|
67121
|
+
}
|
|
67122
|
+
function checkLockViolation(sdtNodes, from3, to) {
|
|
67123
|
+
for (const sdt of sdtNodes) {
|
|
67124
|
+
const overlaps = from3 < sdt.end && to > sdt.pos;
|
|
67125
|
+
if (!overlaps) continue;
|
|
67126
|
+
const containsSDT = from3 <= sdt.pos && to >= sdt.end;
|
|
67127
|
+
const insideSDT = from3 >= sdt.pos && to <= sdt.end;
|
|
67128
|
+
const crossesStart = from3 < sdt.pos && to > sdt.pos && to < sdt.end;
|
|
67129
|
+
const crossesEnd = from3 > sdt.pos && from3 < sdt.end && to > sdt.end;
|
|
67130
|
+
const wouldDamageWrapper = containsSDT || crossesStart || crossesEnd;
|
|
67131
|
+
const wouldModifyContent = insideSDT && !containsSDT;
|
|
67132
|
+
const isSdtLocked = sdt.lockMode === "sdtLocked" || sdt.lockMode === "sdtContentLocked";
|
|
67133
|
+
const isContentLocked = sdt.lockMode === "contentLocked" || sdt.lockMode === "sdtContentLocked";
|
|
67134
|
+
if (isSdtLocked && wouldDamageWrapper) {
|
|
67135
|
+
return { blocked: true, reason: `Cannot delete SDT wrapper (${sdt.lockMode})` };
|
|
67136
|
+
}
|
|
67137
|
+
if (isContentLocked && wouldModifyContent) {
|
|
67138
|
+
return { blocked: true, reason: `Cannot modify content (${sdt.lockMode})` };
|
|
67139
|
+
}
|
|
67140
|
+
}
|
|
67141
|
+
return { blocked: false };
|
|
67142
|
+
}
|
|
67143
|
+
function createStructuredContentLockPlugin() {
|
|
67144
|
+
return new Plugin({
|
|
67145
|
+
key: STRUCTURED_CONTENT_LOCK_KEY,
|
|
67146
|
+
state: {
|
|
67147
|
+
init(_2, editorState) {
|
|
67148
|
+
return collectSDTNodes(editorState.doc);
|
|
67149
|
+
},
|
|
67150
|
+
apply(tr, cachedSDTNodes, _oldState, newState) {
|
|
67151
|
+
if (!tr.docChanged) return cachedSDTNodes;
|
|
67152
|
+
return collectSDTNodes(newState.doc);
|
|
67153
|
+
}
|
|
67154
|
+
},
|
|
67155
|
+
props: {
|
|
67156
|
+
/**
|
|
67157
|
+
* Intercept key events BEFORE any transaction is created.
|
|
67158
|
+
* This prevents the browser selection from getting out of sync.
|
|
67159
|
+
*/
|
|
67160
|
+
handleKeyDown(view, event) {
|
|
67161
|
+
const { state } = view;
|
|
67162
|
+
const { selection } = state;
|
|
67163
|
+
const { from: from3, to } = selection;
|
|
67164
|
+
const isDelete = event.key === "Delete";
|
|
67165
|
+
const isBackspace = event.key === "Backspace";
|
|
67166
|
+
const isCut = (event.metaKey || event.ctrlKey) && event.key === "x";
|
|
67167
|
+
if (!isDelete && !isBackspace && !isCut) {
|
|
67168
|
+
return false;
|
|
67169
|
+
}
|
|
67170
|
+
const sdtNodes = STRUCTURED_CONTENT_LOCK_KEY.getState(state);
|
|
67171
|
+
if (sdtNodes.length === 0) {
|
|
67172
|
+
return false;
|
|
67173
|
+
}
|
|
67174
|
+
let affectedFrom = from3;
|
|
67175
|
+
let affectedTo = to;
|
|
67176
|
+
if (from3 === to) {
|
|
67177
|
+
if (isBackspace && from3 > 0) {
|
|
67178
|
+
affectedFrom = from3 - 1;
|
|
67179
|
+
} else if (isDelete && to < state.doc.content.size) {
|
|
67180
|
+
affectedTo = to + 1;
|
|
67181
|
+
}
|
|
67182
|
+
}
|
|
67183
|
+
const result = checkLockViolation(sdtNodes, affectedFrom, affectedTo);
|
|
67184
|
+
if (result.blocked) {
|
|
67185
|
+
event.preventDefault();
|
|
67186
|
+
return true;
|
|
67187
|
+
}
|
|
67188
|
+
return false;
|
|
67189
|
+
},
|
|
67190
|
+
/**
|
|
67191
|
+
* Handle text input (typing) for content-locked nodes
|
|
67192
|
+
*/
|
|
67193
|
+
handleTextInput(view, from3, to, _text) {
|
|
67194
|
+
const sdtNodes = STRUCTURED_CONTENT_LOCK_KEY.getState(view.state);
|
|
67195
|
+
if (sdtNodes.length === 0) {
|
|
67196
|
+
return false;
|
|
67197
|
+
}
|
|
67198
|
+
const result = checkLockViolation(sdtNodes, from3, to);
|
|
67199
|
+
if (result.blocked) {
|
|
67200
|
+
return true;
|
|
67201
|
+
}
|
|
67202
|
+
return false;
|
|
67203
|
+
}
|
|
67204
|
+
},
|
|
67205
|
+
/**
|
|
67206
|
+
* Safety net: filter transactions that slip through
|
|
67207
|
+
* (e.g., programmatic changes, paste, drag-drop)
|
|
67208
|
+
*/
|
|
67209
|
+
filterTransaction(tr, state) {
|
|
67210
|
+
if (!tr.docChanged) {
|
|
67211
|
+
return true;
|
|
67212
|
+
}
|
|
67213
|
+
const sdtNodes = STRUCTURED_CONTENT_LOCK_KEY.getState(state);
|
|
67214
|
+
if (sdtNodes.length === 0) {
|
|
67215
|
+
return true;
|
|
67216
|
+
}
|
|
67217
|
+
for (const step of tr.steps) {
|
|
67218
|
+
if (step.from === void 0 || step.to === void 0) {
|
|
67219
|
+
continue;
|
|
67220
|
+
}
|
|
67221
|
+
const result = checkLockViolation(sdtNodes, step.from, step.to);
|
|
67222
|
+
if (result.blocked) {
|
|
67223
|
+
return false;
|
|
67224
|
+
}
|
|
67225
|
+
}
|
|
67226
|
+
return true;
|
|
67227
|
+
}
|
|
67228
|
+
});
|
|
67229
|
+
}
|
|
67230
|
+
function createStructuredContentSelectPlugin() {
|
|
67231
|
+
return new Plugin({
|
|
67232
|
+
appendTransaction(transactions, oldState, newState) {
|
|
67233
|
+
const { selection } = newState;
|
|
67234
|
+
if (!selection.empty) return null;
|
|
67235
|
+
if (oldState.selection.eq(newState.selection)) return null;
|
|
67236
|
+
if (transactions.some((tr) => tr.docChanged)) return null;
|
|
67237
|
+
const $pos = selection.$from;
|
|
67238
|
+
for (let d = $pos.depth; d > 0; d--) {
|
|
67239
|
+
const node = $pos.node(d);
|
|
67240
|
+
if (node.type.name === "structuredContent") {
|
|
67241
|
+
const sdtStart = $pos.before(d);
|
|
67242
|
+
const contentFrom = $pos.start(d);
|
|
67243
|
+
const contentTo = $pos.end(d);
|
|
67244
|
+
if (contentFrom === contentTo) return null;
|
|
67245
|
+
const old$pos = oldState.selection.$from;
|
|
67246
|
+
for (let od = old$pos.depth; od > 0; od--) {
|
|
67247
|
+
if (old$pos.node(od).type.name === "structuredContent" && old$pos.before(od) === sdtStart) {
|
|
67248
|
+
return null;
|
|
67249
|
+
}
|
|
67250
|
+
}
|
|
67251
|
+
return newState.tr.setSelection(TextSelection$1.create(newState.doc, contentFrom, contentTo));
|
|
67252
|
+
}
|
|
67253
|
+
}
|
|
67254
|
+
return null;
|
|
67255
|
+
}
|
|
67256
|
+
});
|
|
67257
|
+
}
|
|
66924
67258
|
const structuredContentClass = "sd-structured-content";
|
|
66925
67259
|
const structuredContentInnerClass = "sd-structured-content__content";
|
|
66926
67260
|
const StructuredContent = Node$1.create({
|
|
@@ -66966,6 +67300,14 @@ const StructuredContent = Node$1.create({
|
|
|
66966
67300
|
return { "data-alias": attrs.alias };
|
|
66967
67301
|
}
|
|
66968
67302
|
},
|
|
67303
|
+
lockMode: {
|
|
67304
|
+
default: "unlocked",
|
|
67305
|
+
parseDOM: (elem) => elem.getAttribute("data-lock-mode") || "unlocked",
|
|
67306
|
+
renderDOM: (attrs) => {
|
|
67307
|
+
if (!attrs.lockMode || attrs.lockMode === "unlocked") return {};
|
|
67308
|
+
return { "data-lock-mode": attrs.lockMode };
|
|
67309
|
+
}
|
|
67310
|
+
},
|
|
66969
67311
|
sdtPr: {
|
|
66970
67312
|
rendered: false
|
|
66971
67313
|
}
|
|
@@ -66983,6 +67325,9 @@ const StructuredContent = Node$1.create({
|
|
|
66983
67325
|
0
|
|
66984
67326
|
];
|
|
66985
67327
|
},
|
|
67328
|
+
addPmPlugins() {
|
|
67329
|
+
return [createStructuredContentLockPlugin(), createStructuredContentSelectPlugin()];
|
|
67330
|
+
},
|
|
66986
67331
|
addNodeView() {
|
|
66987
67332
|
return (props) => {
|
|
66988
67333
|
return new StructuredContentInlineView({ ...props });
|
|
@@ -67017,10 +67362,12 @@ class StructuredContentBlockView extends StructuredContentViewBase {
|
|
|
67017
67362
|
element.prepend(dragHandle);
|
|
67018
67363
|
element.addEventListener("dragstart", (e) => this.onDragStart(e));
|
|
67019
67364
|
this.root = element;
|
|
67365
|
+
this.updateContentEditability();
|
|
67020
67366
|
}
|
|
67021
67367
|
updateView() {
|
|
67022
67368
|
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
67023
67369
|
updateDOMAttributes(this.dom, { ...domAttrs });
|
|
67370
|
+
this.updateContentEditability();
|
|
67024
67371
|
}
|
|
67025
67372
|
update(node, decorations, innerDecorations) {
|
|
67026
67373
|
const result = super.update(node, decorations, innerDecorations);
|
|
@@ -67073,6 +67420,14 @@ const StructuredContentBlock = Node$1.create({
|
|
|
67073
67420
|
return { "data-alias": attrs.alias };
|
|
67074
67421
|
}
|
|
67075
67422
|
},
|
|
67423
|
+
lockMode: {
|
|
67424
|
+
default: "unlocked",
|
|
67425
|
+
parseDOM: (elem) => elem.getAttribute("data-lock-mode") || "unlocked",
|
|
67426
|
+
renderDOM: (attrs) => {
|
|
67427
|
+
if (!attrs.lockMode || attrs.lockMode === "unlocked") return {};
|
|
67428
|
+
return { "data-lock-mode": attrs.lockMode };
|
|
67429
|
+
}
|
|
67430
|
+
},
|
|
67076
67431
|
sdtPr: {
|
|
67077
67432
|
rendered: false
|
|
67078
67433
|
}
|
|
@@ -86349,18 +86704,25 @@ const _hoisted_3$8 = {
|
|
|
86349
86704
|
};
|
|
86350
86705
|
const _hoisted_4$4 = {
|
|
86351
86706
|
key: 3,
|
|
86352
|
-
class: "link-
|
|
86707
|
+
class: "link-title"
|
|
86353
86708
|
};
|
|
86354
|
-
const _hoisted_5$2 = {
|
|
86355
|
-
const _hoisted_6$1 = ["onKeydown"];
|
|
86356
|
-
const _hoisted_7$1 = { class: "input-row url-input-row" };
|
|
86357
|
-
const _hoisted_8$1 = ["innerHTML"];
|
|
86358
|
-
const _hoisted_9 = ["onKeydown"];
|
|
86359
|
-
const _hoisted_10 = ["innerHTML"];
|
|
86360
|
-
const _hoisted_11 = { class: "input-row link-buttons" };
|
|
86361
|
-
const _hoisted_12 = ["innerHTML"];
|
|
86362
|
-
const _hoisted_13 = {
|
|
86709
|
+
const _hoisted_5$2 = {
|
|
86363
86710
|
key: 4,
|
|
86711
|
+
class: "link-input-wrapper"
|
|
86712
|
+
};
|
|
86713
|
+
const _hoisted_6$1 = { class: "input-row text-input-row" };
|
|
86714
|
+
const _hoisted_7$1 = ["readonly"];
|
|
86715
|
+
const _hoisted_8$1 = { class: "input-row url-input-row" };
|
|
86716
|
+
const _hoisted_9 = ["innerHTML"];
|
|
86717
|
+
const _hoisted_10 = ["readonly", "onKeydown"];
|
|
86718
|
+
const _hoisted_11 = ["innerHTML"];
|
|
86719
|
+
const _hoisted_12 = {
|
|
86720
|
+
key: 0,
|
|
86721
|
+
class: "input-row link-buttons"
|
|
86722
|
+
};
|
|
86723
|
+
const _hoisted_13 = ["innerHTML"];
|
|
86724
|
+
const _hoisted_14 = {
|
|
86725
|
+
key: 5,
|
|
86364
86726
|
class: "input-row go-to-anchor clickable"
|
|
86365
86727
|
};
|
|
86366
86728
|
const _sfc_main$j = {
|
|
@@ -86454,6 +86816,7 @@ const _sfc_main$j = {
|
|
|
86454
86816
|
});
|
|
86455
86817
|
const isEditing = computed(() => !isAnchor.value && !!getLinkHrefAtSelection());
|
|
86456
86818
|
const isDisabled2 = computed(() => !validUrl.value);
|
|
86819
|
+
const isViewingMode = computed(() => props.editor?.options?.documentMode === "viewing");
|
|
86457
86820
|
const openLink = () => {
|
|
86458
86821
|
window.open(url.value, "_blank");
|
|
86459
86822
|
};
|
|
@@ -86479,6 +86842,7 @@ const _sfc_main$j = {
|
|
|
86479
86842
|
if (props.showInput) focusInput();
|
|
86480
86843
|
});
|
|
86481
86844
|
const handleSubmit = () => {
|
|
86845
|
+
if (isViewingMode.value) return;
|
|
86482
86846
|
const editor = props.editor;
|
|
86483
86847
|
if (!editor) return;
|
|
86484
86848
|
if (!rawUrl.value) {
|
|
@@ -86509,36 +86873,38 @@ const _sfc_main$j = {
|
|
|
86509
86873
|
return openBlock(), createElementBlock("div", {
|
|
86510
86874
|
class: normalizeClass(["link-input-ctn", { "high-contrast": unref(isHighContrastMode2) }])
|
|
86511
86875
|
}, [
|
|
86512
|
-
isAnchor.value ? (openBlock(), createElementBlock("div", _hoisted_1$g, "Page anchor")) :
|
|
86513
|
-
__props.showInput && !isAnchor.value ? (openBlock(), createElementBlock("div",
|
|
86514
|
-
createBaseVNode("div",
|
|
86515
|
-
_cache[
|
|
86876
|
+
isAnchor.value ? (openBlock(), createElementBlock("div", _hoisted_1$g, "Page anchor")) : isViewingMode.value ? (openBlock(), createElementBlock("div", _hoisted_2$b, "Link details")) : isEditing.value ? (openBlock(), createElementBlock("div", _hoisted_3$8, "Edit link")) : (openBlock(), createElementBlock("div", _hoisted_4$4, "Add link")),
|
|
86877
|
+
__props.showInput && !isAnchor.value ? (openBlock(), createElementBlock("div", _hoisted_5$2, [
|
|
86878
|
+
createBaseVNode("div", _hoisted_6$1, [
|
|
86879
|
+
_cache[5] || (_cache[5] = createBaseVNode("div", { class: "input-icon text-input-icon" }, "T", -1)),
|
|
86516
86880
|
withDirectives(createBaseVNode("input", {
|
|
86517
86881
|
type: "text",
|
|
86518
86882
|
name: "text",
|
|
86519
86883
|
placeholder: "Text",
|
|
86520
86884
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => text.value = $event),
|
|
86521
|
-
|
|
86522
|
-
|
|
86885
|
+
readonly: isViewingMode.value,
|
|
86886
|
+
onKeydown: _cache[1] || (_cache[1] = withKeys(withModifiers(($event) => !isViewingMode.value && handleSubmit, ["stop", "prevent"]), ["enter"]))
|
|
86887
|
+
}, null, 40, _hoisted_7$1), [
|
|
86523
86888
|
[vModelText, text.value]
|
|
86524
86889
|
])
|
|
86525
86890
|
]),
|
|
86526
|
-
createBaseVNode("div",
|
|
86891
|
+
createBaseVNode("div", _hoisted_8$1, [
|
|
86527
86892
|
createBaseVNode("div", {
|
|
86528
86893
|
class: "input-icon",
|
|
86529
86894
|
innerHTML: unref(toolbarIcons).linkInput
|
|
86530
|
-
}, null, 8,
|
|
86895
|
+
}, null, 8, _hoisted_9),
|
|
86531
86896
|
withDirectives(createBaseVNode("input", {
|
|
86532
86897
|
type: "text",
|
|
86533
86898
|
name: "link",
|
|
86534
86899
|
placeholder: "Type or paste a link",
|
|
86535
86900
|
class: normalizeClass({ error: urlError.value }),
|
|
86536
|
-
"onUpdate:modelValue": _cache[
|
|
86901
|
+
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => rawUrl.value = $event),
|
|
86902
|
+
readonly: isViewingMode.value,
|
|
86537
86903
|
onKeydown: [
|
|
86538
86904
|
withKeys(withModifiers(handleSubmit, ["stop", "prevent"]), ["enter"]),
|
|
86539
|
-
_cache[
|
|
86905
|
+
_cache[3] || (_cache[3] = ($event) => urlError.value = false)
|
|
86540
86906
|
]
|
|
86541
|
-
}, null, 42,
|
|
86907
|
+
}, null, 42, _hoisted_10), [
|
|
86542
86908
|
[vModelText, rawUrl.value]
|
|
86543
86909
|
]),
|
|
86544
86910
|
createBaseVNode("div", {
|
|
@@ -86546,9 +86912,9 @@ const _sfc_main$j = {
|
|
|
86546
86912
|
innerHTML: unref(toolbarIcons).openLink,
|
|
86547
86913
|
onClick: openLink,
|
|
86548
86914
|
"data-item": "btn-link-open"
|
|
86549
|
-
}, null, 10,
|
|
86915
|
+
}, null, 10, _hoisted_11)
|
|
86550
86916
|
]),
|
|
86551
|
-
|
|
86917
|
+
!isViewingMode.value ? (openBlock(), createElementBlock("div", _hoisted_12, [
|
|
86552
86918
|
isEditing.value ? (openBlock(), createElementBlock("button", {
|
|
86553
86919
|
key: 0,
|
|
86554
86920
|
class: "remove-btn",
|
|
@@ -86558,25 +86924,25 @@ const _sfc_main$j = {
|
|
|
86558
86924
|
createBaseVNode("div", {
|
|
86559
86925
|
class: "remove-btn__icon",
|
|
86560
86926
|
innerHTML: unref(toolbarIcons).removeLink
|
|
86561
|
-
}, null, 8,
|
|
86562
|
-
_cache[
|
|
86927
|
+
}, null, 8, _hoisted_13),
|
|
86928
|
+
_cache[6] || (_cache[6] = createTextVNode(" Remove ", -1))
|
|
86563
86929
|
])) : createCommentVNode("", true),
|
|
86564
86930
|
createBaseVNode("button", {
|
|
86565
86931
|
class: normalizeClass(["submit-btn", { "disable-btn": isDisabled2.value }]),
|
|
86566
86932
|
onClick: handleSubmit,
|
|
86567
86933
|
"data-item": "btn-link-apply"
|
|
86568
86934
|
}, " Apply ", 2)
|
|
86569
|
-
])
|
|
86570
|
-
])) : isAnchor.value ? (openBlock(), createElementBlock("div",
|
|
86935
|
+
])) : createCommentVNode("", true)
|
|
86936
|
+
])) : isAnchor.value ? (openBlock(), createElementBlock("div", _hoisted_14, [
|
|
86571
86937
|
createBaseVNode("a", {
|
|
86572
|
-
onClick: _cache[
|
|
86938
|
+
onClick: _cache[4] || (_cache[4] = withModifiers((...args) => __props.goToAnchor && __props.goToAnchor(...args), ["stop", "prevent"]))
|
|
86573
86939
|
}, "Go to " + toDisplayString(rawUrl.value.startsWith("#_") ? rawUrl.value.substring(2) : rawUrl.value), 1)
|
|
86574
86940
|
])) : createCommentVNode("", true)
|
|
86575
86941
|
], 2);
|
|
86576
86942
|
};
|
|
86577
86943
|
}
|
|
86578
86944
|
};
|
|
86579
|
-
const LinkInput = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["__scopeId", "data-v-
|
|
86945
|
+
const LinkInput = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["__scopeId", "data-v-198fc596"]]);
|
|
86580
86946
|
const _hoisted_1$f = ["aria-label", "onClick", "onKeydown"];
|
|
86581
86947
|
const _hoisted_2$a = ["innerHTML"];
|
|
86582
86948
|
const _hoisted_3$7 = ["innerHTML"];
|